 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 this lecture we are going to see how noise and related ideas can be brought into GNU radio. In particular we will see the noise source in GNU radio and various properties that it has in particular how it behaves when you have real noise or complex noise. We will then also introduce the concept of matched filtering as a way by which we can average out the noise to minimize its impact for various kinds of pulses and this will go into making your receiver efficient. So in this lecture we are going to inspect the impact of matched filtering from a noise perspective. One key idea is that if you take any pulse that is used for signaling for example in this case we are taking a partial ramp signal and let us say that this ramp is used to send data. Now unfortunately the ramp is going to get affected by noise and you are going to have this wavy pulse at the receiver. Now if everything were good and you wanted to find out what data was sent you can ideally just look at this particular point because that has the highest amplitude. But for some reason if the noise is very high in that particular point and takes you to another value you may make a mistake. You are also making an error by not taking into account all of these possible values. So the key idea is for us to take all of these values into consideration in order to determine which particular amplitude was sent. Let's say that you send a ramp from 0 to 1, a ramp with a different amplitude from 0 to 2 and so on. So you have to find out which exact value was sent by looking at the whole duration over here. So the key idea is that you have to take the weighted average of the noisy samples. Now why should you take the weighted average and not the average? The reason is because over here the amplitude of the ramp is very high and even if there is noise the noise is not going to carry the signal or carry the value far down or far away from the desired value. But over here if you look at the points near 0 the noise could cause a huge shift. For example let us say that the amplitudes we have are 0, 1, 2, 3 and over here it will be 0, 1, 2, 3 in very close succession and the noise may end up carrying you to the wrong amplitude and make you make more errors. So in some sense these all these measurements which you can see over here are measurements of the actual value except that they have different SNRs and it turns out that if you look at the matched filter theory they say that the matched filter that is that filter which you have to choose or that combination of these values that you have to choose is basically weighted in such a way that you give these low SNR points a smaller weightage and a higher SNR points a higher weightage. Therefore from the perspective of maximizing the signal to noise ratio by combining all these optimally what should you do? It turns out that you have to essentially weight these values exactly by the amplitude of the ramp. So you are going to multiply this value by this particular amplitude this by this this by this and add all of them up which basically translates to multiplying the ramp or rather the noisy ramp by the clean ramp and then performing the averaging. That is the optimal weight is the amplitude itself. This is why matched filter theory also tells you that this particular approach gives you the best SNR maximizing solution where that takes into account all the values with appropriate SNRs. An exercise you can think of is that if you take a rectangular pulse which we will do soon then you can weight all the points as they are meaning all the points equally because every point has in equal SNR. Now the other point which we will look at is that the other point that we have to consider is that we want to implement matched filtering which is effectively correlation as a convolution. How do we do that? So let's stick with our S of t if this is our S of t if we essentially want to perform convolution we consider S of t minus tau and multiply it out. Unfortunately S of t minus tau will be the flip rectangle that is it will be flip triangle rather the ramp essentially going from up to down instead. But if we look at S of tau minus t instead that is the exact you know signal that we want is essentially if you take this as S of tau this S of tau minus t which means it is shifted by t along this axis and if you choose t as 0 this S of tau that's exactly what you have over here and if you now look at this particular overlap you can see that this is the convolution of S of t with S of minus t sampled at 0. In other words you are taking S of t flipping it, convolving it and taking it at 0 offset of course in a causal implementation there may be other delays but this is the way by which you can visualize that the correlation can be implemented as convolution by just taking S of t flipping it and using it for convolution with S of t. We will now inspect this briefly in GNU radio. Let us now put together a very simple example of match filtering just to send some bit of let's say pulse amplitude modulated data and recover it by using match filtering in the presence of noise. So before we go ahead let us just look at how this can be done and how we can actually make a particular pulse and then get the data back from that particular pulse. I am going to first use a bit of some numpy functions. So I am going to just do control f for command f and I am going to say import and for convenience we will just double click this and say import numpy as np so that we don't have to keep typing numpy dot numpy dot all the while. Now for simplicity let me take a vector source so control f for command f we take vector source yes we have a vector source I will do a real simulation so we will just say float I need to get my pulse over here so I am going to take a fairly long pulse so that we can visualize things easily and I want to use the pulse in multiple locations. So I am not going to use this particular I am not going to hard code the pulse within the vector source I am going to do control f for command f and say variable and I am just going to double click and call it my pulse that is my variable name and the pulse I am going to use is a ramp so I am going to create a ramp by just adding numbers in a sequence in numpy so np dot a range and maybe let's take the ramp from 0 to 1 in let's say 400 samples so let's say 400 samples and I want to take it from 0 to close to 1 so I will say by 400 in fact should be 399 but let's because np dot a range gives you the numbers from 0 through 399 but I think that's ok maybe if you want we can ok let us stick with this now just to have an intuition 32k is the sample rate that means each sample is separated by 1 by 32,000 seconds 400 by 32,000 seconds implies that this particular ramp is going to last about 400 by 32,000 seconds that works out to I think 4 by 320 seconds that works out I think 1 by 80th of a second we will just confirm now let us just put my pulse over here as the variable name we will add a throttle control f for command f we will grab a throttle double click this should be a float next we will grab a time sink control for command f and if you type time you get a QTGUI time sink we double click this call it float for now let us live with this this is just to visualize our pulse and verify that it is correct if I execute this flow graph I get this kind of pulse let us just make things more convenient so I am going to double click this time sink and I am going to make it have a grid and I am going to make it out of scale ok and we can actually make this let us say yeah this is fine actually so we can make this a multiple of this you know 400 to just have it static say 1 2 0 0 is the number of points now you can see that you have these now the question is what is the gap between or what is the gap between this so this is 0 and we have over here 12.5 milliseconds 12.5 milliseconds now if you do the maths 400 upon 32000 is 4 upon 320 there is 1 upon 80 1 upon 80 that is 1000 upon 80 milliseconds and 1000 upon 80 milliseconds you can verify will be 12.5 milliseconds so this is actually like sending 1111 but we want to send some data that we will do momentarily and it goes from 0 to 1 comes down goes from 0 to 1 comes down and so on this is good so now when we want to do something like matched filtering we want to essentially convolve this pulse with it's a it's flipped version in this case notice that I have chosen the ramp specifically because this is an unsymmetric pulse if you have a symmetric pulse like a sink or a root trace cosine or a rectangular pulse you can just convolve with itself but now you have a pulse which is non-symmetric so let us actually do conduct an exercise let us now just perform let's take some data and then perform this so I am going to remove this vector source I am going to control F for command F type random get a random source our random source we will say the random source takes 0 1 2 3 so four possible values okay now we need to just we can just take these 0 1 2 3 values as our float as well so I am just going to take an int to float so control F for command F I am going to type int to float grab this block connect it over here now I need to essentially put this pulse or put this pulse for this data and I have chosen 400 specifically I have not let me maybe make that a variable m so that we don't have any issues I'll call this capital M I'll call this capital M and I'll say control F for command F I'll say variable and double click this call this variable M and make it 400 so now we need to essentially put zeros and then convolve of zeros in between these samples and convolve it with this particular variable to do that we will use the interpolating FIR filter so control F for command F I type interpolating I'll grab the interpolating FIR filter double click the interpreting FIR filter we'll go with float to float we'll call the interpolation amount 400 and the taps we will basically make it exactly my pulse now what will this result in this will result in a successive sequence of ramps each multiplied by either zero or one or two or four one after the other now this number of points may actually be may you may need to increase this but let's just run it and check yeah so you can see that it is working but let us increase the number of points okay let's make this about let's say 12,000 we'll make it 12,000 if you make it 12,000 and let me just stop you can see what is happening you have let's say a zero then you have a two and then you have a one and a two and maybe another one and then a three and so on let's actually try to look at what the gap between successive peaks is over here over here this is I think 225 milliseconds this is 237.5 that's again 12.5 milliseconds so the gap between these is 12.5 milliseconds which is consistent with the way you have designed your pulse your pulse was designed to be 251 you know 12.5 milliseconds so each successive modulated data ramp is 12.5 milliseconds long now the challenge for us is to get back this data okay now to get back this data we need to do the reverse operation we need a decimating FIR filter and the decimating FIR filter will essentially take this output and we will try to get back our random source points so it's to control F for command F type decimating grab the decimating FIR filter double-click it you want float to float we want a decimation factor of M actually actually I should have typed M in your interpreting also we will do that and I will call it now here is something which we have to be careful about when we want to do a decimating we were decimating filter let's keep the decimation at one we are not going to do any decimation let us now put the tabs as my pulse colon colon minus one colon colon minus one is python notation for reversing a sequence so what does this do this takes into account the fact that your pulse is being reversed because the filters always perform convolution you want correlation you are essentially reversing the pulse let's say okay we will double click this we will call this M I missed that alright now let us actually just get another QT GUI time sink I am going to double click this first and say this name is interpolated and then I am going to just grab another QT GUI time sink by doing control F and say time and grab another QT GUI time sink we will double click this call it float call it decimated okay it's not yet decimated but still bear with me we will add a grid we will do autoscale say okay now I am going to just take the output of the interpolating affair filter I take it out from the throttle doesn't matter connect it to the QT GUI time sink and we will check what happens okay so as you can see there are these peaks which you get why are these peaks coming the reason these peaks are coming is because this particular pulse is essentially being convolved with the decimating filter and that results in these peaks and notice also there is an interesting happening the time over here timescale is from 0 to 350 while here the timescale is 0 to 30 this is effectively because there is a factor you know there is a factor multiplication because you have decimated that's where you know you're going to decimate that's the reason why this particular thing happens just be aware of this the reason I mean the actual reason is because I've chosen different timescales here I've chosen 12k here chosen 1.024k so maybe if I really wanted to make it somewhat consistent because I'm decimating by a factor of 400 I will have to make this 12,000 by 400 I'm sticking to the number of points over here it doesn't matter now now the key thing is that if I stop this if you look at these values over here maybe let's just make this slightly longer we'll make this also some 3000 and let's run this and I'm going to stop this so the values over here are close to 400 here the value is close to 138 here the value is close to you know 267 you know so the value seem to be close to 0 130 130 or so 266 and close to 400 what is the cause the reason for this is because when you actually perform an overlap of the original pulse with this particular decimating filter you're actually going to get up the value that you're going to get the is actually the integral or this autocorrelation of the function evaluated at zero in other words you're going to get the integral of the square of the signal let's actually just verify that temporarily let me remove this particular connection then let us grab a vector source so control for command F we'll say vector source and in the vector source let us actually put our pulse I'll say float and I'm going to say my pulse and let's see what happens with this correlation so this particular operation is just essentially taking the pulse multiplying by itself and moving it also in time so if I run this I get this kind of thing to make it stable and static I need to double click this I need to basically take care of the length so this is the length of this is about 400 the length of this is about 400 so maybe I'm just going to make this let's say let me try making this 800 yeah so now this is very very stable so now what happens is that this particular peak is actually a value which is around let me zoom in over here or let me maybe zoom in like this it's like 133 or something like that okay why is it 133 what is the significance of this value it turns out that this particular highest value occurs when you overlap the peak of the ramp with itself recall from the slide you're overlapping the ramp with itself which means you're essentially multiplying the ramp samples by themselves and adding them up now therefore what you get is actually the sum square of the my pulse coefficients if you don't believe me let's grab a variable for command F type variable okay now what I'm going to do is I'm going to double click this and just say NP dot sum that adds a vector my pulse star star 2 that basically performs the square of the every element of the vector and this adds them and that it gives you 132.834 if you now look closely at the output you get over here this is going to be close to 132.8 it's because I'm not able to put my finger on the right location you get it so I think it must be close to 132.8 over here yeah it's close to 132.8 at the peak okay so then if you really want to get back the original samples we can just scale it by adding a scale over here I'm just going to scale it by dividing this I'm going to divide by NP dot sum my pulse squared now if I execute this after doing the match filtering I get a nice one now our task is to add noise and recover the original pulse but before we go there notice that there's a slight you know this essentially there is a slight you know there's a one and then it goes down there's a one and then it goes down and so on okay this is because of the periodic convolution that is something we'll have to just handle now let us get rid of before we go further let's also add the decimation I'm going to make the decimation 400 or m if I do this in this case I get a value close to one this is slightly inaccurate because it should be exactly one because we got the exact value over there so one thing we can do is we can try to add a sample delay and see whether that helps okay or we can try to just we can just remove the sample delay over here we can try to add a delay over here say control F for command F and we'll say delay as always we'll grab a delay we can double click this delay make it an integer delay sorry make it a float rather and the delay will make it a variable DELAY now connect this connect this and we'll have a range control F for command F we'll type range we'll add a QT GUI range ID will be delay and it will be a value between let's say one and default value let's say zero they say we'll go between one and M step one this is fine a type should be int by the way now if we execute this flow graph this is close to one but not exactly one if we now take it take this delay over here and keep going it you can see that we're essentially changing the sampling point and as you get get to 400 you get close to one again as you get to zero you get to one so if I set it at one then exactly it matches this it exactly matches this value if there is no delay there is a slight offset now why is this the case the reason is because if you don't add a delay then if you convolve my pulse with itself let's say that you know let's remove this decimation and set it to one if you run this you will see that this particular peak actually starts at one but it is the first point and if you really want to catch that point you have to add a delay of one so if you don't add this delay then the sampling point is slightly off which is why if you add this decimation you have to add a delay if you don't say you know if you see over here you just have to add a delay of one so for now what we'll do is we'll add this delay we'll make the default value as one and then we are set let us now move on to the task of recovering our original data to do that let us get rid of this vector source and let's connect this particular thing over output over here and let us see whether we are able to get our original data back if I now execute this flow graph we will wait a little for the samples to accrue after you wait you have to wait for a period you are able to see that your samples seem to be coming through the values are zero let's stop this middle click and stop values zero this value is one this value is two this value is three so the sample seem to be coming let's actually execute this the reason why it takes time is because you have this is a multirate kind of flow graph because this part is operating much slower because it needs 400 samples and decimates that's why it takes time for you to get the samples okay so let us now actually make it equal to thousand so that we can compare our data directly let's actually also add another let's say input and let us connect the output of the into float directly over here okay so I want to you to able to see that it's actually happening correctly so now if I now execute this flow graph we'll have to wait because it we have to wait for this buffer to get filled up and only then it will display the samples once I get it I will pause now I'm going to just say stop now if you zoom in you are going to see some other effect you're going to see that there is another delay actually the pulses look very very similar the in fact the red pulses the original but and the green pulses you know green pulses the blue pulse is the recovered the samples look pretty okay but there is definitely a delay now what is the cause of this delay now once again your ramp is causal because your ramp is causal if you know convolve the ramp with itself and sample that sampling point is one sample away let us now look back at our presentation so you can see that this particular sample is one one symbol away from the start of the pulse which means that you have to account for this extra delay so to account for this extra delay the secret for you is to just add another delay over here of one so the way we are going to do it is to just add a delay in this link so let's remove this particular this connection over here and move the delay up move this here will make a copy of the delay using control C and control V connect these in this manner just to make it easy for you to discern what is happening will just move these around and now if you execute this flow graph and keep waiting for this particular link to this particular plot to settle you will see that the delay is essentially handled you can see that the delay is gone because we have addressed the causal nature of the matched filter so this addresses that issue now the next thing to do is to see the impact of noise now as you are aware noise actually not directly but noise affects the performance using SNR so the signal to noise ratio is what determines the impact of noise over here the waveform takes values of this form you know it takes values between 0 and 1200 because of the way we have constructed the ramp so let's actually see how noise in you know plays a role and how the match filter handles the noise by means of averaging to do this we will add a noise source in between the interpolating a fair filter and the decimating a fair filter which does the match filtering so we'll take our usual approach of adding a range first controller for commander will say range so we'll take a QT GUI range call it noise STD and we'll say this system 0 and stops at 3 think stops at 3 is fine okay but when we add a noise source let's actually add the noise source over here we'll delete this second toilet for command if we'll say noise okay now what we'll do is we'll actually normalize it to have the pulse energy also so I'm going to actually say this is noise STD times and I'm going to say in P dot s Q R T in P dot sum okay I'm going to take the square root of the energy of the pulse so I'm going to say my pulse square so this essentially will normalize the SNR to the pulse energy so now I will also make it float and I'll grab an ad block controller for command if we'll say add and we'll just make the ad float we'll connect the noise over here and now we are set and let us wait of course the impact of noise will not be visible directly let's actually set the noise to something like this and keep waiting you can see that the noise is affecting your signal significantly and you can see the impact of noise clearly over here because the signal is quite affected so this is a very high amount of noise it's I think we should make the noise step a little better should step by 0.1 so now let's execute the flow graph and make it 0.2 0.2 seems high because of our normalization but it's keeping it at 0.1 and if you keep waiting you will see that the impact of noise essentially shows over here it's still able to average out the noise significantly even though the waveform is hardly discernible over here it's able to average it out and the averaging significantly reduces the impact of noise so the match filter is able to extract out your signal even amidst this kind of high amount of noise let us now just quickly check another pulse let's use the rectangular pulse so I'll say NP dot ones so this is just a rectangular pulse which is you know which is consists of 400 ones so now if you look at your pulse you have these rectangles now if you add some noise you will see that the noise affects you significantly and let's see what happens now on the right side you will see because of the noise there is there are these variations but those variations are still small and you are able to largely discern the signal if you increase the noise which you will see in the right you can hardly make out the signal over here over here however you are able to see the averaging come into play and you're able to discern it somewhat so in this way even in the presence of noise the match filter does a proper weighted averaging of the waveform samples to give you the best possible result and this is the key idea behind the design of the match filter as a correlator so you have seen how the match filter works and the impact of the causal delay in this particular new radio experiment in this lecture you have used new radio in order to simulate the effect of noise and add noise to signals and study the impact of how this noise essentially affects your signals in the concept of match filtering you have seen how match filters can effectively combine the received symbols which are received signal that is affected by noise to get your signals to get your symbols without much symbol error measuring this is something that we will see in the subsequent lectures