 Welcome to this lecture on digital communication using GNU radio, my name is Kumar Appaya. In continuing with our series of lectures on GNU radio, in this lecture we are going to put together some of the learnings from the previous lectures and particularly see how you can use a constellation, a constellation object in particular in GNU radio, how you can decode the received value. For example, if you have additive Gaussian noise, how you can get the minimum distance point and convert that to symbols and we will then inspect the symbol error rate in the presence of noise as well. This will put together several concepts that you have been seeing over the past lectures and making them work together will allow you to put together powerful simulations that can confirm the theoretical and conceptual knowledge that you have gained. Let us begin with an approach to construct and generate constellations from symbols on GNU radio. So let us begin by first looking at the chunks to symbols block. So I will press control F for command F and type chunk. So we grab the chunks to symbols block and place it here. The chunks to symbols block plays the role of a table lookup. You have to provide a symbol table and the chunks to symbols block takes an integer 0, 1, 2 or so and gives you the 0th, 1st or 2nd corresponding object from the symbol table. We will keep the dimension as 1 and we will start with a commonly used constellation that is the QPSK or QAM4. We will specify this constellation by placing the constellation elements in a list. So I am going to say square bracket 1 plus 1j, 1 minus 1j, minus 1 plus 1j, minus 1 minus 1j and that's it. The integer which you input if it is 0 then this particular symbol is outputted. If it is 1 then this is output. If it is 2 then this, if it is 3 then this. For convenience for later use I am going to change this to a byte. It makes no difference because a byte can also take the values 0, 1, 2 and 3. Now in order to actually create these symbols randomly we are next going to introduce a random source. So I am going to say control F for command F and type random. Then we will get the random source, place it in the beginning and we will make the random source output a byte which is 1 of 0, 1, 2 or 3. Now as you have seen in the previous lecture one issue with the random source is that it will only output the same sequence of random values again and again repeatedly. So to ensure that we have enough randomness we will just make the size of this larger to a 100,000. That will ensure that the sequence does not have too few random values that keep repeating at least there is a sizable number of random values. We say okay we connect the random source to the input of the chunks to symbols. Before we visualize this constellation let me also preemptively add noise or rather the facility to add noise. So I am going to say control F for command F. I am going to type noise and I am going to get this noise source over here and I want to be able to control the standard deviation or variance of this noise. So I am going to change this amplitude to noise STD say okay and I am going to also add a QT GUI range that will allow me to change the noise standard deviation. So say control F for command F, range let us get the range and place it over here. If I double click the QT GUI range and change its ID to noise STD this will now become a knob which I can tune to change the amount of noise. Now the default value I will set to no noise let it start at 0 let the standard deviation go up to 10 and let us make the step 0.01. Now we have a means by which we can control the noise because the default value of noise STD is 0 the amplitude shows 0 here that is not a problem. Now we need to add these up so I will say control F for command F and say ADD add we will connect the chunks to symbols and noise source together. We need a throttle so I will get control F I will get throttle. So now that we have a throttle we can now connect this to a constellation sync. So visualizing this in a time sync is essentially going to give you 1s and minus 1s pair of signals because this is just 1 plus 1j or 1 minus 1j minus 1 plus 1j so the real part is plus 1 or minus 1 the imaginary part is plus 1 or minus 1 therefore what is more interesting for us is to use a constellation sync. We will say control F for command F C O N S T so there is this Q T G Y constellation sync let us grab it and connect it over here. We are now ready to visualize the constellation which this particular flow graph generates what does the constellation mean well let us just see it and we will get to know. So there are four dots the four dots are at 1 plus 1j 1 minus 1j minus 1 minus 1j and minus 1 plus 1j. So what is happening is that this can be looked up on as something like a 2D histogram without the counting of course and the constellation sync is presenting to you all the values that it sees from the input. The random source is essentially producing 0 1 2 and 3 randomly and each of those numbers picks out one of these constellations and you are able to pick I mean one of the constellation points one of the quam 4 points and this is essentially displayed. Let us now just add a little bit of noise and see what happens if I make the noise standard deviation point 0 2 you can now see some slight bit of movement here what is this so over here you are taking the 1 plus 1j point and adding Gaussian noise to it. How do I understand it think of it this way if you have just 1 plus 1j then it's like an impulse sitting here which means only 1 plus 1j is being sent if you had a 2D histogram will have a stick here a stick here a stick here a stick here all those would be of the same height. Now instead of a stick you will essentially have a small 2D Gaussian sitting here which is taking your 1 plus 1j point and spreading it slightly around why slightly because the noise standard deviation is point 0 2 which corresponds to a very small amount or in communication terms a very high SNR scenario. Let us now make a modification by increasing the amount of noise so as I increase the amount of noise it is evident that the spread is larger 1 plus 1j if you add noise to it which is essentially a 2D Gauss complex Gaussian it starts throwing it in farther and farther locations let's actually before we go further make a slight change for better visualization if I double click the QT GUI constellation sync one thing that you can see is that the number of points is 1024 we can actually make it 1024 0 just to add little more density to our constellation we can make the grid and we can also autoscale it autoscale will not keep because we have the X and Y axis correct now let us execute this flow graph now if you add noise let's say we add we keep increasing the noise to about 0.1 you can see that you have a reasonably dense constellation this is in fact a Gaussian because at the center it is concentrated but as you go further away you can see that the points are becoming a little more sparse now this is a very high SNR scenario if you really want to compute it this 1 plus 1j corresponds to an amplitude of root 2 this corresponds to a sigma of 0.1 and you just find the ratio and appropriately get the symbol to noise ratio it will turn out to be something like you know 14 in linear scale convert to db but if you start increasing the noise then something strange starts to happen so if you start increasing the noise then the probability that your 1 plus 1j gets affected by the additive noise and then is incorrectly detected as say minus 1 plus 1j or 1 minus 1j or even minus 1 minus 1j starts becoming higher and higher and in fact if you make the noise very very large then things become crazy and you may end up making a large number of errors when you perform the detection now this is very evident because we have seen that as you increase the noise power or decrease the signal to noise ratio you are going to encounter more and more symbol errors but it would be useful for us to have a way by which we can quantify or measure it we will look at that in a moment before we continue to actually get the symbol error rate or find out whether a symbol error has occurred we need to use our minimum distance decoding remember from our lecture earlier lecture that minimum distance decoding is optimal when you have equiprobable symbols under Gaussian noise the chunks to symbols block specifies the symbols now we need to build a minimum distance decoder in order to get back the symbols at the receiver and compare them to the transmitted symbols to verify that the symbol is correct or mark it as incorrect now this can be done by adding some computations in GNU radio but because it is cumbersome and a common operation GNU radio provides a bit more sophisticated and easier to use in build constellation approach that does not rely on chunks to symbols wherein you can do this minimum distance decoding and other such aspects very easily so let us now move to that approach so there are three blocks that we will see first we will see two of them let's remove chunks to symbols and first to control f and get constellation object and place it on our flow graph now this constellation object is a strange block just like variable and range it doesn't have any inputs and outputs but it is a specification that results in a variable this variable is of type constellation so let us double click this so its default type is variable constellation there are bpsk qpsk dpq psk 8 psk 16 quam we will actually just stick with variable constellation to start with so the symbol map is 0 1 3 2 now they have chosen this particular map for a specific reason reason being that these actually have the meaning of bits as we shall see later for now you can just ignore this and this is basically what would be output if the random source generate 0 will be this if the random source generates 1 it will be this the random source generates 2 it will be the last one and the random source 3 will output this now there are other aspects that I am not going to cover at the moment but this is a variable that will result in a constellation I'm going to say okay and the second block I am going to take is the constellation encoder so control f s a c o n s p e there is this constellation encoder we can grab that block and connect it over here now we can now we can double click the constellation encoder and the constellation object will be this one but the name is variable constellation 0 I'm instead going to change it to my c o n s t my const for convenient naming and we will now name this my const m y c o n s t and we're set and we're going to connect this over here and now we will execute the flow graph now if we run before we begin notice that the constellation has changed a little and it is at 0.7 plus 0.7 j like this is actually 1 by root 2 plus 1 by root 2 j the reason is because the constellation encoder has normalized ever constellation for example let me just increase the noise over here and you can see that the points are concentrated around this particular area which is not 1 plus 1 j but 0.1 sorry 0.7 plus 0.7 j why did this happen let us actually double click the constellation object so there is something called normalization type when you choose normalization type is amplitude then the constellation is scaled so as to make these values have some square divided by the number of points equal to 1 so let's change it to none if I change it to none then you can see that they go back to 1 plus 1 j if I change it to power in this case also they will be at 1 by root 2 plus j by root 2 these exact meanings of these we will cover later but for now let us keep it as amplitude the other aspect is that if you execute the flow graph you can see that adding noise does put a 2d Gaussian over here and as the 2d Gaussians variance or standard deviation starts increasing to a level where it's really really big then some of these points will go into the other decision region remember the decision region for this particular constellation is the x-axis and the y-axis so any point that crosses the the quadrant so to speak for example the first quadrant is the decision region for 1 plus 1 j the second quadrant is the decision region for 1 minus 1 j and similar anything that crosses is going to cause an issue now as I mentioned to you the minimum distance decoder is optimal our task is to find out whenever we receive a particular data point which was the closest constellation point that it would map to the reason for this is because under Gaussian noise in if you have equi probable symbols the minimum distance decoder is optimal fortunately in GNU radio the minimum distance decoder has been implemented it is present in the constellation decoder so let us grab the constellation decoder control and controller for command F you type constant there's a decoder available now the decoder also needs to know which constellation you're talking about so double it and say my const now before we use this decoder to get back our constellation symbols let us first check whether it actually does what we wanted to that is let us first check whether it does minimum distance decoding we can easily do that by just moving around a point and checking whether it decides correctly let's actually do that so I'm going to actually create two ranges and construct a particular received value and see what the constellation decoder gives me let's check so I'm now going to just add a constellation encoder also after this so control I'm going to control C or command C control V or command V add a constellation encoder and then I'm going to add a constellation sync I'm just going to grab this from over here now I'm going to also title this as test so that we know that this is not this particular constellation and now I need to construct a received symbol so for that I'm just going to need I'm just going to need two values so two real value which I will construct into a complex number I'm say control f range and I'm going to say get this range double click this I'm going to call this r underscore real for the real received value starts at z let's say it's it's it's one no let's say it's one let's say it starts at minus one stops at one step is I think 0.05 would be good enough and default value is let's say one now I'm going to copy this control C and paste this control V and call this r underscore image for the imaginary part and then I'm going to actually view that as well over here so I'm going to say control I will click this and I'm going to just add two inputs and I'm going to add a constant source so control f or command f I'll grab a constant source and this constant source I'm going to make the constant value a sorry r underscore real plus 1 j times r underscore image so what I've done is this constant value even though it's called constant is going to keep varying with my range and it's going to appear on this constellation sink and I'm also going to connect this source to the decoder so this constant source is going to be decoded and reproduce the original point while you're also going to see the second one if you are worried about colors the decoded one is going to be blue the ink and the original one is going to be red received symbol that is let me execute this flow graph and let's focus on this test I had one plus one j as I told you it got decoded to point seven plus point seven j let's actually add a grid now I have these two things let us actually just keep moving this constellation point receive point here now the moment I move it to the left of zero the minimum distance constellation point should actually be minus 1 by root 2 plus j by root 2 let's check as you can see if I move it to the left then automatically it decodes to minus 1 by root 2 plus j by root 2 because that is the minimum distance solution let me move it down a little if I move it below 0 I move it below 0 you can see that it moves to minus j minus 1 minus 1 by root 2 minus j by root 2 and if I move it to the right let's just make this rather than scroll it let us make it 0.3 so this actually does the right thing it does the minimum distance decoding as I move this test point around it does give me the right point even if you scale it for example if I'm now going to do 1 minus yeah it's still and 1 minus 1 plus 1 j is this let us do 0.7 plus 0 point minus 0.8 so it does a good job of finding the minimum distance point in essence the constellation decoder does the job for you so let us now get rid of our test setup but just keep the constellation decoder a constellation oops control Z control Z control Z yeah we'll just keep the constellation decoder and now our task is to find out from the noisy output what the decoded point is and compare it with the original random sources input the approach that we will take is to first get the decoded output and then compare it with the encoder rather the original source but we will do that using our own custom python block because it is much simpler to do it using that approach if you remember in a previous lecture we have seen how you can make your own python blocks and we are going to use this feature in order to find out the errors and then we will use a histogram to count the number of errors let us begin so I'm going to connect the noisy output to the constellation decoder and now I am going to just get this particular output and this particular output of this random source and build a comparison system using an embedded python block so I'm going to say control F for command F embedded I'm sorry say python block double click it and I'm going to say open in editor you can choose any editor that you desire so let us now start building our block let us double click this and open in editor we'll choose our favorite editor you can choose any editor that is appropriate for editing python and now you get the template block as we have seen earlier in this case remember that we are going to compare two integers but the result which will be an integer can be converted to float 64 so that you can view it in a histogram so let us begin we don't need we don't need this particular comment we don't need this documentation and we don't need any exam any parameters in fact and the only thing is that we are taking two inputs which are bytes so int 8 and int 8 and our output can also be an int 8 or we can directly give a float also let us actually give an int 8 because we are only outputting zeros and ones we should ideally just give an int 8 now we don't have any attributes over here now over here all we are going to do is we are going to check our input items array element 0 with 1 and check where they are not the same and then output the locations where they differ so that that can be histogramed a very quick python aside in order to compare numpy arrays let us first import numpy there are there is an easy approach to do so let's first create an array let's say x is equal to NP dot array and let's say it is one two and let's say three and let's say y is equal to NP dot array and let's say it is one three and let's say four or one three and three that's fine now we want to basically create an array that has a marker of every point where x and y differ so if I say x not equal to y numpy gives me an array consisting of false true false that is these are potentially the locations of mismatch or if you think of it in zeros and ones locations of errors if you think of it in symbols locations of differences so these are the locations where symbol errors are present but I want to convert this to an integer so that I can then convert it to float and histogram it so what do I do it turns out that I can just view this as an array and I can convert it using numpy using the as type to int eight and I end up getting an array consisting of zeros and ones one being the marker for an error this is a very convenient approach so now I just need to can I just need to construct that particular array in the same way I will say input underscore items 0 not equal to input items 1 dot as type int 8 this will output me an array consisting of zeros wherever there are no errors one wherever there is an error and that's it so let us now save and exit now if you look over here you get an embedded python block and very nicely gnu radio has detected that you want to integer inputs and sorry byte inputs and you have a byte output let us just connect this over here and connect this over here now we need to just use a histogram oops let me just make some rearrangements now all you need is a histogram to find out where home I know at how many points these end up differing so I'm going to just say control f for command f and type histogram but for a histogram we need to be able to change the we need to be able to change the data type as a control f and they'll say byte to float okay byte to float is inconvenient let us actually make this an integer by editing this out that'll make it easy I'll double click this and say open an editor so this int 8 let us change it to int 32 and this becomes an integer so I'm going to say control f and say int to float because that makes the conversion easier I could also have converted it to float directly here but I just wanted to avoid it now the values which we're searching for are zeros and ones so I'm just going to double click this and I'm going to say I'm going to maybe make this more more bins very more points and x axis it's a minus 0.2 y axis is 1.2 and that's it now let us execute this so as you can see it gives me a 10,240 zeros which means there are no errors let's start increasing the noise okay there are still no errors at noise standard deviation of point 2 we have a very nice rock solid block at 0 now if I start increasing however let's say if I increase the noise standard deviation to about let's say close to 1 what you can see is that now a fraction of the numbers end up over here and another fraction over here this means that this is the number of total values out of 10,240 that are detected correctly and this is the number that are not detected correctly over here you can see the constellation is really bad let's actually take a pause and go back you can see that over here even though there is noise the chance of this particular point going and crossing over to produce an error is small which is why you don't see this growing let's make this about 0.25 even now you will see that there is not really much in terms of errors over here let's make this close to 0.35 you may be able to see that there's a small jump over here there's a small jump over here indicating that there is some amount of symbol errors that are being detected now if I make it close to 0.5 just so you know the SNR is now lower because the noise standard deviation is increasing there is a stable amount of error that you're capturing you can see from the constellation that most points seem to fall in the correct region of interest but there are some locations where there are still errors as I increase the noise further and further you can see that the chance of having errors is much higher and if you go further and further and further and further you get even more errors and further and further and further further and you end up with a much larger number of errors this is a problem and this means that the signal to noise ratio is not enough to support this kind of you know this kind of communication with a very low symbol error rate if you make the noise so large that it smothers the signals then you get this kind of situation where about three thousand one two hundred or three thousand three hundred symbols are correct while seven thousand of them are wrong so three thousand is correct seven thousand are wrong why does this happen the reason is because you are sending one of four symbols if you now start making random guesses you just randomly guess then one fourth of the time you will be right which means that the ratio between your incorrect to incorrect will be 1 is to 3 right because let's say that I'm giving you numbers between 0 and 3 and I want you to guess the correct number now even blindly guessing 0 all the time will make you correct one fourth of the time which means the ratio of you getting the correct answer to you getting the wrong answer is essentially 1 is to 3 which is why the histogram is clearly telling you that about seven thousand of them are wrong and three thousand of them are correct so now if you now increase the noise then you can see that the ratio is quite close to that one fourth but let me just ensure that you see it if you make the noise really really high let's say the variance is hundred square which is like extremely low signal to noise ratio then if you now observe what you can see over here this is 2,500 or close to it this is 7,500 or close to it the ratio is one third in other words about only 25% of the symbols are being decoded correctly which you can just do with blind guessing because whenever you have four equiprobial symbols always guessing that you're going to get the first symbol will make you write about 25% of the time thus you have now a simple way by which you can characterize the performance of the system by just observing the rates of the symbol errors you can infer the performance you can basically infer how well the performance of the system will be at some SNR's roughly speaking in the signal to noise ratio is closer to you know let's say you know a hundred or something like that then you get excellent performance as you get to make the signal to noise ratio closer lower and lower you're going to start seeing some bit of errors and if you are in a situation where you have a huge number of errors let's say something like this then the only option for you is to make amends by either decreasing the rate of transmission increasing the power or reducing the data rate or some such other trade-off these are some things that we will see in eventual lectures. So in this lecture we have seen how putting together a constellation encoder a constellation decoder and noise can essentially allow you to visualize and measure the impact of noise on various constellations by tuning various parameters and changing various knobs so to speak in GNU radio you can measure or simulate and measure the performance of various constellations and under way and under different scenarios as well as a remark if you have hardware experiments as well and if you put them together in GNU radio this is a convenient way to benchmark the performance of your system as well. In the subsequent lectures we will build on top of this knowledge to put together even more complex simulations that mimic the reality more closely.