3
votes

I have this MATLAB assignment I need to do and thus far I have generated a mixed signal consisting of cosine functions of three frequencies values: 86Hz, 159Hz and 392Hz. I used a sampling frequency of 1Khz and generated one second worth of data. I then created the discrete fourier transform of this code which showed (what I think the purpose of the FT is) The most commonly occurring frequencies in the composite signal. The code and generated plots for this is shown below:

fs = 1000;
t = (0 : 1/fs : 1)';
f = [ 86, 159, 392 ];
x = sum( cos(2*pi * t * f), 2 );
y = fft(x);
subplot(2,1,1), plot(t,x);
subplot(2,1,2), stem(y,t);

(For the sake of expediency I'll omit the code for axis and plot titles). Here is the two figures that I have generated thus far for the report.

Mixed frequency signal and its DFT

The next part of the report asks this of me:

"If we consider only the middle frequency of interest find the frequency response of a LTI system that filters out the higher and lower frequencies using the fourier transform"

I need to know if there is some way this can be done automatically in MATLAB. I'm uncertain how to create this bandpass filter and then find its frequency response manually so I was wondering if there was some way MATLAB will do it automatically as I may be overthinking it.

1

1 Answers

1
votes

By "middle" frequency, I'm assuming you want to filter out the signal so that only the component at 159 Hz is present. This means that the output result should only contain one sinusoid at 159 Hz. First off, I'd like to mention that the Fourier Transform shows a frequency decomposition of your signal. You can think of a signal as a summation of many sinusoids at different frequencies and they're possibly out of phase with different phase shifts. For each sinusoid at a frequency, there is a magnitude component and a phase component. The magnitude tells you how large the sinusoid is at this frequency, and the phase tells you how much of a delay that sinusoid is experiencing.

Now, when computing the FFT, this performs the Cooley-Tukey algorithm, which is a very efficient way of computing the Fourier Transform. It's computed in such a way where the first half of the signal shows the spectrum from 0 <= f < fn and the second half of the signal shows the spectrum from -fn <= f < 0. fn is what is known as the Nyquist frequency, which is half of the sampling frequency. Note the exclusivity in the range of the first half of the spectrum compared to the second half. We don't include fn in the first half, but we include -fn in the second half.

This only applies for real signals, which is your case with the three sinusoidal summed together. In order to make this a bit more meaningful, you can use fftshift so that you are reorganizing the spectrum so the 0 Hz / DC frequency appears in the middle, which will allow you to plot the spectrum so that it's between -fn <= f < fn.

Also, the way the signal is being plotted is normalized, which means that you see the frequencies are actually between -1 <= f <= 1. To translate this to actual frequencies, you use the following relationship:

freq = i * fs / N

i is the bin number or the point on the FFT you want, which in your case is from 0 up to 500. Remember, the first half of the signal represents the frequency distribution from 0 up to fn and from 0 up to 500 in the signal is what you need. The negative frequencies can be found by just substituting i for -i. fs is the sampling frequency and N is the size of the FFT, which in your case is the total length of the signal, 1001. To generate the right frequencies that correspond to the right points, you can use linspace and generate N+1 points between -fn and fn to ensure the spacing is correct, but because we don't include fn at the positive end, we remove this from the end of the range.

Also, to plot the magnitude and phase of the signal, use abs and angle respectively.

Therefore, try plotting it this way, and also focus on the magnitude and phase too. Just plotting the spectra is undefined because in general, there are real and imaginary components.

%// Your code
fs = 1000;
t = (0 : 1/fs : 1)';
f = [ 86, 159, 392 ];
x = sum( cos(2*pi * t * f), 2 );
y = fft(x);

%// New code
%// Shift spectrum
ys = fftshift(y);
N = numel(x); %// Determine number of points
mag = abs(ys); %// Magnitude
pha = angle(ys); %// Phase

%// Generate frequencies
freq = linspace(-fs/2, fs/2, N+1);
freq(end) = [];

%// Draw stuff
figure;
subplot(2,1,1);
plot(freq, mag);
xlabel('Frequency (Hz)');
ylabel('Magnitude');

subplot(2,1,2);
plot(freq, pha);
xlabel('Frequency (Hz)');
ylabel('Phase (radians)');

Here's what I get:

enter image description here

As you can see, there are three spikes which correspond to the three sinusoidal components. You want the middle one, and that's at 159 Hz. To create a bandpass filter, you want to filter out all components except for the ones at +/- 159 Hz. If you want to do this automatically, you'd find the bin locations that are the closest to +/- 159 Hz, then expand a neighbourhood that surrounds these two points and ensure they're untouched while zeroing out the rest of the components.

Because you have exact sinusoids, using a bandpass filter in this regard is perfectly acceptable. In general, you don't do this due to ringing and aliasing effects as the sharpness of the cutoff from the bandpass filter in this way introduces unwanted aliasing effects in the time-domain. See the Wikipedia article on aliasing for more details.

So, to figure out where we need to filter out, try using min and find the absolute difference between the generated frequencies above with 159 Hz - specifically find the location. Once you find these for both +159 Hz and -159 Hz, extend a neighbourhood around these points, make sure they're untouched while the rest of the points are set to 0 in the spectrum:

[~,min_pt_pos] = min(abs(freq - f(2))); %// Find location where +159 Hz is located
[~,min_pt_neg] = min(abs(freq + f(2))); %// Find location of where -159 Hz is

%// Neighbourhood size
ns = 100; %// Play with this parameter

%// Filtered signal
yfilt = zeros(1,numel(y));

%// Extract out the positive and negative frequencies centered at
%// 159 Hz
yfilt(min_pt_pos-ns/2 : min_pt_pos+ns/2) = ys(min_pt_pos-ns/2 : min_pt_pos+ns/2);
yfilt(min_pt_neg-ns/2 : min_pt_neg+ns/2) = ys(min_pt_neg-ns/2 : min_pt_neg+ns/2);

yfilt now contains the filtered signal that removes all components except for 159 Hz. If you want to show the magnitude and phase of this filtered signal, we can do that:

mag2 = abs(yfilt);
pha2 = phase(yfilt);
figure;
subplot(2,1,1);
plot(freq, mag2);
xlabel('Frequency (Hz)');
ylabel('Magnitude');

subplot(2,1,2);
plot(freq, pha2);
xlabel('Frequency (Hz)');
ylabel('Phase (radians)');

Here's what we get:

enter image description here

As we expect, there is only one strong frequency that decomposes this signal, and that's at 159 Hz. Now to reconstruct this signal, you'll have to undo the centering we did, and you'll have to use ifftshift on this filtered result, then do the inverse via ifft. You may also get small residual imaginary components, so it's a good idea to use real on the output result.

out = real(ifft(ifftshift(yfilt)));

If we plot this, we get:

plot(t, out);
xlabel('Time (seconds)');
ylabel('Height');

enter image description here

As you can see, there is a sinusoid with one frequency and that's at 159 Hz. Don't mind the amplitudes though. This is simply due to an imprecision in how many points you have chosen to plot the signal and so some of the time points may not exactly coincide with the true peaks of the signal. Do bear in mind that if there was more than one sinusoid present, there will be a point where the peaks of all sinusoids will meet and you'll get a higher peak instead of a peak of 1 that a single sinusoid offers. Because the amplitude hovers around -1 to 1, you can be certain that only one sinusoid is present. This can be avoided if you were to choose a finer grain step size, and hence more points in the FFT.


Hope this is enough to get you started. Good luck!