50 % (2) The MathWorks (MATLAB company) Documentation Center page, "Fast
51 % Fourier Transform" explains the practical basics, as well as some of the
52 % theory of FFTs, link:
53 % http://www.mathworks.com/help/matlab/math/fast-fourier-transform-fft.html
54
55 % (3) The MathWorks Documentation Center page on the ’fft’ function
56 % supplements the above, link:
57 % http://www.mathworks.com/help/matlab/ref/fft.html
58
59 % (4) The MathWorks Documentation Center page on "Power Spectral Density
60 % Estimates Using FFT" informed this function’s power output option. Link:
61 % http://www.mathworks.com/help/signal/ug/psd-estimate-using-fft.html
62
63 % (5) The MathWorks Documentation Center page on "Amplitude Estimation and
64 % Zero Padding" informs this function’s option of using zero-padding and is
65 % important to spectroscopy, link:
66 % http://www.mathworks.com/help/signal/ug/amplitude-estimation-and-zero-padding.html
67
68 % (6) Short presentation online, "FFT Normalisation for Beginners",
69 % concering total power in wave, link:
70 % http://www.hep.ucl.ac.uk/~rjn/saltStuff/fftNormalisation.pdf
71
72 %% PERFORM THE FFT, INITIAL PROCESSING OF RESULTS
73
74 % The size of the orignal time-series data is the window length; this can
75 % be extended with zero padding.
76
77 length_signal = length(data_signal);
78 if (num_zeroPad > 0) % user wants zero-padding
79 num_fftPts = 2^(nextpow2(length_signal)+(num_zeroPad-1));
80 else % user does not want zero-padding
81 num_fftPts = length_signal;
82 end
83
84 % Perform the fft, with number of points as calculated above.
85 F = fft(data_signal,num_fftPts);
86
87 % Calculate frequency step size
88 deltaFreq = rate_sample/num_fftPts;
89
90 % Calculate the Nyquist frequency
91 Nyq = rate_sample/2;
92
93 % Create the (inital) frequency axis (correct spacing, but runs to sample
94 % frequency)
95 f = (0:(num_fftPts-1))*deltaFreq;
96 % Adjust frequency axis to have negative frequencies (i.e. only <= Nyquist
97 % frequency content).
98 f(f>Nyq) = f(f>Nyq)-(Nyq*2);
99 % Alternatively (to above), could have done below, as the vector elements
100 % in the range of (floor(end/2)+2:end) are/correspond to negative
101 % frequencies (for both even/odd # of fft points)(and mirror the positive
102 % frequency terms).
103 %f(floor(end/2)+2:end) = f(floor(end/2)+2:end) - (Nyq*2);
104
105 %% CONVERT FFT RESULTS TO SELECTED OUTPUT TYPE
106
107 switch case_output
108
109 case 0 % COMPLEX FFT RESULTS - ALL FREQUENCIES (INCLUDING NEGATIVE)
110 % Values for this case already calculated above, just pass along.
111
112 output_fft = F;
113 output_freqaxis = f;
114
115 case 1 % COMPLEX FFT RESULTS - DC TO POSITIVE FREQUENCIES
116 % Similar to case 0 above, but only pass DC and positive
117 % frequencies. Useful for real signals, which is the usual
118 % application.
119
120 % note to self, set up like case 0 but also mult DC and Nyquist (if
121 % present by 2)
122 % Set output frequency axis as positive frequencies.
123 output_freqaxis = f(f>=0);
124 % Alternatively (to above), could have used fact that vector
125 % elements in range of (1:ceil(end/2)) are the DC and positive
126 % frequencies (for both even/odd # of fft points). Would also need
127 % to account for Nyquist component in case of even # fft points.
128 %output_freqaxis = f(1:(ceil(end/2)+(1-mod(num_fftPts,2))))
129
130 % Pass along complex Fourier terms as they are (no amp(), etc.)
131 output_fft = F(f>=0);
132 % Normalize to window length
133 output_fft = output_fft/length_signal;
134
135 % Double non-unique frequency components (i.e. those other than
136 % DC and, if present, Nyquist) as taking single sideband spectrum
137 % of a real signal.
138 output_fft(2:ceil(num_fftPts/2)) = output_fft(2:ceil(num_fftPts/2))*2;
139
140 case 2 % AMPLITUDE
141 % Need to select only DC and positive frequencies for axis. And to
142 % take real amplitude of complex Fourier coefficients.
143
144 % Set output frequency axis as positive frequencies - same as in
145 % complex case (#1) above.
146 output_freqaxis = f(f>=0);
147
148 % Take real amplitude of complex Fourier terms (in elements
149 % corresponding to positive frequencies as above for frequency
150 % axis)(and could instead select such elements with ’ceil’, ’mod’,
151 % etc. as alternatively suggested above).
152 output_fft = abs(F(f>=0));
153 % Normalize to window length
154 output_fft = output_fft/length_signal;
155 % Multiply non-unique components by 2 as in above case.
156 output_fft(2:ceil(num_fftPts/2)) = output_fft(2:ceil(num_fftPts/2))*2;
157
158 case 3 % POWER (simple square of amplitude)
159 % Square the amplitude values and divide by the number of FFT points.
160
161 % Set output frequency axis as positive frequencies - same as in
162 % complex case (#1) above.
163 output_freqaxis = f(f>=0);
164
165 % Take the amplitudes as in amplitude case above, square, divide by
166 % number of FFT points.
167 output_fft = abs(F(f>=0)).^2;
168
169 % Multiply non-unique components by 2 as in above case.
170 output_fft(2:ceil(num_fftPts/2)) = output_fft(2:ceil(num_fftPts/2))*2;
171
172 case 4 % POWER (sum squared amplitude)
173 % Square the amplitude values and divide by the number of FFT points.
174
175 % Set output frequency axis as positive frequencies - same as in
176 % complex case (#1) above.
177 output_freqaxis = f(f>=0);
178
179 % Take the amplitudes as in amplitude case above, square, divide by
180 % number of FFT points.
181 output_fft = (1/num_fftPts).*abs(F(f>=0)).^2;
182
183 % Multiply non-unique components by 2 as in above case.
184 output_fft(2:ceil(num_fftPts/2)) = output_fft(2:ceil(num_fftPts/2))*2;
185
186 case 5 % POWER SPECTRAL DENSITY (linear power per Hz)
187 % Very similar to power case above, but scale differently for ’per
188 % Hz’ spectral density.
189
190 % Set output frequency axis as above.
191 output_freqaxis = f(f>=0);
192
193 % Take the amplitudes as in power case above, but change
194 % pre-factor.
195 output_fft = (1/(rate_sample*num_fftPts)).*abs(F(f>=0)).^2;
196
197 % Multiply non-unique components by 2 as in above case.
198 output_fft(2:ceil(num_fftPts/2)) = output_fft(2:ceil(num_fftPts/2))*2;
199
200 otherwise % user selected undefined value for ’case_output’
201 % Let use know of the problem and pass along zeros.
202
203 disp(’Error in fft_plus function: improper case_output value’)
204 output_freqaxis = 0;
205 output_fft = 0;
206
207 end
208
209 end