 Welcome to this lecture on digital communication using GNU radio. My name is Kumar Appaya and I belong to the department of electrical engineering at IIT Bombay. In the next sequence of lectures, we are going to put into practice what we have learned in terms of constellations and noise. In this lecture, we are going to use GNU radio in order to construct constellations. Particularly, we are going to look at multiple ways. Basically, it is like a dictionary lookup where we can generate random symbols and convert them to complex symbols that represent constellations and we will see how we can visualize those constellations as well in GNU radio in a convenient format. We will initially begin by creating the constellation by ourselves using the chunks to symbols block. Subsequently, we will also introduce some of the inbuilt features for making constellations in GNU radio. So let us begin. The first task for us is to grab the throttle which we will first place on our flow graph. So Ctrl F or Command F, throttle. We will place the throttle in our flow graph. We will then start by introducing the chunks to symbols. So Ctrl F or Command F and CHUN will get chunks to symbols and then we will also get a random source. Ctrl F, Command F, random source and we will place the random source in our flow graph. We will connect the random source to our chunks to symbols, the chunks to symbols to the throttle. The random source initially, we will make it only have two values but then we will make it, you know, we will make it 1024 samples and the symbol table will be one dimensional and let us keep it as complex because it will be convenient later but let us just make the symbols in square brackets minus 1 comma 1, close square bracket. This means that whenever the random source produces the value 0, minus 1 is output by the chunks to symbols. Whenever the random source produces the value 1, 1 is output by the chunks to symbols. Now we will introduce the constellation viewing block which is very convenient when you want to do some debugging and so on. So there is a constellation sync that is Ctrl F, we will do QT GUI and constellation sync. So this constellation sync is very, very useful. If you just drag and drop it here and connect it, we have our system in place. So if we now hit run, we will basically see this kind of a scenario where there is a plus 1 and minus 1, they are being essentially shown on your constellation plot. If you want to see the effect of some variations, we can just quickly add some noise and verify. So let us just do Ctrl F for Command F and type noise. We will grab the noise source and we will initially just add a small amount of noise. So we will keep the amplitude at 0.1 and keep it as complex Gaussian. And let us disconnect this QT GUI constellation sync, grab an adder, so Ctrl F and type add and we will just add the noise over here. This is like a symbol level noise addition. And if you now run your constellation, you will see that because of noise, you have this kind of blob. Essentially, it just draws all those blocks of 1024 samples onto your screen. And this is varying because of the noise. So this is a basic introduction to the QT GUI constellation sync. Now, let us just do a very small exercise. Let us actually just do the pulse shaping and get back the original constellation points from this particular flow graph. All we need to add is a root race cosine pulse, which will essentially pulse shape your original data. And you need to add a root race cosine pulse that will act as a match filter. So let us go about it. Now, to easily produce a root race cosine pulse shaper, let us generate the tabs first. So if you say Ctrl F or Command F and type RRC, you will get the RRC filter tabs block. We can place it over here. We'll double click this and call this RRC tabs. Then we will keep the gain as one for now. We will play with it later. We want the symbol rate over here to be 8000 because if you recall our original like past experiments, we were using 8000 symbols per second or something like that. So I'm going to define something called samples per second because that is often used by this RRC. So I'm just going to say my symbol rate is sample rate divided by SPS. And remember that double slash is for integer division because we need the symbol rate to be it's preferable to make the symbol rate an integer. And so we need to now just add a variable called SPS. So let's say Ctrl F or Command F, we'll say variable. And we will make this variable SPS the value four. The moment you do this, the RRC filter tabs turns black and it starts, you know, it's basically ready for use. Now, before we add this noise and everything, let us disconnect this. Let us disconnect this. Let us disconnect this. Now we are going to just perform the pulse shaping by using an interpolating FIR filter with these RRC tabs. So let's do Ctrl F or Command F, interpolating. We'll grab the interpolating FIR filter. We'll connect the output of the throttle and we will subsequently add noise over here. So and then we will have to add a decimating filter as well. But let's get to that in a minute. So this interpolating FIR filter, we will use the same tabs as these RRC underscore tabs and the interpolation factor, we need not hard code. We will use the SPS that we have used earlier. So SPS is our samples per second, samples per symbol effectively. So now our interpolated signal is ready. But now we need to also get back this. So let's first view it in the constellation sync and see what happens. I will also add a time sync so Ctrl F or Command F, time sync and see what we get. If you view this, you are going to get a pulse shaped waveform. But this doesn't really make much sense because over here, essentially, all these values which you see over here are getting plotted. Now unfortunately, these values are not what you want. What you actually want is the values after taking the match filtering or in other words, from the previous class, you took the angle bracket y comma s and sampled it. If you remember the match filtering operation, we have to perform that, which means in this particular case, we have to essentially integrate, multiply this by the RRC filter again and integrate and only then we can figure this out. As we mentioned, multiplying by the RRC filter and sampling can be equivalently performed by filtering with the flipped version of the RRC filter and essentially sampling at the correct point. This can be achieved by means of a decimating FIR filter. So let's first do that. We will disconnect this over here and let's rearrange our things over here. Let's actually grab a decimating FIR filter. So Ctrl F or Command F, we'll say DEC. We'll get the decimating FIR filter. This is the pair of our interpolating FIR filter. This will be SPS so that we can always just change the samples per second. We're going to say RRC underscore tabs. Actually speaking, it should be the flipped version. If you really want to, you can say square bracket colon colon minus one. What this does is it actually flips the samples, but this is not strictly necessary because the RRC filter is symmetric about its center. The flipped version is very similar. In fact, the same, ideally speaking, as the unflipped version. So let's say okay. So now what we need to do is we need to connect the output of this noise added signal and then let us inspect the constellation sync. Now if we run this, you will see that you are able to get this particular output which essentially is what you expect because of the addition of noise, there is some variation. Now there is an important point to remember in this flow graph, the fact that you got the constellation with the decimation also is something which is a little bit, you know, it's somewhat fortunate. Let's actually see what happens if there is a slight delay in between. So let's say that, you know, you don't sample at the right time. So let me remove before we go further, right? Let's double click this and change the number of tabs over here to let's say, let's say, let's keep it as is. Let's add a delay over here. So I'm going to delete this. What's a control F for command F and type delay. And we will grab a delay block. Connect this, connect this over here. And we will set the delay to a variable called delay. T e l a y. The next thing we will do is we will grab a QT GUI range, control F for command F and say range, place the range over here. We will of course name it as delay. And we'll set the default value as zero. Stop can be just 10. That is fine and should be an integer. Let's say, okay. Now let us run this flow graph. Now let us just add some delay. The moment you add some delay, you can see that the constellation essentially goes momentarily bad. The reason why it goes bad is because the point at which you sample is not the right point. In other words, you have essentially performed the match filtering, but you're not sampling at the right point. Let us actually do one more thing. Let us change the samples per second to let's say five. And let's say run. Now again, you can see that this doesn't look very good or pleasing. If you know, press this, you get the correct constellation. In fact, if you don't believe me, you can actually just make the noise zero. And if you execute this flow graph, you will see that the this particular constellation looks like a blur. While if you just add a delay of one, you get back the original constellation. Why is this the case? The reason is because this particular interpolating FIR filter is not a it's not an instantaneous filter. It is a causal filter. Therefore, this particular filter introduces some amount of delay. In fact, you can actually calculate the delay based on the number of taps. So there are 55 taps and probably this filter introduces about, let's say, I think it's 28, 27, 28 samples of delay. And further, you are now performing this kind of filtering. And this also is going to introduce another 27, 28 samples of delay. So if you now compute the exact delay of this filter, it may be something like 55 samples or so. While you are not, you are essentially decimating filter has to sample exactly at the right point. So to to find the right sampling point, you need to have an adjustment. You need to add that extra compensation if things don't match. So for example, over here, this, let's say that I change my samples per second to six. Let us execute our flow graph. It seems to work because of the multiples matching. And if I add a delay of six samples, it works again. If I add a delay of, yeah, I should have done 12, but I let me just change the delay to 100. If I now add a delay of 12, it will still work. 11 doesn't 11 doesn't work. 10 doesn't work. This means that often you must be aware that sometimes to get the exact sampling point, you need to be able to find it or adjust it using a delay. This is something that will come in handy when you do your future experiments. If you really want to find out the exact mechanism, you can find out the group delay of the interpolating FIR filter and group delay introduced by the decimating FIR filter and then take the modular with respect to the symbols per second. And that will give you the correct answer. I'm going to set the samples per second to four. We are now back. Let us add back the noise. Let's say it's 0.1 and then you get back the original constellation. Now it is generally cumbersome to use the chunks to symbols to set your constellation. And GNU radio, in fact, has a more more systematic way of generating constellations. So let us remove the chunks to symbols. And let us add the so called constellation encoder. So control F for command F. Constellation, you say constellation object. If you double click this, you can just choose one of many prebuilt constellations. For example, I'm going to choose BPSK and say, okay, and then I need a constellation encoder. So control F for command F, CONST. I'll get this constellation encoder. The constellation encoder takes byte inputs. So I'm going to change my random source by double clicking it and choosing byte. And I'm going to connect these together. But now the constellation object is actually a variable. So I'll call it my CONST, my const. And the constellation encoder takes a constellation object as an argument. So I'll say my const. Therefore, any changes in this constellation will reflect on this encoder. Let us see what this does. If I execute this flow graph, I get back what I expected. But let us also now try to just make some changes. So this constellation encoder, rather this constellation object allows you to specify one of many different constellations. For example, if you say QPSK and change the random source to have up to four values, you'll start getting QPSK samples. And the waveform also gets modified accordingly. Let us now go back to BPSK. I'm going to make this two. I'm going to make this variable constellation, actually. So you can now specify an arbitrary constellation by specifying a list of integers. These integers are essentially what go as input. For example, if the random source produces three, then the third symbol is output here, random source produces two, and the second symbol is output and so on. This will come in handy when you deal with pics. So let us actually make it very simple. We're going to make zero comma one. And we're going to make our constellation minus one comma one and say okay, and rotational symmetry will be two. Now, if we execute our flow graph, you'll get back what we expected. But let's actually just make some changes. Before we go ahead, let's actually double click this time sink and add a grid and say auto scale, and let's double click the constellation sink and add a grid and auto scale. So now let's look at the constellation, sorry, constellation object. And let us now change this to something like minus one minus one j and one plus one j. So it's going to be the bottom left and the top right. And notice that there is something called normalization. It does amplitude based normalization. Okay, so let's see what happens if you execute this flow graph. If you execute this flow graph, you get something interesting. This particular constellation ends up being between only minus something like 0.2 and 0.2 or something. What is the cost for this? The cost for this is because this particular filtering is causing some amount of loss in gain. So for example, even if I make the noise zero, if I execute this flow graph, you're going to get the constellation points at around minus 0.17 minus 0.17 and 0.717.17. To adjust this, what you need to do is you need to add a gain for in the RRC filter tabs. And the gain which you need to add is precisely SPS square root of SPS. I'm just going to write SPS star star that is power 0.5. So if I do this, then I'm going to get it at minus 0.7 minus 0.7 plus 0.7 plus 0.7, which is very close to one by root two one by root two and minus one by root two minus one by root two, which makes it equidistant from the origin. Now this is something very useful because even if you set this to something like minus two minus 2j and no two plus 2j, the normalization is going to take care and you're going to get the same set of values minus 0.7 minus 0.7 plus 0.7 plus 0.7 and this makes things a lot easier to handle. So now let's add back the noise. So 0.1 and you're going to see slightly shaky but its center is around minus one by root two minus one by root two and one by root two one by root two. So this is a useful way to generate different constellations. Of course, you can always just change it back to QPSK by just making this go from zero through four and changing this constellation to QPSK. And now you will start seeing this QPSK constellation. Okay. So you can you can now start experimenting with various constellations and simultaneously observe the waveforms and so on. There's an interesting point to note, because of the amplitude based scaling, this is actually close to root two comma root two. If you now double click the constellation object, you can actually just change it to variable constellation and set your own QPSK. That will also give you a different kind of constellation. You can play with this and understand what this exactly does. There is another convenience wrapper which GNU radio offers you when using constellations. Because the act of using constellations along with pulse shaping is so common, there is also a constellation, constellation, you know, modulator. So if you look at control f command f and type constellation, you have a constellation modulator as well. So we are going to just check out how that works so that it can come in handy for your simulations as well. So before we begin, let us just add a throttle, control f for command f, grab the throttle, place it on our flow graph, we will place some variables just similar to the previous flow graph. So control f for command f, type variable, put the variable over here. Our first variable will be SPS and we'll make it four. Okay, then we are going to just get our random source control f for command f and type random source. We'll double click this random source, we'll make it go from zero to two, but we'll keep it as let's say, bite. Okay, so because that's what a constellation modulator wants, we'll create our constellation. So control f for command f, we'll say constellation, object, we'll double click it, we'll call it my const. Maybe we'll just keep this constellation itself and change our random source to make it four. The next thing we will do is we will grab the constellation modulator. So constellation modulator, place it over here. Now connect this over here. Connect this over here. If you double click the constellation modulator, the first thing we'll say is we'll say my const, and we'll also say differential encoding as no, that will, we'll discuss differential encoding subsequently. We'll say samples per symbol as SPS. Now what happens over here is that this particular constellation modulator does the job of doing the root trace cosine filtering for you, which is why this excess bandwidth term is available for you. So you can directly expect the output of this to have the root trace cosine pulse shaping within it. To verify this, let us just get a time sync. So control f for command f, we'll say time qt GUI time sync and connect it out over here. If you connect it, you will see that the pulses are shaped using something like a sync like signal, which exactly is your root trace cosine. And if you verify, I'm not going to go through that verification, these will be separated by exactly, you know, there'll be a one by 8000 seconds apart because of the fact that your sampling rate is 32000 samples per second. And you are performing the experiment or you're performing the upsampling at four samples per second. Now, let us now get back the constellation from here. So to get it back, there's something called a constellation decoder over here, okay, or rather constellation modulate constellation receiver over here. The constellation receiver can be used to do undo the effect of the constellation modulator. But for now, we are going to just get back the signal manually like we did earlier, because the constellation receiver has other features that we will discuss subsequently. So let us delete this. So the first thing we're going to do is we will even get rid of this time sync by clicking on it and hitting delete. We are going to just do the same thing we did, which is generate the RRC tabs with the constellation modulator uses internally and do the root trace cosine match filtering. So I'm going to say control F or command F decimation decimating FIR filter. Over here, you can see that the excess bandwidth is 350 m so 0.35. Let's make that into a variable as well. So control F for command F variable and create this variable called excess BW and make it 0.35. And even over here, we will call this excess underscore BW. And in the decimating FIR filter, we're going to just make it complex to complex. The decimation is samples per second. The tabs are RRC underscore tabs, you can do colon colon minus one, but I'm not going to do it this time. Now we need RRC tabs. So control F for command F, we'll say RRC. So grab the RRC filter tabs block. Name is RRC underscore tabs. Gain is SPS power 0.5 for our normalization. This is not mandatory, but it's just convenient. Symbol rate is SAMP RAID double slash SPS to get our 8000. And this is exes underscore BW. We'll say okay. And let us actually view this decimated output in a time sink and also view it in a constellation sink. Control F for command F. We'll get a time sink. And we will also get a constellation decoder control F command F. We'll get a constellation sink rather. And this constellation sink, let's do one thing. Let's add a grid sort of scale it. Let's also add two inputs. So let's connect the original constellation over here and the potentially decoded constellation over here. Now let's execute this. If you execute this. So actually the original constellation, I will not connect I'm sorry because that's pulse shaped. I can't view it. So let's get rid of this. Let's make it only one input. But more importantly, if you now run it, this is something which is close to what you're going to see. And in fact, let's make this also auto scale. I'm going to get the time sink with a grid auto scale. So now if you view this, you can see that the even after match filtering the extra pulse shaping effect is there. So this goes up and down and things like that. So at the bottom close to the minus 1.5 mark, there is some variation that is what reflects over here. You can see that the variation goes close to minus two and goes up to about minus 1.2. That variation is essentially manifesting over here at the bottom as well. This is this clear indication that the match filtering is not happening. Meaning match filtering is happening. But your sampling point is not correct. This is because internally we don't know how much delay the constellation modulator may be introducing. So we take the same step before this decimating filter, we remove this, we add a delay control f for command f, we type delay, we connect the throttle, connect this over here, double click the delay, call this d e l a y control f for command f. We will get a range, double click, we'll call this range as d e l a y. And this needs to run only from one to samples per second. But I'm just going to make the default value zero. Let it run from zero to 100. It doesn't matter. Now if I execute this flow graph, and add one sample delay, the constellation changes again, you can see it over here that there's some other marks. One more sample and boom, you can see that this is really sharp. If you look at the stem plot, you know, everything checks out, it's always between, you know, the positive root two and negative root two levels. Again, if you go, you lose it. Again, you lose it again, you lose it again, if you come to six, you do so effectively a two sample delay is enough for you to recover this. So this is the key which you must understand when using the inbuilt constellation mod modulator object or constellation modulator modulator that includes the pulse shaping as well. In this lecture, we have seen multiple ways by which you can use canoe radio to make constellation points from randomly generated data symbols. In subsequent lectures, we will be using this as a building block to generate QPSK or BPSK symbols and use this to verify the performance of these types of constellations under additive white Gaussian noise and other impairments.