I am using Measurement Studio 8.1 to read an analog input that I would
like to get the frequency from. It would be simpler to use a counter
but one is not available so
I am resorting to using an analog scan of the channel then a FFT to get
the frequency. In the real application the signal will be coming from a
hall effect sensor reading an RPM. For testing I am sampling at 10kHz, my test
signal is at 400Hz, and I am gathered 2500 points/channel.
During
development I am using a signal generator to test the program. I
thought I had it working fine because when I use a sine, square, or
triangle wave with a 50% duty cycle all works well and my program does
exactly what I want. The problem is, I started to test with a square
wave of varying duty cycle and now it is not working. First it was
reading zero because my simple algorithm was grabbing the DC component
for it's calculation. Fixed that. But now I have a situation where my
FFT result looks to be double or sometimes triple what the test signal frequency is. I do
not claim to be a FFT or PowerSpectrum expert but I did find a few good
articles at NI developer zone that make me think I am doing the basics
right. The help files don't give examples, just equations. I did run the sample program called Filtering and if you vary the suty cycle of the square wave in that sample I think I can see why I am getting the problem I am getting, I just don't know how to fix it. If a multimeter is smart enough to give me the right frequency of the signal I'm sure Measurement Studio can do the same...I just don't know how. The function I am using to get the frequency from an analog signal is listed below. Any suggestions would be greatly appreciated.
public static double CalcFrequencyViaFFT(double[,] AIScandata, int arrayIndexForCalc, int scanRate)
{
double[] dataRow;
double[] dataRowCopy;
double mx, mn, offset, scale;
int idxMax, idxMin;
//Extract Row to be used for calculation
dataRow = ArrayOperation.CopyRow(AIScandata, arrayIndexForCalc);
dataRowCopy = (double[]) dataRow.Clone();
//Scale copy to -1 to 1 signal
dataRowCopy = ArrayOperation.Scale1D(dataRowCopy, out offset, out scale);
int datasize = dataRow.Length;
ComplexDouble[] FFTValue;
double[] magnitudes;
double[] phases;
//Perform FFT
//FFTValue = Transforms.RealFft(dataRow);
//Try using power spectrum to see if it can give the same result more directly
// ** In the end gives same result as .RealFft. TODO: benchmark to see which is faster
Transforms.PowerSpectrum(dataRowCopy);
dataRowCopy[0] = 0.0; //Get rid of DC component so I can find variable component
ArrayOperation.MaxMin1D(dataRowCopy, out mx, out idxMax, out mn, out idxMin);
//Use FFT data
//ComplexDouble.DecomposeArrayPolar(FFTValue, out magnitudes, out phases);
//ArrayOperation.MaxMin1D(magnitudes, out mx, out idxMax, out mn, out idxMin);
// Console.Out.WriteLine("\t\tDEBUG INFO: scanrate,datasize,idxMax={0}, {1}, {2}",
// scanRate,datasize,idxMax);
return (double) scanRate/datasize*idxMax;
} //end CalcFrequencyViaFFT