MUSC 208 Winter 2014 John Ellinger Carleton Collegejellinge/m208w14/pdf/Lab14.pdf · John Ellinger...
Transcript of MUSC 208 Winter 2014 John Ellinger Carleton Collegejellinge/m208w14/pdf/Lab14.pdf · John Ellinger...
1
MUSC 208 Winter 2014John Ellinger Carleton College
Setup
Lab 14 will show you how to use and interpret results from the Fast Fourier Transform or FFT. Create a m208Lab14 folder on your desktop. Open Octave and make the m208Lab14 folder your working directory.
Lab 14 FFT
Frequency Analyzer
Hypothesis. If you multiply two digital waveforms sample by sample and sum the products, the sum will be a maximum when the two waveforms are identical.
If the waveforms are identical the amplitudes at each sample will both be positive or both be negative. Their product will always be positve. Summing the results will produce a large positive number. If the waveforms are different but have the same frequency and starting phase, the sum of products will be large. If the waveforms have different frequencies or different starting phases, there will be times when the resulting product will be negative, resulting in a lower number, often near zero.
Frequency Analyzer
The diagram below shows a black box frequency analyzer.
2
The operator adjusts the dial of the sine wave generator to a known frequency and feeds the sine wave and the unknown waveform into the black box. The black box computes the product of the two waveforms and outputs the result. The operator then records the output value, turns the dial to a new sine wave frequency, and repeats the process. The resolution of frequency components in the unknown waveform depends on how far the dial is turned (ideally uniform steps) on each pass through the black box. The products with the largest values correspond directly to the frequency components present in the unknown waveform. A graph of the output values is called the spectrum of the unknown waveform. That's essentially what the Fourier Transform does.
Test the Hypotheses - Generate a Square Wave in Audacity
Choose Tone from the Generate menu.
Generate a Square wave (no alias) with a frequency of 100 Hz, amplitude of 1.0, and a duration of 1.0 seconds.
3
Choose Plot Spectrum from the Anaylze menu and make these settings.
There are frequency components present at 100, 300, 500, 700, 900… Hz, exactly as you would expect from the square wave formula:
Square = sin(2π i100) +1
3sin(2π i 300) +
1
5sin(2π i 500) +
1
7sin(2π i 700) +
1
9sin(2π i 900)...
4
Export To square100Hz.wav
Choose Export from the File menu and save as square100Hz.wav. Quit from Audacity.
Octave
Create these three files in Octave. Save them in the m208Lab14 folder.
gensin.m
## gensin ( amp, freq, secs )## returns sine wave samples for a given## amplitude, frequency, and duration
## Author: John Ellinger <[email protected]>## Created: 2013-04-13
function [ ret ] = gensin (amp, freq, secs)SR = 44100; # sample rateT = 1/SR; # sample periodnumSamp = SR*secs; # number of samples neededn = 1:numSamp; # index values from 1 to numSampret = amp * sin( 2 * pi * freq * (n-1) * T );
endfunction
freqMatch.m
## freqMatch## function [ ret ] = freqMatch ( inWav, testFreq )## requires gensin.m
## Author: John Ellinger <[email protected]>## Created: 2014-02-18
5
function [ ret ] = freqMatch ( inWav, testFreq )lenIn = length( inWav );dur = lenIn / 44100;sinTest = gensin( 1.0, testFreq, dur );ret = sum( inWav .* sinTest );
endfunction
analyzeSquare100.m
## analyzeSquare100.m## requires gensin.m and freqMatch.m
## Author: John Ellinger <[email protected]>## Created: 2014-02-14
format long; SR = 44100;BITS = 16;
[square100, SR, BITS] = wavread( "square100Hz.wav" );square100 = square100'; # column to row# length( square100 )
#test for 100 Hzprintf("--------------------------\n");match100 = freqMatch ( square100, 100 )match99point5 = freqMatch ( square100, 99.5 )match101point5 = freqMatch ( square100, 101.5 )printf("--------------------------\n");match300 = freqMatch ( square100, 300 )match299point5 = freqMatch ( square100, 299.5 )match301point5 = freqMatch ( square100, 301.5 )printf("--------------------------\n");match500 = freqMatch ( square100, 500 )match499point5 = freqMatch ( square100, 499.5 )
6
match501point5 = freqMatch ( square100, 501.5 )printf("--------------------------\n");match700 = freqMatch ( square100, 700 )match699point5 = freqMatch ( square100, 699.5 )match701point5 = freqMatch ( square100, 701.5 )printf("--------------------------\n");match900 = freqMatch ( square100, 900 )match899point5 = freqMatch ( square100, 899.5 )match901point5 = freqMatch ( square100, 901.5 )printf("--------------------------\n");format; # reset
Run analyzeSquare100. You should see these results. Note the orders of magnitude (powers of ten) difference between the matching frequencies and the surrounding frequencies that differ by 0.5 Hz.
7
8
The Fourier Theorem
Jean Baptiste Joseph Fourier (1768-1830) developed the Fourier theorem during his study of heat conduction. Hundreds of books, treatises, college and graduate school mathematics and engineering courses are devoted to the study of Fourier analysis. Although the mathematicians and scientists of Fourier's day were skeptical of his ideas, they became widely accepted after his death. However, the calculations for solving them were so difficult and time consuming that they were not widely used in science until recently. The basic premise of Fourier's theorem states that:
Any continuous periodic waveform can be transformed into the sum of sine and cosine waves of different amplitudes and phases whose frequencies are integer multiples of a fundamental frequency.
In other words an harmonic series of sinusoidal frequencies called the Fourier series.
The Fast Fourier Transform or FFT
The Fast Fourier Transform (FFT), published in 1965 (link below), is a computer algorithm that performs the Fourier Transform very quickly. The FFT is arguably the most important tool in DSP in general and digital audio in particular. FFT's are used in audio, communications, radar, sonar, mathematics, physics, geology, chemistry, economics, Photoshop filters, optical character recognition and many other disciplines. The FFT transforms samples from the time domain into another set of samples in the frequency domain. The IFFT (Inverse FFT) transforms the samples from the frequency domain back into the time domain. No information is lost in the process. The frequency domain (FFT) and time domain (IFFT) are two different ways of viewing the same signal.
http://www.ams.org/journals/mcom/1965-19-090/S0025-5718-1965-0178586-1/S0025-5718-1965-0178586-1.pdf
Spectrum
The FFT output in the frequency domain is called the spectrum of the signal. Just as a prism separates light into different colors, the FFT separates a periodic waveform into its component frequencies.
9
You do not have to understand the underlying mathematics of the Fourier transform in order to use it. This lab will show you how to use it. If you want to learn more about the math behind the Fourier Transform get on the Google.
FFT Essentials
1. FFT Size
The number of samples input to the FFT should be a power of 2 for speed. FFT size is directly related to frequency resolution and inversly related to time resolution. More details below in item 4.
2. Time Domain Samples
Time domain samples are real numbers where the X axis represents time and the Y axis represents amplitude. Digital audio samples are evenly spaced 1/SR seconds apart on the X axis and amplitude values range from −1 to +1 on the Y axis.
3. Frequency Domain Samples
Frequency domain samples are complex numbers where the X axis represents frequency and the Y axis represents either magnitude or phase. FFT samples are
10
evenly spaced in SampleRateFFT _SIZE units of Hz along the X axis and the Y axis units may be magnitude, power, decibels, or radians.
The first frequency bin is referred to as the DC offset and is a measure of waveform offset above or below the x axis. The Nyquist frequency appears at bin FFT _SIZE2 . All frequency bins to the right of the Nyquist bin are alias frequencies that are mirror images of the frequency bins to the left of the Nyquist bin. Energy values present in the frequency bins represent the amount of that the frequency present in the waveform. The bin with the largest magnitude is usually, but not always, the fundamental frequency.
For example, using a sample rate of 44100 Hz and an FFT size of 4096, the frequency bins along the x axis are equally spaced in units of 441004096 = 10.7Hz . If bin 30 has the largest magnitude, the fundamental frequency is the bin number times the frequency spacing unit or 30 x 10.767 = 323.01 Hz.
4. FFT Uncertainty Principle
FFT size is directly proportional to frequency resolution and inversely proportional to time resolution. Large FFT sizes have excellent frequency resolution but poor time resolution. For example using an FFT window size of
28 you can resolve time to around 6 milliseconds, but your frequency resolution will be no better than 172 Hz. Conversely, if you use an FFT size of 215 you'll be able to resolve frequencies to within 1.3 Hz, but you can only resolve time to around 750 milliseconds.
11
This table shows the relationship between FFT size, frequency resolution, and time resolution at the CD sample rate of 44100 samples per second.
Power of 2 FFT Size Frequency Resolu6on in Hz Time Resolu6on in Ms6 64 689 1.57 128 345 2.98 256 172 5.89 512 86 11.610 1024 43 23.211 2048 21 46.412 4096 11 92.913 8192 5.4 185.814 16384 2.7 371.515 32768 1.3 743.0
12
FFT Example 1
Our first example is arbitrarily constructed to illustrate principles of the FFT. To keep data within manageable limits we'll use a very slow sample rate. The principles we discover also apply to the audio CD sampling rate of 44100 samples/second.
Create the file fft1.m.
Remove the function and endfunction lines, enter and execute this code.
## fft1
## Author: John Ellinger <[email protected]>## Created: 2013-05-12
## construct a 16 point sine wave with 2 periodsSR = 16;T = 1/SR;f = 2;nT = 0:T:1-T;x = sin( 2*pi*f*nT );
## set the FFT_SIZEFFT_SIZE = 2^4; # power of two
## DSP convention uses Upper Case to represent spectrum## lower case to indicate waveformX = fft( x, FFT_SIZE );
## calculate the bin frequency spacingbin_Freq = SR/FFT_SIZE;
## abs() is the octave function to compute the magnitude## of a complex number = square root of (a + ib)(a - ib)
13
mag = abs( X );
## angle() is the octave function to compute the phase## of a complex number phase (a + ib) = arctan( b/a )phase = angle( X );
len_x = length( x );len_X = length( X );
## print resultsprintf( "-------------------------------------\n" );printf( "Variables\n" );printf( "-------------------------------------\n" );printf( "Waveform\t%d samples\n", length(x) );printf( "FFT_SIZE\t%d samples\n", FFT_SIZE );printf( "Spectrum\t%d frequency bins\n", length(X) );printf( "Frequency bin spacing along X axis: %f Hz\n", bin_Freq );
printf( "-------------------------------------\n" );printf( "Time Domaian (16 samples)\n" );printf( "-------------------------------------\n" );x' # display values in column
printf( "-------------------------------------\n" );printf( "Frequency Domain (16 Complex Numbers)\n" );printf( "-------------------------------------\n" );X' # display values in column
printf( "-------------------------------------\n" );printf( "FFT Magnitude Results\n" );printf( "-------------------------------------\n" );mag' # display values in column
printf( "-------------------------------------\n" );printf( "FFT Phase Results Radians\n" );printf( "-------------------------------------\n" );
14
phase' # display values in column
printf( "-------------------------------------\n" );printf( "FFT Phase Results Degrees\n" );printf( "-------------------------------------\n" );degrees = phase .* 360/(2*pi);degrees' # display values in column
These results should appear in the Octave terminal. The waveform samples are symmetrical around the center because the sample rate (16 Hz) is an integer multiple of the frequency (2 Hz).c
-------------------------------------Variables-------------------------------------Waveform 16 samplesFFT_SIZE 16 samplesSpectrum 16 frequency binsFrequency bin spacing along X axis: 1.000000 Hz
-------------------------------------Time Domaian (16 samples)-------------------------------------ans =
0.00000 0.70711 1.00000 0.70711 0.00000 -0.70711 -1.00000 -0.70711 -0.00000 center of symmetry values alternate plus and minus above and below 0.70711 1.00000 0.70711 0.00000 -0.70711 -1.00000 -0.70711
15
-------------------------------------Frequency Domain (16 Complex Numbers)-------------------------------------ans =
-0.00000 - 0.00000i -0.00000 - 0.00000i -0.00000 + 8.00000i 0.00000 + 0.00000i 0.00000 - 0.00000i -0.00000 + 0.00000i 0.00000 + 0.00000i 0.00000 + 0.00000i 0.00000 - 0.00000i center of symmetry values alternate plus and minus above below 0.00000 - 0.00000i 0.00000 - 0.00000i -0.00000 - 0.00000i 0.00000 + 0.00000i 0.00000 - 0.00000i -0.00000 - 8.00000i -0.00000 + 0.00000i
-------------------------------------FFT Magnitude Results-------------------------------------ans =
6.4325e-16 = 0 Hz ignored for symmetry 8.6444e-16 8.0000e+00 1.6352e-15 2.4493e-16 9.4302e-16 1.8513e-15 1.3563e-15 1.1331e-15 center of symmetry values alternate plus and minus above below 1.3563e-15 1.8513e-15 9.4302e-16 2.4493e-16 1.6352e-15 8.0000e+00 8.6444e-16
16
-------------------------------------FFT Phase Results Radians-------------------------------------ans =
3.14159 = 0 Hz ignored for symmetry 2.89292 -1.57080 -0.81769 0.00000 -2.30018 -1.28535 -0.20576 0.00000 center of symmetry values alternate plus and minus above and below 0.20576 1.28535 2.30018 -0.00000 0.81769 1.57080 -2.89292
-------------------------------------FFT Phase Results Degrees-------------------------------------ans =
180.00000 = 0 Hz ignored for symmetry 165.75222 -90.00000 -46.85027 0.00000 -131.79059 -73.64526 -11.78902 0.00000 center of symmetry values alternate plus and minus above below 11.78902 73.64526 131.79059 -0.00000 46.85027 90.00000 -165.75222
17
FFT Example 2
Let's plot the results. Create a new file fft2a.m. Note: It's called fft2a to avoid a conflict with the Octave fft2 function.
You can reuse the beginning of fft1.m.
## fft2a
## Author: John Ellinger <[email protected]>## Created: 2013-05-12
## construct the sine waveSR = 16;T = 1/SR;f = 2;nT = 0:T:1-T;x = sin( 2*pi*f*nT );x' # display values in column
## set the FFT_SIZEFFT_SIZE = 2^4 # power of two
## DSP convention uses Upper Case to represent spectrum## lower case to indicate waveformX = fft( x, FFT_SIZE );
## calculate the bin frequency spacingbin_Freq = SR/FFT_SIZE;
# spectrum is 32 complex numbersX' # display values in column
len_x = length( x );len_X = length( X );
18
## print variablesprintf( "-------------------------------------\n" );printf( "Variables\n" );printf( "-------------------------------------\n" );printf( "Waveform\t%d samples\n", length(x) );printf( "FFT_SIZE\t%d samples\n", FFT_SIZE );printf( "Spectrum\t%d frequency bins\n", length(X) );printf( "Frequency bin spacing along X axis: %f Hz\n\n", bin_Freq );
## five plots in 5 separate windows using "figure"fig1 = figure;plot( x ); # plot it# set up labels and titlexlabel("time (seconds)");ylabel("x(t)");title("Sample Sine Wave Line Plot");grid; # turn on grid
fig2 = figure;stem( x ); # plot it# set up labels and titlexlabel("time (seconds)");ylabel("x(t)");title("Sample Sine Wave Stem Plot");grid; # turn on grid
fig3 = figure;plot( X ); # FFT results as complex numbers# set up labels and titlexlabel("frequency bins" );ylabel("");title("Raw FFT Plot - NOT HELPFUL");grid; # turn on grid# not exactly helpful
19
fig4 = figure;## abs() is the octave function to compute the magnitude## of a complex number = square root of (a + ib)(a - ib)stem( abs( X ) ); # FFT Magnitude plot# set up labels and titlexlabel("frequency bins" );ylabel("Magnitude");title("FFT Magnitude Plot - MOST HELPFUL");grid; # turn on grid
fig5 = figure;## angle() is the octave function to compute the phase## of a complex number phase (a + ib) = arctan( b/a )stem( angle( X ) ); # FFT Phase plot# set up labels and titlexlabel("frequency bins" );ylabel("Phase");title("FFT Phase Plot");grid; # turn on grid
20
The waveform is not a smooth sine wave because of the low sampling rate.
The stem plot best represents the nature of sampling. You can see the symmetry between positive and negative samples.
21
A plot of the complex number values returned by the FFT is not helpful.
The FFT Magnitude plot displays the frequency spectrum and has the most helpful frequency information.
22
You can see two frequency spikes at bin 3 and bin 15. Because bin 1 represents 0 Hz, bin 3 is 2 Hz and bin 15 is 14 Hz. Bin 16 represents SR-1Hz = 15 Hz and bin 8 represents SR/2, the Nyquist frequency. Recall from earlier in the term that frequency f > SR/2 will be aliased to the frequency SR - f. Thus 14 Hz is heard as 2 Hz. All the frequency information we need is contained in the left half of the full spectrum plot.
FFT Phase Plot
The phase information is necessary to transform the signal back to the time domain, but has little significance to the frequencies we hear.
23
To recap the important points
1. The time domain is sampled in seconds in units of 1/SR.
2. The FFT of N real valued time samples returns N complex valued frequency bins.
3. The frequency domain is sampled in Hz in units of binF .
0 ibin_ f , 1ibin_ f , 2 ibin_ f , 3 ibin_ f ... (FFT _SIZE −1) ibin_ f
where bin_ f = SampleRateFFT _SIZE
4. The magnitude spectrum displays the frequency energy in each frequency bin.
5. Frequency bin values are complex numbers a+ib.
The magnitude of a frequency bin is
(a + ib)(a − ib) = a2 + b2
The phase of a frequency bin is
arctan b
a( ).
24
FFT Example 3
Example 1 was contrived so that the sample rate was an integer multiple of the frequency. What happens when we take the FFT of an arbitrary frequency? A similar symmetry exists in the sample values and FFT results.
Create a new file fft3.m.
You can reuse the beginning of fft1.m.
## fft3
## Author: John Ellinger <[email protected]>## Created: 2013-05-12
## construct a 16 point sine wave with 2 periodsSR = 16;T = 1/SR;f = 2.7;nT = 0:T:1-T;x = sin( 2*pi*f*nT );
## set the FFT_SIZEFFT_SIZE = 2^4; # power of two
## DSP convention uses Upper Case to represent spectrum## lower case to indicate waveformX = fft( x, FFT_SIZE );
## calculate the bin frequency spacingbin_Freq = SR/FFT_SIZE;
## abs() is the octave function to compute the magnitude## of a complex number = square root of (a + ib)(a - ib)mag = abs( X );
25
## angle() is the octave function to compute the phase## of a complex number phase (a + ib) = arctan( b/a )phase = angle( X );
len_x = length( x );len_X = length( X );
## print resultsprintf( "-------------------------------------\n" );printf( "Variables\n" );printf( "-------------------------------------\n" );printf( "Waveform\t%d samples\n", length(x) );printf( "FFT_SIZE\t%d samples\n", FFT_SIZE );printf( "Spectrum\t%d frequency bins\n", length(X) );printf( "Frequency bin spacing along X axis: %f Hz\n\n", bin_Freq );
printf( "-------------------------------------\n" );printf( "Time Domaian (16 samples)\n" );printf( "-------------------------------------\n" );x' # display values in column
printf( "-------------------------------------\n" );printf( "Frequency Domain (16 Complex Numbers)\n" );printf( "-------------------------------------\n" );X' # display values in column
printf( "-------------------------------------\n" );printf( "FFT Magnitude Results\n" );printf( "-------------------------------------\n" );mag' # display values in column
## time domain and frequency domain stem plotsfig1 = figure;stem( x ); # plot it# set up labels and title
26
xlabel("time (seconds)");ylabel("x(t)");title("Sample Sine Wave Stem Plot");grid; # turn on grid
fig2 = figure;stem( abs( X ) ); # FFT Magnitude plot# set up labels and titlexlabel("frequency bins" );ylabel("Magnitude");title("FFT Magnitude Plot");grid; # turn on grid
The FFT results results show the sme symmetry as the 2 Hz example.
-------------------------------------Variables-------------------------------------Waveform 16 samplesFFT_SIZE 16 samplesSpectrum 16 frequency binsFrequency bin spacing along X axis: 1.000000 Hz
There is no symmetry to the sample values.-------------------------------------Time Domaian (16 samples)-------------------------------------ans =
0.00000 0.87250 0.85264 -0.03926 -0.89101 -0.83147 0.07846 0.90814 0.80902 -0.11754 -0.92388 -0.78532 0.15643
27
0.93819 0.76041 -0.19509 0.76041 -0.19509
-------------------------------------Frequency Domain (16 Complex Numbers)-------------------------------------ans =
1.59223 - 0.00000i 0 Hz, ignored for symmetry 1.78752 - 0.41809i 3.08923 - 1.53900i -4.91496 + 4.14706i -0.69318 + 0.97320i -0.17988 + 0.50422i -0.00205 + 0.28121i 0.07124 + 0.12883i 0.09191 - 0.00000i SR/2, Nyquist rate, center of symmetry 0.07124 - 0.12883i -0.00205 - 0.28121i -0.17988 - 0.50422i -0.69318 - 0.97320i -4.91496 - 4.14706i 3.08923 + 1.53900i 1.78752 - 0.00000i SR
-------------------------------------FFT Magnitude Results-------------------------------------ans =
1.592227 0 Hz, ignored for symmetry 1.835765 3.451357 6.430779 1.194833 0.535345 0.281216 0.147218 0.091914 SR/2, Nyquist rate, center of symmetry 0.147218 0.281216 0.535345 1.194833
28
6.430779 3.451357 1.835765 SR
The Waveforms Are Different
2 Hz waveform 2.7 Hz waveform
The Spectrums Are Very Different
2 Hz Spectrum 2.7 Hz Spectrum
Fft Frequency Bin Leakage
The frequency bins of both the 2 Hz and 2.7 Hz example are spaced at 1 Hz intervals. The 2 Hz frequency spectrum, only showed energy present in two frequency bins. The 2.7 Hz frequency spectrum shows energy present in all bins.The freqeuncy bin with the largest magnitude is now in bin 4 and indicating
29
substantial energy at 3 Hz. Some of the 2.7 Hz frequency has "leaked" energy into bins to the left and right of bin 4. We can no longer get an exact frequency measurement from the bin with the largest magnitude.
30
FFT Example 4
Create a new fft4.m file. You can reuse the first part of fft3.m.
## fft4
## construct a 16 point sine wave with 2 periodsSR = 16;T = 1/SR;f = 2.7;nT = 0:T:1-T;x = sin( 2*pi*f*nT );
## set the FFT_SIZEFFT_SIZE = 2^4; # power of two
## DSP convention uses Upper Case to represent spectrum## lower case to indicate waveformX = fft( x, FFT_SIZE );
printf( "-------------------------------------\n" );printf( "FFT(x)\n" );printf( "-------------------------------------\n" );X' # column display
printf( "-------------------------------------\n" );printf( "FFT(x) Scaled Values\n" );printf( "-------------------------------------\n" );XS = X .* 1.0/FFT_SIZE;XS' # column display
printf( "-------------------------------------\n" );printf( "X Magnitude\n" );printf( "-------------------------------------\n" );XM = abs(X);XM' # column display
31
printf( "-------------------------------------\n" );printf( "X Scaled Magnitude\n" );printf( "-------------------------------------\n" );XMS = abs( XM );XMS' # column display
printf( "-------------------------------------\n" );printf( "X Phase\n" );printf( "-------------------------------------\n" );XP = angle(X);XP' # column display
printf( "-------------------------------------\n" );printf( "X Scaled Phase\n" );printf( "-------------------------------------\n" );XPS = angle(XS);XPS' # column display
Interpreting The FFT
The imaginary parts of the FFT complex numbers are non zero.
-------------------------------------FFT(x)-------------------------------------ans =
1.59223 - 0.00000i 1.78752 - 0.41809i 3.08923 - 1.53900i -4.91496 + 4.14706i -0.69318 + 0.97320i -0.17988 + 0.50422i -0.00205 + 0.28121i 0.07124 + 0.12883i 0.09191 - 0.00000i
32
0.07124 - 0.12883i -0.00205 - 0.28121i -0.17988 - 0.50422i -0.69318 - 0.97320i -4.91496 - 4.14706i 3.08923 + 1.53900i 1.78752 + 0.41809i
FFT Scaled Values
The real and imaginary parts of the complex numbers been reduced by 1/SR = 1/16. We'll use the scaled values later.
-------------------------------------FFT(x) Scaled Values-------------------------------------ans =
0.09951 - 0.00000i 0.11172 - 0.02613i 0.19308 - 0.09619i -0.30718 + 0.25919i -0.04332 + 0.06083i -0.01124 + 0.03151i -0.00013 + 0.01758i 0.00445 + 0.00805i 0.00574 - 0.00000i 0.00445 - 0.00805i -0.00013 - 0.01758i -0.01124 - 0.03151i -0.04332 - 0.06083i -0.30718 - 0.25919i 0.19308 + 0.09619i 0.11172 + 0.02613i
33
Magnitude
The magnitude is calculate using the abs() function in octave.
-------------------------------------X Magnitude-------------------------------------ans =
1.592227 1.835765 3.451357 6.430779 1.194833 0.535345 0.281216 0.147218 0.091914 0.147218 0.281216 0.535345 1.194833 6.430779 3.451357 1.835765
34
The magnitude of a complex numbers a+ib is defined as
a2 + b2 or (a + ib)(a − ib)
-------------------------------------Magnitude Calculated by Pythagorean Theorem-------------------------------------ans = 1.5922ans = 1.8358ans = 3.4514ans = 6.4308ans = 1.1948ans = 0.53535ans = 0.28122ans = 0.14722ans = 0.091914ans = 0.14722ans = 0.28122ans = 0.53535ans = 1.1948ans = 6.4308ans = 3.4514ans = 1.8358
-------------------------------------Magnitude Calculated by Complex Conjugate-------------------------------------ans = 1.5922ans = 1.8358ans = 3.4514ans = 6.4308ans = 1.1948ans = 0.53535ans = 0.28122ans = 0.14722ans = 0.091914ans = 0.14722ans = 0.28122
35
ans = 0.53535ans = 1.1948ans = 6.4308ans = 3.4514ans = 1.8358
Scaled Magnitude
The magnitudes of the scaled FFT are 1/SR of the direct magnitudes.
-------------------------------------X Scaled Magnitude-------------------------------------ans =
0.0995142 0.1147353 0.2157098 0.4019237 0.0746771 0.0334591 0.0175760 0.0092011 0.0057446 0.0092011 0.0175760 0.0334591 0.0746771 0.4019237 0.2157098 0.1147353
36
Phase
-------------------------------------X Phase-------------------------------------ans =
0.00000 0.22976 0.46219 -2.44073 -2.18971 -1.91346 -1.57809 -1.06567 0.00000 1.06567 1.57809 1.91346
37
2.18971 2.44073 -0.46219 -0.22976
For the complex numbers a+ib values of the FFT, phase is defined as
arctan ba .
-------------------------------------Calculated Phase using atan2( b, a )-------------------------------------ans = 0ans = 0.22976ans = 0.46219ans = -2.4407ans = -2.1897ans = -1.9135ans = -1.5781ans = -1.0657ans = 0ans = 1.0657ans = 1.5781ans = 1.9135ans = 2.1897ans = 2.4407ans = -0.46219ans = -0.22976
38
FFT Example 5 The Fourier Series
Once you know the magnitude and phase values of the FFT you can reconstruct the waveform using the Fourer series formula where n and N represent the FFT size (16 in our example) and k represents the frequency bin index of the complex number in the FFT results.
FourierSeries = x(0)+ x(1)+ x(2)...x(N −1)where
x(n) = Ck cos2π knN
+φk⎛⎝⎜
⎞⎠⎟k=0
N−1
∑
The Fourier coefficient Ck is the scaled magnitude value of frequency bin k from the FFT. The scaled magnitude is the actual magnitude divided by the sample rate. The phase φk is the phase value of of frequency bin k from the FFT.
39
The calculation for x(3) would look like this.
x(3) = C0 cos 2π 0 i 316
+φ0⎛⎝⎜
⎞⎠⎟ +C1 cos 2π1• 3
16+φ1
⎛⎝⎜
⎞⎠⎟
+C2 cos 2π 2• 316
+φ2⎛⎝⎜
⎞⎠⎟ +C3 cos 2π 3• 3
16+φ3
⎛⎝⎜
⎞⎠⎟
...
+C14 cos 2π14 • 316
+φ14⎛⎝⎜
⎞⎠⎟ +C15 cos 2π15• 3
16+φ15
⎛⎝⎜
⎞⎠⎟
We'd need to calculate this 16 times, for x(0) to x(16), to produce 16 sine waves harmonically related to the fundamental frequency 2π16 and then add them together to reconstruct the original waveform. Here's Octave code to do just that.
Reconstructing the Waveform From The FFT
Create a new fft5.m file. You can reuse the first part of fft4.m.
## fft5
## Author: John Ellinger <[email protected]>## Created: 2013-05-12
## construct a 16 point sine wave with 2 periodsSR = 16;T = 1/SR;f = 2;nT = 0:T:1-T;x = sin( 2*pi*f*nT );
## set the FFT_SIZEFFT_SIZE = 2^4; # power of two
## DSP convention uses Upper Case to represent spectrum
40
## lower case to indicate waveformX = fft( x, FFT_SIZE );
## scale values to -1 to +1# X = X .* 1.0/FFT_SIZE;
# The FFT_SIZE determines the f0 = 2*pi/FFT_SIZE;y = [];A = abs( X ); # magnitude
## scale values to -1 to +1A = A .* 1.0/FFT_SIZE; # magnitude = amplitude
P = angle( X ); # phase
N = FFT_SIZE;f0 = 2 * pi / N;## loop 16 timesfor n = 0:FFT_SIZE-1
y(n+1) = \A(1)*cos( (n*0*f0) + P(1)) + \A(2)*cos( (n*1*f0) + P(2) ) + \A(3)*cos( (n*2*f0) + P(3) ) + \A(4)*cos( (n*3*f0) + P(4) ) + \A(5)*cos( (n*4*f0) + P(5) ) + \A(6)*cos( (n*5*f0) + P(6) ) + \A(7)*cos( (n*6*f0) + P(7) ) + \A(8)*cos( (n*7*f0) + P(8) ) + \A(9)*cos( (n*8*f0) + P(9) ) + \A(10)*cos( (n*9*f0) + P(10) ) + \A(11)*cos( (n*10*f0) + P(11) ) + \A(12)*cos( (n*11*f0) + P(12) ) + \A(13)*cos( (n*12*f0) + P(13) ) + \A(14)*cos( (n*13*f0) + P(14) ) + \A(15)*cos( (n*14*f0) + P(15) ) + \A(16)*cos( (n*15*f0) + P(16) );
endfor
41
figure;plot(x);title( "Original" );figure;stem(x);title( "Original" );
figure;plot( y );title( "Reconstructed x" );figure;stem( y );title( "Reconstructed x" );
## print resultsprintf( "------------------------------------------\n" );printf( "original\treconstructed\terror\n" );printf( "------------------------------------------\n" );for n = 1:FFT_SIZE
printf("%f\t%f\t%f\n", x(n), y(n), x(n) - y(n) );endfor
The results agree. The original and reconstructed signals match.
42
43
44
FFT Example 6 The IFFT (Inverse FFT)
Fortunately you'll never have to reconstruct a Fourier series by hand, just use the IFFT function. The IFFT takes FFT frequency results as input and returns time domain samples.
Create a new fft6.m file. You can reuse the first part of fft5.m.
## fft6
## Author: John Ellinger <[email protected]>## Created: 2013-05-12
## construct a 16 point sine wave with 2 periodsSR = 16;T = 1/SR;f = 2;nT = 0:T:1-T;x = sin( 2*pi*f*nT );
## set the FFT_SIZEFFT_SIZE = 2^4; # power of two
## DSP convention uses Upper Case to represent spectrum## lower case to indicate waveformX = fft( x, FFT_SIZE );
## compute the IFFTinv_x = ifft( X );
printf( "---------------------------------------------\n" );printf( "x\t\tinv_x\t\tdifference\n" );printf( "---------------------------------------------\n" );for n = 1:length(x)
printf( "%f\t%f\t%f\n", x(n), inv_x(n), inv_x(n) - x(n) );endfor
You should see these results.
45
A typical digital audio use of the FFT and IFFT is to
1. Take the FFT 2. Modify the Spectrum3. Take the IFFT of the modified spectrum4. Play the result.
46
Audio Rate FFT
Choose Tone from the Generate menu.
Generate a Sawtooth wave with a frequency of 300 Hz, amplitude of 1.0, and a duration of 0.5 seconds.
47
Choose Plot Spectrum from the Anaylze menu and make these settings.
If you take readings at each of the 5 peaks you'll get:
Peak Expected Freq Audacity Freq Amplitude dB1 300 299 -3.22 600 600 -103 900 900 -14.54 1200 1199 -18.65 1500 1496 -19.4
Export To square100Hz.wav
Choose Export from the File menu and save as saw300.wav. Quit from Audacity.
48
Octave
Create a new Octave file sawFFT.m.
## sawFFT## Author: John Ellinger <[email protected]>## Created: 2013-05-14
# create our saw wave[x, SR, BITS] = wavread( "saw300.wav" );x = x';
# definesSR = 44100;FFT_SIZE = 2^12;BIN_F = SR / FFT_SIZE;LEFT_HALF = FFT_SIZE / 2;
# printprintf( "SR = %d\nFFT_SIZE = %d\nBIN_F = %f\n", SR, FFT_SIZE, BIN_F );
# take the fft and find the magnitude spectrumX = fft(x, FFT_SIZE);X_Mag = abs( X );
# plot the spectrumfigure1 = figure;stem( X_Mag );
# plot the left half of the spectrumfigure2 = figure;stem( X_Mag( 1:LEFT_HALF ) );
# plot a small portion of the spectrum# empirically we know that the highest expected frequency is 1500 Hz# we also know that the BIN_F is 10.77 Hz# if we plot the first 200 bins we'll cover the 0 - 2000+ Hz rangefigure3 = figure;stem( X_Mag( 1:200 ) );
49
Full Spectrum Plot
50
Left Half Spectrum Plot
51
First 200 Frequency Bins Plot
52
Crude Frequency Estimation
Add these lines to sawFFT1.
# calculate the five maximum magnitude bin indexes# first make a copy of X_Magmag = X_Mag(1:LEFT_HALF);
# find the first peak[x xi1] = max( mag );f1 = (xi1-1) * BIN_F;printf( "xi1 = %d\t f1 = %f\n", xi1-1, f1 );
# set magnitude of peakcs adjacent xi1 to zero and find peak 2mag(xi1) = 0;mag(xi1-1) = 0;mag(xi1+1) = 0;[x xi2] = max( mag);f2 = (xi2-1) * BIN_F;printf( "xi2 = %d\t f2 = %f\n", xi2-1, f2 );
# set magnitude of xi2 to zero and find peak 3mag(xi2) = 0;mag(xi2-1) = 0;mag(xi2+1) = 0;[x xi3] = max( mag );f3 = (xi3-1) * BIN_F;printf( "xi3 = %d\t f3 = %f\n", xi3-1, f3 );
# set magnitude of xi3 to zero and find peak 4mag(xi3) = 0;mag(xi3-1) = 0;mag(xi3+1) = 0;[x xi4] = max( mag );f4 = (xi4-1) * BIN_F;printf( "xi4 = %d\t f4 = %f\n", xi4-1, f4 );
# set magnitude of xi4 to zero and find peak 5mag(xi4) = 0;
53
mag(xi4-1) = 0;mag(xi4+1) = 0;[x xi5] = max( mag );f5 = (xi5-1) * BIN_F;printf( "xi5 = %d\t f5 = %f\n", xi5-1, f5 );
You should get these results that are reasonably close to the actual frequencies.
Let's see if we can do better.
Increase The FFT Size
One way of improving frequency resolution is to increase the FFT_SIZE. If you don't have enough samples you can simply add more zeros. The Octave FFT does this automatically if you ask for an FFT_SIZE that is larger than the number of samples. Here's the documentation.
Increase FFT_SIZE and run the program again.
54
The frequency resolution has improved from a 10.77 Hz bin spacing to a 1.34 Hz spacing.
The draw back to this method is is takes longer and may make real time calculations impossible.
Peak Frequency Estimation By Interpolation
Another method of estimating the peak frequency is based on the amount of leakage present in the left and right frequency bins. I adapted this formula from the book Understanding Digital Signal Processing (2nd Edition) by Richard Lyons.
Estimate Pitch Lyons Method
Create a new Octave file extimatePitchLyons.m. Save it in the same folder as sawFFT1.m.
55
## estimatePitchLyons## F is the result of the fft() function## ix is the bin index of interest## sr is Sample Rate## sz is the FFT_SIZE
## Author: John Ellinger <[email protected]>## Created: 2013-05-14
function y = estimatePitchLyons( F, ix, sr, sz ) mmax = F( ix ); prev = F( ix - 1 ) ; next = F( ix + 1 ) ;
delta = ( next - prev ) / ( (2.0 * mmax - prev) - next );
% -1 to convert one based bins to zero based binspeakbin = ix - 1 - real(delta);y = peakbin * ( sr / sz );
end
Change the FFT_SIZE back to 2^ 12.
Add these lines to the end of sawFFT1.m
printf("**** Lyons Pitch Estimation Method ****\n");f1 = estimatePitchLyons( X, xi1, SR, FFT_SIZE )f2 = estimatePitchLyons( X, xi2, SR, FFT_SIZE )f3 = estimatePitchLyons( X, xi3, SR, FFT_SIZE )f4 = estimatePitchLyons( X, xi4, SR, FFT_SIZE )f5 = estimatePitchLyons( X, xi5, SR, FFT_SIZE )
The results are even better than with increasing FFT_SIZE.
56
Let's see how small an FFT_SIZE we can use and still get a good result. Remember smaller FFT_SIZE means better realtime performance.
Using an FFT_SIZE of 2^10 = 1024 we still get good results.
If we go lower than that we'll need to improve our maximum peak choosing method because we'll get errors.
57
You can see the 300 Hz fundamental lies between bin xi1 and xi2. The 600 Hz tone was picked up at xi4 and the 900 Hz tone at xi5. This is the classic trade-off with the FFT. You need large FFT_SIZE for frequency resolution and small FFT_SIZE for time resolution.
Magnitude To Decibels
Add these lines to sawFFT.m.
# find magnitude at the 5 peaks# need to go back to one based indexing# make a copy of X_Magprintf("**** Raw Magnitude ****\n");mag = X_Mag(1:LEFT_HALF);mag1 = mag( xi1 )mag2 = mag( xi2 )mag3 = mag( xi3 )mag4 = mag( xi4 )mag5 = mag( xi5 )
# find maximum magnitude and scale to 1.0
58
printf("**** Normalized Magnitude ****\n");maxMag = max( mag );mag1 = mag( xi1 ) / maxMagmag2 = mag( xi2 ) / maxMagmag3 = mag( xi3 ) / maxMagmag4 = mag( xi4 ) / maxMagmag5 = mag( xi5 ) / maxMag
printf("**** Normalized Magnitude to Decibels ****\n");# print Octave Magnitude in dBamp1 = 20 * log10( mag1 )amp2 = 20 * log10( mag2 )amp3 = 20 * log10( mag3 )amp4 = 20 * log10( mag4 )amp5 = 20 * log10( mag5 )
printf("**** Scaled to Audacity -3.1 dB ****\n");# print Audacity scaled magnitude# Subtract 3.1 that Audacity thought was first peak dBamp1 = 20 * log10( mag1 ) - 3.1amp2 = 20 * log10( mag2 ) - 3.1amp3 = 20 * log10( mag3 ) - 3.1amp4 = 20 * log10( mag4 ) - 3.1amp5 = 20 * log10( mag5 ) - 3.1
59