Hello. Welcome back to the course on Audio Signal processing for music applications. This week we are talking about the Fourier properties and theorems. And in this programming lecture, we are going to be using that to actually implement the analysis of a sound using The Fourier transform. And we will take advantage of those properties to better understand this programming aspect of it. Okay, so let's first go to a terminal. And we're going to be working within the SMS tools kind of package. So we'll go to where we have kept the SMS tools code that we downloaded from GitHub and we're going to be working from the workspace directory. So we are within the workspace directory and now we can start IPython. So today we going to be using IPython, which is an interactive shell that is very convenient for interactively calling Python commands. Since we're going to be using matplotlib all the time, there is a way when we start IPython, to already import matplotlib. So we do that by calling pylab, okay? And this will execute IPython, and it already will be using the matplotlib as part of that. Okay now we want to start typing Python but it's much easier to do it from a text editor. Okay so here is our G editor, text editor, and I already typed some of the commands of what I want to explain. So this is a very simple script in which I imported three packages. So NumPy, the standard array processing package. Then, I wanted to use a triangular function, so I got that from SciPy, okay, so I imported that function. And I want to use the DFT implementation in Python, the FFT algorithm. So I get that also from SciPy from the FFT pack. Okay, now we declare, we create a triangular function, an array of values that is a triangular shape. Sorry, I compute 15 samples of a triangular function. Then I call the FFT algorithm and here it's very important to notice that the size of the input signal is 15 samples. It's not a power of 2. Even though we mentioned that in order to use the FFT algorithm, we require to have length of a power of two signal. But this implementation of the FFT, when the input signal is not the power of two, then it just implements the DFT, the standard implementation of the equation of the DFT. Therefore, it does not take off the advantage of the power of two of the implementation of the FFT. So therefore we can use the FFT for any size. Of course we will have to try to use power of two when this is called very often. And then after computing the spectrum, copy the legs, we obtain the magnitude and the phase of the spectrum. Okay? So from Add Item we can execute this file. This file is in our workspace directory. It's test.py. Okay? So I can execute this script by just typing run and test. No need to type the .py because it knows that we are executing Python files. Okay, so now it has executed these commands. It hasn't printed or plotted anything. It didn't ask for any Output in that way, but it has computed all these variables. So these variables are now known into the environment. So, for example, just type the variable X. It shows the array of our triangular function that we have computed and we can plot it if we plot x or plot the matplotlib function. I don't need to make reference to the packet, but just directly the function plot and I plot x. I display the triangular function line from zero to 14. Okay. Then, the magnitude and phase spectrum can also be plotted. So I just can plot nX. And this is the magnitude spectrum, okay? And this requires some explanation. The magnitude spectrum of a real function like a triangular function is symmetric. And here, there is a symmetry. But maybe a little misleading. The symmetry is around zero. And the way this has to be understood is as a circular buffer in which the center is zero. And then the first half of the ray are the positive values. And the second half of the ray are the negative values. So, in fact, the sample 14 is also the sample minus 1. Okay so this keeps repeating left and right. And therefore, this ending is the negative part. And then, we can understand this symmetry very clearly. Okay? We can plot the face spectrum by typing plot(px). Okay, and it shows this great complex function which is kind of not so intuitive from what we talked about. When we analyze a real function, and an even function like the triangular function, the phase should be zero. This was one of the symmetry properties of the DFT. And here, the phase is not zero. Why? Well, because our time signal, the triangular signal, was not centered around zero. It had a shift operation. It had a shift of half of the triangular function. So, from what we just talked about, the concept of centering around zero, in order to compute a triangular function that is centered around zero, we have to place the triangle in a different way. Let's show that. Okay, in this second file I have added three lines thatt change the triangular function in a way to center it around zero. Okay so after computing the triangular function, we are creating a variable, which we call FFT buffer, of the same size as X. All initialized with zeros. So, np.zeros is a way to create an array of empty values. And then, what we're going to do is locate the triangle around zero, which means That the first part of the buffer will be the N on the triangle. So this way of accessing the rate, basically says that from seventh location of the input signal to the N. Are placed at the beginning of the FFT buffer, and the second part of the triangle, the second half, is placed at the end. No, the first part of the triangle is placed at the end of the FFT buffer and then, we do exactly what we did before. We compute this array that has the triangle now centered around zero, and we obtain the magnitude and phase spectrum. So again, this file is in our workspace, so we can just execute it, run test1. Okay, and now what we're interested is in the FFT buffer. So, if we show, we plot the FFT buffer. Okay, we see the triangle but placed around zero, what does that mean? Well, the center of the triangle the value one is now at location zero. This is the second half of the triangle and the first half is now placed in negative values. Now it's placed at the n. This would be the negative samples of n, okay? And if we now look at the the magnitude spectrum, well, it should be the same than before. It's exactly the same. The magnitude does not change. What we have done is a shifting operation. We have moved the triangle from 0 to 14, to -7, to 7, so the magnitude does not change. But the phase should be very much different, okay. So let's plot the phase, well, that looks strange, but let's understand that axis to understand it. There is this factor, this exponential factor here, of e to the minus 15, so basically these numbers are zero. Now there is some numerical error, but these are tiny, tiny values. It's not 0 to 4 but it's 0 to 4 to the -15. So basically, this means that these is all zeros and of course, there were some numerical errors. That is caused by a when we use computers, so anyway, this is zero phase result, okay. Okay, now let's look at a real signal. Let's do the Fourier analysis of a real signal and for that, I created another file, test2. In which, we basically use some of the same code, but added code in order to be able to read a sound file. Okay, so we have the same packages but here, we need to include a file that is within the SMS tool's directory. Called Util functions, that has the WAF read function, okay. The WAF read function is a function that reads a file and then it converts to floating point numbers normalized to minus 1 to 1. So this is what we needed. That's why we import that and then, instead of having some fixed values we have defined some variables that allows us to define any section or any type of N values that we want. Any duration of input signal. So what we do here is a way to compute the duration of the second half and of the first half of the input signal. So, we can then center things around zero and this allows us to handle even and odd size values, okay. So this is just simply two variables that allow us to decide where is the middle of a window. Then we read the input signal. We read a file, the Soprano WAF file and we store it in to a variable X and the sampling rate FS. And then we just going to take a fragment of that, so we're going to take from the X array. We're going to take the values that go from 5,000 to 5,000 plus the size of the window, so 501. And then, we will multiply by a smoothing window. We'll talk that more next week. Okay so now, we have a signal x1, which is a short signal, 501 samples and then, we do what we did before. We're going to center this signal around zero in the FFT buffer. And this is, all this code does that, and then we just compute the result. So let's execute that, so this is test2. And let's first plot the original sound that we read, so the whole soprano sound. Okay, this is the whole soprano sound and it has more than 50,000 samples, close to 60,000 samples. And this is normalized from minus one to one, so it's not that loud. So, it goes from -0.10 to 0.15. Now, let's plot the FFT, well let's first plot the fragment that we chose, the X1. X1 is the fragment that we chose from the singing voice already windowed by this moving hamming window. So these are the 501 samples and now, we have to put them in the FFT buffer, centered around 0. Okay, so we plot the FFT buffer and this now, is the same fragment of the sound but centered around zero. The second half of the signal is in the positive time, and the first part is in the negative time. And now of course, we can plot the spectrum. We can plot the magnetic spectrum. So this is the magnetic spectrum, and here we see the symmetry that we saw before. So this is the positive part, at the beginning, and here is the negative part, at the end and we have 501 samples. Of course, we only need half of it, because the others is redundant. And if we look at the face, we can plot(px) And this is the phase, which looks quite noisy. And now we will try to improve that, but this is what it is. And it's antisymmetric, so the first half is the negative values of the second half, okay. Now, in order to use the FFT, what we want to be able to do is take the power of two length signal without having to change the fragment of sound we actually take. So what we can do is, well, here the FFT size n can be independent of the fragment of sound we take. So here, so for example, now we can have n independently of m. And n will be that FFT buffer in order to be able to use a part of two in FFT, so we can just, for example, put 1024. Now this will compute the FFT, and it will use the FFT algorithm of 1,024 samples, even though we're only going to take for 501 samples. Let's try to understand that a little bit. So we will run the test2. Now the fragment of the input signal is the same. But if we plot the FFT buffer, well, now we see that the second half is starting the same way at the positive side. And the beginning of the sound is placed at the end at the negative samples. And the whole middle are zeros. This is the zero padding. So okay, so these are zeroes that we have added in order to fill up to the FFT size. And this is good, okay. Now we will look at the output at MX. Well, it would look similar to the previous one, but in fact, there are more samples now. There are 1,024 samples. And maybe here, we are not seeing the difference, but now for example, if we plot it in DB, we might be able to see more information. Okay, so instead, the magnitude spectrum, one of the things we mentioned is that we want to display in a logarithmic scale. So what we're going to do is multiply 20 times the log, log 10, which is a NumPy function, of the absolute value of x. Okay, so now If we save it and run it again, okay, run test2. And we plot the magnitude spectrum, it looks very different, okay? It looks, of course, the vertical axis has changed a lot. Here, we see again the symmetry. Of course, here, again now, it doesn't make sense to plot the whole thing, so typically, what we're going to do is we're just going to plot the values that go from 0, from the beginning, to half of the FFT size, which is going to be 512. Okay, so 512 is half of the spectrum. And this is what we normally plot. Okay, this is the magnitude of the spectrum. And for the phase, one thing that we also talked about when we talked about the properties is that it's good to do an unwrapping of the phase. So what we're going to do is call the unwrap function, okay, from NumPy. And this will allow us to visualize this phase spectrum better. If you remember, the phase spectrum looked very strange. Now if we execute with the unwrapping function, let's execute again that and we show the phase, well, looks much nicer. In fact, we should only be watching the first half. So in fact, let's watch the part that goes from 0 to 512. Okay, and this is the phase spectrum. And this looks, as I said, much nicer. It lets unwrap the phase, and it does this pi, 2 pi unwrapping, so it looks much smoother. Okay, so this is the normal way that we will be computing the spectrum of a signal. And this would be, in this case, of a real sound. So this is a pretty good code that implements the Fourier transform of a signal using the FFT algorithm and using some of the properties that we mentioned and understanding the issues of symmetry. Okay, and that's all I wanted to say. So basically, we have used some of the Fourier theorems and properties, so please make sure that you understand them, especially the concept of symmetry, zero phase, windowing, the concept of db scale, the concept of unwrapping the phase, etc. So that when we compute the Fourier transform, we can actually visualize and understand the values in a good way. We use iPython, which becomes very helpful. And so we can use a text editor for some aspects. And then, for like the plotting and to display some things interactively, we can use the iPython command, so that's pretty good. And we're starting to use number of packages? Well, apart from NumPy and matplotlib, the FFT is part of scipy, so that's going to be a very useful package for us. And that's all, so we have tried to use some of the properties we've talked about in the context of programming, so in the context of actually practical use. And we have basically developed a piece of code that implements the Fourier analysis of a fragment of a sound. So we're starting to get something interesting. So I hope you continue and that I will see you next class. Bye bye.