
FFT Programming (Magnitude and Phase), Please Help

baitzer
I've been using Igor Pro for about five years now, however I have only just ventured into the art of programming. Currently I am attempting to modify a prexisting experiment that performs FFT on interferometric fringe patterns. The original function listed below works well but only outputs the Magnitude of the Fourier Transform:
Function RealTimeFFT2(w,windowing,resolution,limits) //designed to do a fast FFT of wave named "w" //w is considered to be an optical spectrum from the ocean optics CCD. The routine takes the wavelength x-axis from //"Wavelength" and converts it to the proper frequency scaling before FFT. string w variable windowing //This is the windowing: 1= None; 2=Hanning variable resolution //Resolution enhancement: 1, 2, 3, 4, 5, 6 are: none;2;4;8;16;32 respectively. Actually just determines how many data points are in the FFT variable limits //Modified from Wavemetrics Library //Given an input wave ( doesn't have to be a power of two), creates a new wave //with the suffix "_Mag" that contains the normalized frequency response //Several levels of resolution enhancement (really just sin x/x interpolation) are provided. //Options include windowing (Hann) vs no windowing. string destw=w+"_Mag" Variable n //= numpnts($w) variable start_point, end_point if (limits) //want to do FFT only on portion of spectrum selected between the cursors in the spectrum window NVAR GCursorAPoint_spectrum=GCursorAPoint_spectrum NVAR GCursorBPoint_spectrum=GCursorBPoint_spectrum GCursorAPoint_spectrum=pcsr(A,"Graph4") GCursorBPoint_spectrum=pcsr(B,"Graph4") start_point=GCursorAPoint_spectrum end_point=GCursorBPoint_spectrum else //do FFT on entire spectrum start_point=0 end_point=numpnts($w)-1 endif if( (resolution<1) %| (resolution>6) ) Abort "resolution out of range" endif resolution=2^resolution //convert this resolution value to the appropriate binary number (if file length is 2^n, it speeds up the FFT algorithm) //resolution -= 1 Duplicate/O/R=[start_point,end_point] Wavelength, xData xData=1/xData //X axis will be 1/nm so FT will be in nm Duplicate/O/R=[start_point,end_point] $w, yData Sort xData, xData, yData // sort by increasing X Duplicate/O yData, tempFFT // make tempFFT file to contain properly scaled waveform SetScale/I x xData[0], xData[(numpnts(xData)-1)], tempFFT // set the range of X values tempFFT = interp(x, xData, yData) if(windowing==2) Hanning tempFFT; tempFFT *= 2 //assumes continuous rather than pulsed data endif n= numpnts(yData) Redimension/N=(CeilPwr2(n)*2^resolution) tempFFT //pad with zeros to power of 2 //print "resolution is " +num2str(resolution) //print "Ceilpwr2(n) is " +num2str(CeilPwr2(n)) //print "number of new data points is " +num2str(CeilPwr2(n)*2^resolution) FFT tempFFT Wave/C tempFFTC= tempFFT //this resets the complex part of FTspectrum, which was generated in the fft tempFFTC=r2polar(tempFFT) Redimension/R tempFFTC //NOTE: depending on your application you may want to un-comment the next line // $destw[0] /= 2 //dc is special tempFFT /= n/2 SetScale y,0,0,"Cts",tempFFT Redimension/R tempFFT Duplicate/O tempFFT $destw end
I would like to also calculate the phase angle from the FFT. I am basing my modification on the example experiement "MagPhase Demo". As I have previously mentioned this is my first attempt at igor pro programming and while I am slowly learning how it all works, I keep getting an error code near the end of the function, "Function not available for this numbertype", relating to the line ----- tempFFT_Phase = imag(r2polar(tempFFT2)). I believe that this indicates that the wave has not been identified as complex, however I thought I had addressed this previously with ----- Wave/C tempFFT_Phase= tempFFT2.
Any help would be greatly appreciated and as I am still a beginner, example code would be fantastic.
Function RealTimeFFTMagPhase(w,windowing,resolution,limits) //designed to do a fast FFT of wave named "w" //w is considered to be an optical spectrum from the ocean optics CCD. The routine takes the wavelength x-axis from //"Wavelength" and converts it to the proper frequency scaling before FFT. string w variable windowing //This is the windowing: 1= None; 2=Hanning variable resolution //Resolution enhancement: 1, 2, 3, 4, 5, 6 are: none;2;4;8;16;32 respectively. Actually just determines how many data points are in the FFT variable limits //Modified from Wavemetrics Library //Given an input wave ( doesn't have to be a power of two), creates a new wave //with the suffix "_Mag" that contains the normalized frequency response //Several levels of resolution enhancement (really just sin x/x interpolation) are provided. //Options include windowing (Hann) vs no windowing. string destw_Mag, destw_Phase destw_Mag=w+"_Mag" //Destination file for Magnitude destw_Phase=w+"_Phase" //Destingation file for Phase Variable n //= numpnts($w) variable start_point, end_point if (limits) //want to do FFT only on portion of spectrum selected between the cursors in the spectrum window NVAR GCursorAPoint_spectrum=GCursorAPoint_spectrum NVAR GCursorBPoint_spectrum=GCursorBPoint_spectrum GCursorAPoint_spectrum=pcsr(A,"Graph4") GCursorBPoint_spectrum=pcsr(B,"Graph4") start_point=GCursorAPoint_spectrum end_point=GCursorBPoint_spectrum else //do FFT on entire spectrum start_point=0 end_point=numpnts($w)-1 endif if( (resolution<1) %| (resolution>6) ) Abort "resolution out of range" endif resolution=2^resolution //convert this resolution value to the appropriate binary number (if file length is 2^n, it speeds up the FFT algorithm) //resolution -= 1 Duplicate/O/R=[start_point,end_point] Wavelength, xData xData=1/xData //X axis will be 1/nm so FT will be in nm Duplicate/O/R=[start_point,end_point] $w, yData Sort xData, xData, yData // sort by increasing X Duplicate/O yData, tempFFT // make tempFFT file to contain properly scaled waveform SetScale/I x xData[0], xData[(numpnts(xData)-1)], tempFFT // set the range of X values tempFFT = interp(x, xData, yData) if(windowing==2) Hanning tempFFT; tempFFT *= 2 //assumes continuous rather than pulsed data endif n= numpnts(yData) Redimension/N=(CeilPwr2(n)*2^resolution) tempFFT //pad with zeros to power of 2 //print "resolution is " +num2str(resolution) //print "Ceilpwr2(n) is " +num2str(CeilPwr2(n)) //print "number of new data points is " +num2str(CeilPwr2(n)*2^resolution) FFT tempFFT Duplicate/O/C tempFFT, tempFFT2 //Duplicated Fourier Transformed wave for Mag and Phase analysis Wave/C tempFFT_Mag= tempFFT //this resets the complex part of FTspectrum, which was generated in the fft Wave/C tempFFT_Phase= tempFFT2 tempFFT_Mag=r2polar(tempFFT) Redimension/R tempFFT_Mag //NOTE: depending on your application you may want to un-comment the next line // $destw_Mag[0] /= 2 //dc is special tempFFT /= n/2 SetScale y,0,0,"Cts",tempFFT Redimension/R tempFFT Duplicate/O tempFFT $destw_Mag tempFFT_Phase = imag(r2polar(tempFFT2)) //**************ERROR********** "Function not available for this numbertype" tempFFT_Phase *= 180/PI // Convert phase to degrees Redimension/R tempFFT_Phase tempFFT2 /= n/2 SetScale y,0,0,"Cts",tempFFT2 Redimension/R tempFFT2 Duplicate/O tempFFT2 $destw_Phase end
Thanks
Andy
imag()
returns a real number, not a complex one. So Igor throws an error because you declared tempFFT_Phase to be complex.April 19, 2013 at 01:41 am - Permalink
Wave/C tempFFT_Phase= tempFFT2
to
Wave tempFFT_Phase= tempFFT2
cleared up the error associated with the imag() tag, however now I receive an error on the very next line:
tempFFT_Phase *= 180/PI wave assignment error: "Complex wave used in real expression."
I thought that the imag() tag converted the imaginary component of the complex wave into a real number, as shown in the example experiment MagPhase Demo.
Thanks again for your fast reply
April 19, 2013 at 07:38 am - Permalink
There is no conversion here. imag() is a function that returns a real value. If you assign it to a complex wave the compiler will find it objectionable.
The solution to many of these problems is to use MatrixOP. MatrixOP does not care if your input is real or complex. It attempts to give you the correct output as implied by the return values of all the tokens that appear on the right hand side of the MatrixOP expression.
Also note that you were apparently working from a very old example. FFT has a /DEST flag and /OUT flag that would make your code a bit more compact.
A.G.
WaveMetrics, Inc.
April 19, 2013 at 10:08 am - Permalink
Modified my function to include MatrixOP and now it works great.
April 20, 2013 at 04:31 am - Permalink
Thanks again for your earlier help. I just have a few additional questions relating to the phase angle. I modified my original code according to A.G. and 741's suggestions which solved the associated error's I was receiving.
New Code:
I have now managed to plot both the Magnitude and Phase on a single graph as shown in the attached image (Magnitude = red, phase = blue), however the phase is massive >20 kDegrees. I thought that the phase extracted from the FFT was between -Pi and Pi or -180 to 180 degrees if converted.
http://www.igorexchange.com/files/images/FFT%20Magnitude%20&%20Phase%20(Zoom).JPG
Does anyone have a suggestion as to why my code is creating such a large phase?
Also the project I am modifying the code for requires the phase angle at the magnitude. Now that I have extracted the phase information from the FFT, how would I determine the phase angle. I can easily find the magnitude via peak fitting the red trace but I am unsure how to determine the related phase angle.
Cheers
April 26, 2013 at 10:26 pm - Permalink
April 27, 2013 at 07:22 am - Permalink