This is the fifth post in the blinkdagger signal processing series.

Matlab Logo One of the drawbacks of using the fft command is that it doesn’t give you any information on the frequency axis. It’s up to the user to create the corresponding frequency vector in order to obtain a meaningful FFT result. In the previous post, we discussed how to properly create frequency vectors to correspond with your FFT data.

In this tutorial, we’ll explore a different method to obtain the Fourier Transform of a given signal using a nifty built in command: freqz.

Example

Let’s use the following code to create an example signal. The example signal is simply a sine wave with a fundamental frequency of 4 Hz.

fo = 4;   %frequency of the sine wave in Hz
Fs = 100; %sampling rate in Hz
Ts = 1/Fs; %sampling time interval
t = 0:Ts:1-Ts; %time vector
n = length(t); %number of samples, 100
y = 2*sin(2*pi*fo*t); %the sine curve

%plot the sine curve in the time domain
sinePlot = figure;
plot(t,y)
xlabel('time (seconds)', 'FontWeight','Bold')
ylabel('y(t)', 'FontWeight','Bold')
title('Sample Sine Wave', 'FontWeight','Bold')
set(sinePlot,'Position',[500,500,500,300])
set(sinePlot,'Color',[0.97 0.97 0.97])
grid


Using the fft command

As discussed in the Introductory FFT Tutorial, the fft command within MATLAB only returns one vector of data. You should read this fft tutorial first if you are unfamiliar with using the fft command. But basically, the fft command only takes in as input the y-data of your time-domain signal. Thus, it only returns the output-data of the fourier transform, which is in complex form.

Using the freqz Command

The freqz command is a pretty versatile command. With this command, you can dictate what frequency range you want to be evaluated. So for example, lets say that I wanted to only look at the range of -5 Hz to 16 Hz, with frequency increments of 1 Hz.

freqzExample = figure;
freqRange = -25:1:16; %create a frequency vector from -25 to 16
freqzData = freqz(y,1,freqRange,Fs)/length(y);  %get the fourier data

stem(freqRange,abs(freqzData))
xlabel('freq (Hz)', 'FontWeight','Bold')
ylabel('Amplitude', 'FontWeight','Bold')
title('Using the freqz command', 'FontWeight','Bold')
set(freqzExample,'Position',[500,500,500,300])
set(freqzExample,'Color',[0.97 0.97 0.97])
xlim([-25 16]); ylim([0 2]); %set axes limits
grid

Two Sided Spectrum

If I wanted to do a two sided spectrum, I would have defined the frequency range in the following manner:

twoSided = figure;
freqRange = -Fs/2:1:Fs/2; %create a two sided spectrum
freqzData = freqz(y,1,freqRange,Fs)/length(y);  %get the fourier data

stem(freqRange,abs(freqzData))
xlabel('freq (Hz)', 'FontWeight','Bold')
ylabel('Amplitude', 'FontWeight','Bold')
title('Two Sided Spectrum', 'FontWeight','Bold')
set(twoSided,'Position',[500,500,530,300])
set(twoSided,'Color',[0.97 0.97 0.97])
xlim([-50 50]); ylim([0 2]); grid

Positive Frequencies Only

If I only wanted to see a positive portion of the fourier transform:

positiveFreq = figure;
freqRange = 0:1:Fs/2; % create a frequency range over the positive frequencies
freqzData = freqz(y,1,freqRange,Fs)/length(y);  %get the fourier data

stem(freqRange,abs(freqzData))
xlabel('freq (Hz)', 'FontWeight','Bold')
ylabel('Amplitude', 'FontWeight','Bold')
title('Positive Frequencies', 'FontWeight','Bold')
set(positiveFreq,'Position',[500,500,500,300])
set(positiveFreq,'Color',[0.97 0.97 0.97])
ylim([0 2]); grid

Defining Your Frequency Interval

In addition to defining my frequency limits, I can only define how fine or coarse I want my frequency interval to be. In the following example, I’m going to increase the frequency resolution. This means that the output data will have 5 times as many data points! This can be very useful, as it can help you visualize your data better when you plot it. Read this tutorial on zero padding if there’s any confusion here!

frequencyInterval = figure;
freqRange = 0:0.2:Fs/2; % frequency vector with increment of 0.2
freqzData = freqz(y,1,freqRange,Fs)/length(y); %get the fourier data

stem(freqRange,abs(freqzData))
xlabel('freq (Hz)', 'FontWeight','Bold')
ylabel('Amplitude', 'FontWeight','Bold')
title('Frequeny Interval Reduced', 'FontWeight','Bold')
set(frequencyInterval,'Position',[500,500,500,300])
set(frequencyInterval,'Color',[0.97 0.97 0.97])
ylim([0 2]); grid

Knowing your Limits

The frequency range of your data depends on the sampling rate, Fs. If Fs = 100 Hz, then your spectrum will span from -50 Hz to 50 Hz. What happens if you go outside this range? Simply put, the information is repeated. Let’s see what happens when we define a frequency range from -200 to 200.

freqRange = -200:1:200; %create a frequency vector from -25 to 16
freqzData = freqz(y,1,freqRange,Fs)/length(y);  %get the fourier data

freqzLimit = figure;
stem(freqRange,abs(freqzData))
xlabel('freq (Hz)', 'FontWeight','Bold')
ylabel('Amplitude', 'FontWeight','Bold')
title('Using the freqz command', 'FontWeight','Bold')
set(freqzLimit,'Position',[500,500,500,300])
set(freqzLimit,'Color',[0.97 0.97 0.97])
ylim([0 2]); grid

As you can see, the same information is simply repeated so there is no need to define a frequency vector outside the range of -Fs/2 and Fs/2.

Conclusion

The freqz command is a versatile command which in my opinion, is easier to use than the fft command. The ability to define your frequency axis is very helpful and flexible. With this method, you don’t have to worry about zero padding; you can simply define a very fine frequeny interval to get a better spectral resolution.