/* This method duplicates exactly the function * fft(input) in MATLAB * Input is e.g. an audio signal * Return a complex return arrray. * i.e. the array alternates between a real and an imaginary value * */ public static double[] FFT(double[] input) { Lomont.LomontFFT fft = new Lomont.LomontFFT(); double[] complexSignal = DoubleToComplexDouble(input); fft.FFT(complexSignal, true); return(complexSignal); }
public const double TWO_PI = 2 * Math.PI; //6.283186F; #endregion Fields #region Methods /* * Mimic the original DFT function that was a part of * Wav2Zebra2Java. * Does a 2 x abs() / N before returning the value * */ public static float[] DFTLomont(float[] input) { int N = input.Length; Lomont.LomontFFT fft = new Lomont.LomontFFT(); // even - Re, odd - Img double[] complexSignal = new double[2 * N]; for (int j = 0; j < N; j++) { complexSignal[2*j] = (double) input[j]; complexSignal[2*j + 1] = 0; // need to clear out as fft modifies buffer (phase) } fft.FFT(complexSignal, true); // get power spectral density float[] mag = new float[N]; for (int j = 0; j < N; j++) { double re = complexSignal[2*j]; double img = complexSignal[2*j + 1]; mag[j] = (float) (2 * Math.Sqrt(re*re + img*img) / N); } // rotate left (i.e. shift the first element so it becomes the last float temp = mag[0]; Array.Copy(mag, 1, mag, 0, mag.Length - 1); mag[mag.Length-1] = temp; return mag; }
/* This method duplicates exactly the function * ifft(input) in MATLAB * Requires a complex input number to be able to exactly * transform back to an orginal signal * i.e. x = ifft(fft(x)) * Parameter: inputComplex * If true, the input array is a complex arrray. * i.e. the array alternates between a real and an imaginary value * If false, the array contains only real values * Parameter: returnComplex * If true, return a complex return arrray. * i.e. the array alternates between a real and an imaginary value * If false, return only the positive real value * */ public static double[] IFFT(double[] input, bool inputComplex = true, bool returnComplex = true) { Lomont.LomontFFT fft = new Lomont.LomontFFT(); double[] complexSignal; if (inputComplex) { complexSignal = input; } else { complexSignal = DoubleToComplexDouble(input); } fft.FFT(complexSignal, false); if (returnComplex) { return(complexSignal); } else { return(Real(complexSignal)); } }
/* * Mimic the original DFT function that was a part of * Wav2Zebra2Java. * Does a 2 x abs() / N before returning the value * */ public static float[] DFTLomont(float[] input) { int N = input.Length; Lomont.LomontFFT fft = new Lomont.LomontFFT(); // even - Re, odd - Img double[] complexSignal = new double[2 * N]; for (int j = 0; j < N; j++) { complexSignal[2 * j] = (double)input[j]; complexSignal[2 * j + 1] = 0; // need to clear out as fft modifies buffer (phase) } fft.FFT(complexSignal, true); // get power spectral density float[] mag = new float[N]; for (int j = 0; j < N; j++) { double re = complexSignal[2 * j]; double img = complexSignal[2 * j + 1]; mag[j] = (float)(2 * Math.Sqrt(re * re + img * img) / N); } // rotate left (i.e. shift the first element so it becomes the last float temp = mag[0]; Array.Copy(mag, 1, mag, 0, mag.Length - 1); mag[mag.Length - 1] = temp; return(mag); }
/// <summary> /// Generate a spectrogram array spaced logarithmically /// </summary> /// <param name="samples">audio data</param> /// <param name="fftWindowsSize">fft window size</param> /// <param name="fftOverlap">overlap</param> /// <param name="logBins">number of log bins along the frequency axis</param> /// <param name="logFrequenciesIndex">array of log frequency indexes</param> /// <param name="logFrequencies">array of log frequencies</param> /// <returns>log spectrogram jagged array</returns> public static float[][] CreateLogSpectrogramLomont(float[] samples, int fftWindowsSize, int fftOverlap, int logBins, int[] logFrequenciesIndex, float[] logFrequencies) { LomontFFT fft = new LomontFFT(); int numberOfSamples = samples.Length; // overlap must be an integer smaller than the window size // half the windows size is quite normal double[] windowArray = FFTWindowFunctions.GetWindowFunction(FFTWindowFunctions.HANNING, fftWindowsSize); // width of the segment - e.g. split the file into 78 time slots (numberOfSegments) and do analysis on each slot int numberOfSegments = (numberOfSamples - fftWindowsSize)/fftOverlap; float[][] frames = new float[numberOfSegments][]; // even - Re, odd - Img double[] complexSignal = new double[2*fftWindowsSize]; for (int i = 0; i < numberOfSegments; i++) { // apply Hanning Window for (int j = 0; j < fftWindowsSize; j++) { // Weight by Hann Window complexSignal[2*j] = (double) (windowArray[j] * samples[i * fftOverlap + j]); // need to clear out as fft modifies buffer (phase) complexSignal[2*j + 1] = 0; } // FFT transform for gathering the spectrum fft.FFT(complexSignal, true); frames[i] = ExtractLogBins(complexSignal, logBins, logFrequenciesIndex); } return frames; }
/* This method duplicates exactly the function * ifft(input) in MATLAB * Requires a complex input number to be able to exactly * transform back to an orginal signal * i.e. x = ifft(fft(x)) * Parameter: inputComplex * If true, the input array is a complex arrray. * i.e. the array alternates between a real and an imaginary value * If false, the array contains only real values * Parameter: returnComplex * If true, return a complex return arrray. * i.e. the array alternates between a real and an imaginary value * If false, return only the positive real value * */ public static double[] IFFT(double[] input, bool inputComplex=true, bool returnComplex=true) { Lomont.LomontFFT fft = new Lomont.LomontFFT(); double[] complexSignal; if (inputComplex) { complexSignal = input; } else { complexSignal = DoubleToComplexDouble(input); } fft.FFT(complexSignal, false); if (returnComplex) { return complexSignal; } else { return Real(complexSignal); } }
/* This method duplicates exactly the function * fft(input) in MATLAB * Input is e.g. an audio signal * Return a complex return arrray. * i.e. the array alternates between a real and an imaginary value * */ public static double[] FFT(double[] input) { Lomont.LomontFFT fft = new Lomont.LomontFFT(); double[] complexSignal = DoubleToComplexDouble(input); fft.FFT(complexSignal, true); return complexSignal; }
public static void LomontFFTTestUsingDouble(string CSVFilePath=null, double[] audio_data=null, int testLoopCount=1) { LomontFFT fft = new LomontFFT(); if (audio_data == null) { audio_data = GetSignalTestData(); } double[] complexSignal = FFTUtils.DoubleToComplexDouble(audio_data); // loop if neccesary - e.g. for performance test purposes for (int i = 0; i < testLoopCount; i++) { // perform the FFT fft.FFT(complexSignal, true); } // get the result double lengthSqrt = Math.Sqrt(audio_data.Length); int N = complexSignal.Length / 2; double[] spectrum_fft_real = new double[N]; double[] spectrum_fft_imag = new double[N]; double[] spectrum_fft_abs = new double[N]; for (int j = 0; j < N; j++) { double re = complexSignal[2*j] * lengthSqrt; double img = complexSignal[2*j + 1] * lengthSqrt; spectrum_fft_real[j] = re; spectrum_fft_imag[j] = img; spectrum_fft_abs[j] = Math.Sqrt(re*re + img*img); } // perform the inverse FFT (IFFT) fft.FFT(complexSignal, false); double[] spectrum_inverse_real = new double[N]; double[] spectrum_inverse_imag = new double[N]; double[] spectrum_inverse_abs = new double[N]; // get the result for (int j = 0; j < N; j++) { double re = complexSignal[2*j]; double img = complexSignal[2*j + 1]; spectrum_inverse_real[j] = re; spectrum_inverse_imag[j] = img; spectrum_inverse_abs[j] = Math.Sqrt(re*re + img*img); } if (CSVFilePath!=null) { CommonUtils.Export.exportCSV(CSVFilePath, audio_data, spectrum_fft_real, spectrum_fft_imag, spectrum_fft_abs, spectrum_inverse_real, spectrum_inverse_imag, spectrum_inverse_abs); } }
/// <summary> /// Generate a spectrogram array spaced linearily /// </summary> /// <param name="samples">audio data</param> /// <param name="fftWindowsSize">fft window size</param> /// <param name="fftOverlap">overlap in number of samples (normaly half of the fft window size) [low number = high overlap]</param> /// <returns>spectrogram jagged array</returns> public static float[][] CreateSpectrogramLomont(float[] samples, int fftWindowsSize, int fftOverlap) { LomontFFT fft = new LomontFFT(); int numberOfSamples = samples.Length; // overlap must be an integer smaller than the window size // half the windows size is quite normal double[] windowArray = FFTWindowFunctions.GetWindowFunction(FFTWindowFunctions.HANNING, fftWindowsSize); // width of the segment - e.g. split the file into 78 time slots (numberOfSegments) and do analysis on each slot int numberOfSegments = (numberOfSamples - fftWindowsSize)/fftOverlap; float[][] frames = new float[numberOfSegments][]; // even - Re, odd - Img double[] complexSignal = new double[2*fftWindowsSize]; for (int i = 0; i < numberOfSegments; i++) { // apply Hanning Window for (int j = 0; j < fftWindowsSize; j++) { // Weight by Hann Window complexSignal[2*j] = (double) (windowArray[j] * samples[i * fftOverlap + j]); // need to clear out as fft modifies buffer (phase) complexSignal[2*j + 1] = 0; } // FFT transform for gathering the spectrum fft.FFT(complexSignal, true); // get the ABS of the complex signal float[] band = new float[fftWindowsSize/2]; for (int j = 0; j < fftWindowsSize/2; j++) { double re = complexSignal[2*j]; double img = complexSignal[2*j + 1]; band[j] = (float) Math.Sqrt(re*re + img*img) * 4; } frames[i] = band; } return frames; }
/// <summary> /// Generate a spectrum graph array spaced linearily /// </summary> /// <param name="samples">audio data</param> /// <param name="fftWindowsSize">fft window size</param> /// <param name="fftOverlap">overlap</param> /// <returns>spectrum graph array</returns> public static float[] CreateSpectrumAnalysisLomont(float[] samples, int fftWindowsSize) { LomontFFT fft = new LomontFFT(); int numberOfSamples = samples.Length; // overlap must be an integer smaller than the window size // half the windows size is quite normal double[] windowArray = FFTWindowFunctions.GetWindowFunction(FFTWindowFunctions.HANNING, fftWindowsSize); // even - Re, odd - Img double[] complexSignal = new double[2*fftWindowsSize]; // apply Hanning Window // e.g. take 371 ms each 11.6 ms (2048 samples each 64 samples) for (int j = 0; (j < fftWindowsSize) && (samples.Length > j); j++) { // Weight by Hann Window complexSignal[2*j] = (double) (windowArray[j] * samples[j]); // need to clear out as fft modifies buffer (phase) complexSignal[2*j + 1] = 0; } // FFT transform for gathering the spectrum fft.FFT(complexSignal, true); float[] band = new float[fftWindowsSize/2]; double lengthSqrt = Math.Sqrt(fftWindowsSize); for (int j = 0; j < fftWindowsSize/2; j++) { double re = complexSignal[2*j] * lengthSqrt; double img = complexSignal[2*j + 1] * lengthSqrt; // do the Abs calculation and add with Math.Sqrt(audio_data.Length); // i.e. the magnitude spectrum band[j] = (float) (Math.Sqrt(re*re + img*img) * lengthSqrt); } return band; }