/* 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); }
/* * 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)); } }
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; }
/// <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; }
/// <summary> /// The main. /// </summary> /// <param name="args"> /// The args. /// </param> static void Main(string[] args) { var audioBuffer = new byte[256]; var fftData = new byte[256]; var fft = new double[256]; double fftavg = 0; float amplitude = 10.0f; var fftTransoformer = new LomontFFT(); var writers = new List<IWriter>(); writers.Add(new KeyboardWriter()); writers.Add(new ConsoleWriter()); var audioCapture = new AudioCapture(AudioCapture.DefaultDevice, 8000, ALFormat.Mono8, 256); audioCapture.Start(); audioCapture.ReadSamples(audioBuffer, 256); while (true) { for (int j = 0; j < 92; j++) { // reset mem for (int i = 0; i < 256; i++) { audioBuffer[i] = 0; fftData[i] = 0; fft[i] = 0; } audioCapture.ReadSamples(audioBuffer, 256); for (int i = 0; i < 256; i++) { fft[i] = (audioBuffer[i] - 128) * amplitude; } fftTransoformer.TableFFT(fft, true); for (int i = 0; i < 256; i += 2) { double fftmag = Math.Sqrt((fft[i] * fft[i]) + (fft[i + 1] * fft[i + 1])); fftavg += fftmag; fftData[i] = (byte)fftmag; fftData[i + 1] = fftData[i]; } fftavg /= 10; writers.ForEach(x => x.Write(j, fftData)); //Thread.Sleep(15); Thread.Sleep(20); } } }
/// <summary> /// Return true if unit tests pass /// </summary> /// <returns>true if and only if the tests all passed</returns> public static bool UnitTest() { #region Test Data // some tests of various lengths. Answers are for (A,B) types (1,1), (0,1), (1,-1), and (-1,1) double[] t4 = { 0.9463910302640065255, 2.1719817340114636428, 0.5408022840459105995546, 1.5560308568160938805 }; double[] t8 = { -0.00585152907659816402, -0.38747973044006503981, -0.07599531911180304592, 0.45076971245423087174, 0.26739426495460068114, -0.26125937528189408420, 0.41416072137518122013, -0.01641988546867230817 }; double[] t16 = { 1.315477046808896429519, 1.207210985661466858068, 0.121056790034505835908, -0.25379277220838383483, 0.913644534255553004335, 0.927677591320202188087, 2.235664368076910734991, -0.375686965597889518826, 2.301831908175541205636, 1.06141993445964001079, -0.06885421111166161113, 0.537848193477814512702, 1.776371630015752925985, -0.337293413841513571577, 2.476154181731257139688, -0.246423441467474887253 }; double[] t32 = { 0.43456805587961525780, -0.06380054971262695336, -0.488558284014200504051, -0.416304883965628375255, -0.469871270992736403590, -0.25166411067679778788, 0.40215502170455820014, -0.35830084570211135293, -0.05852687773965932269, 0.06837143745059148373, 0.39433540724645248849, -0.24284994799967130717, 0.35674139694999335405, -0.12888862317683722326, -0.483481846064623712881, 0.31470624594663715993, -0.36261847505420561595, 0.45600311160472028856, -0.32101981739601821164, -0.39660499028915120615, 0.12690816916754634235, -0.15432871988088497073, -0.20789746477910645318, 0.11641012713093763133, 0.15442520359906394183, 0.45398815306631095852, 0.26643905565987603855, -0.443374926998731886764, 0.34684336103208890521, 0.11453023518323556461, -0.24188480129115013822, -0.37645566690319011335 }; double[][] a4R = { new[] { 5.215205905137474648, -2.240819276517640398, 0.405588746218095926, 0.615950877195369762 }, new[] { 2.607602952568737324, -1.120409638258820199, 0.2027943731090479630, 0.307975438597684881 }, new[] { 5.215205905137474648, -2.240819276517640398, 0.405588746218095926, -0.615950877195369762 }, new[] { 1.303801476284368662, -0.560204819129410100, 0.1013971865545239815, 0.153987719298842441 } }; double[][] a4C = { new[] { 1.487193314309917125, 3.728012590827557523, 0.405588746218095926, 0.615950877195369762 }, new[] { 1.051604477483838966, 2.636102983322995846, 0.286794552823765311, 0.435543042142648332 }, new[] { 1.487193314309917125, 3.728012590827557523, 0.405588746218095926, 0.615950877195369762 }, new[] { 0.743596657154958563, 1.864006295413778762, 0.2027943731090479630, 0.307975438597684881 } }; double[][] a8R = { new[] { 0.38531885940498013, 0.81409741687778125, -0.69284999587841737, -0.24905437675199995, -0.07662266638537566, -1.08308893270751769, 0.14635840781601968, 0.73125770422196858 }, new[] { 0.13623078920216368, 0.28782690201036541, -0.24495946521535021, -0.08805401934276420, -0.027090203496846828, -0.38292976447279300, 0.05174551132518686, 0.25853864072513031 }, new[] { 0.38531885940498013, 0.81409741687778125, -0.69284999587841737, 0.24905437675199995, -0.07662266638537566, 1.08308893270751769, 0.14635840781601968, -0.73125770422196858 }, new[] { 0.048164857425622516, 0.101762177109722656, -0.086606249484802171, -0.031131797093999994, -0.009577833298171957, -0.135386116588439711, 0.018294800977002460, 0.091407213027746072 } }; double[][] a8C = { new[] { 0.5997081381413806913, -0.2143892787364005604, -0.7404353919541020251, -0.6163763956451552217, -0.0766226663853756571, -1.0830889327075176876, 0.1939438038917043347, 0.3639356853288133104 }, new[] { 0.2998540690706903457, -0.1071946393682002802, -0.3702176959770510125, -0.3081881978225776108, -0.0383113331926878286, -0.5415444663537588438, 0.0969719019458521674, 0.1819678426644066552 }, new[] { 0.5997081381413806913, -0.2143892787364005604, 0.1939438038917043347, 0.3639356853288133104, -0.0766226663853756571, -1.0830889327075176876, -0.7404353919541020251, -0.6163763956451552217 }, new[] { 0.1499270345353451728, -0.05359731968410014011, -0.1851088479885255063, -0.1540940989112888054, -0.01915566659634391428, -0.2707722331768794219, 0.04848595097292608369, 0.09098392133220332761 } }; double[][] t16R = { new[] { 13.59230635979061742, 8.55038613618289391, -1.21492956216715601, -0.45486697068671133, 1.47323644084476175, -2.83216031656357654, 0.71462633901964782, 0.66109635428761313, 1.54330399052473147, 3.197070083395729214, -3.29601473130025480, -0.99282859461499410, 0.38134914058150166, 6.48707162520707076, -0.14910149101881611, 1.34211646345148113 }, new[] { 3.39807658994765436, 2.137596534045723477, -0.303732390541789004, -0.113716742671677833, 0.368309110211190438, -0.708040079140894134, 0.178656584754911956, 0.165274088571903281, 0.385825997631182867, 0.799267520848932303, -0.82400368282506370, -0.248207148653748524, 0.095337285145375415, 1.62176790630176769, -0.037275372754704028, 0.335529115862870283 }, new[] { 13.59230635979061742, 8.55038613618289391, -1.21492956216715601, 0.45486697068671133, 1.47323644084476175, 2.83216031656357654, 0.71462633901964782, -0.66109635428761313, 1.54330399052473147, -3.197070083395729214, -3.29601473130025480, 0.99282859461499410, 0.38134914058150166, -6.48707162520707076, -0.14910149101881611, -1.34211646345148113 }, new[] { 0.849519147486913589, 0.534399133511430869, -0.075933097635447251, -0.028429185667919458, 0.092077277552797609, -0.177010019785223534, 0.044664146188727989, 0.041318522142975820, 0.096456499407795717, 0.1998168802122330758, -0.206000920706265925, -0.062051787163437131, 0.023834321286343854, 0.405441976575441923, -0.009318843188676007, 0.083882278965717571 } }; double[][] t16C = { new[] { 11.071346247986755665, 2.520960111803861757, -1.295808722180236886, -1.221072246496360113, 0.021126962378336621, -2.981369228242905398, 0.625454618595877207, 1.441125106282221185, 1.543303990524731466, 3.197070083395729214, -3.206843010876484186, -0.212799842620386036, 1.833458619047926789, 6.337862713527741902, -0.068222331005735240, 0.575911187641832353 }, new[] { 3.914312004407837382, 0.891293995078653829, -0.458137567287160258, -0.431714232908133866, 0.007469509181797447, -1.054073199255731085, 0.221131601066795241, 0.509514667595171310, 0.545640358566148453, 1.130334967948880571, -1.133790219595723673, -0.075236105876152529, 0.648225511276855981, 2.240772851482419665, -0.024120236441254322, 0.203615353071368931 }, new[] { 11.071346247986755665, 2.520960111803861757, -0.068222331005735240, 0.575911187641832353, 1.833458619047926789, 6.337862713527741902, -3.206843010876484186, -0.212799842620386036, 1.543303990524731466, 3.197070083395729214, 0.625454618595877207, 1.441125106282221185, 0.021126962378336621, -2.981369228242905398, -1.295808722180236886, -1.221072246496360113 }, new[] { 1.3839182809983444581, 0.3151200139754827196, -0.1619760902725296107, -0.1526340308120450141, 0.0026408702972920776, -0.3726711535303631747, 0.0781818273244846509, 0.1801406382852776481, 0.1929129988155914333, 0.3996337604244661517, -0.4008553763595605232, -0.0265999803275482545, 0.2291823273809908486, 0.7922328391909677378, -0.0085277913757169050, 0.0719888984552290441 } }; double[][] a32R = { new[] { -1.46000712101570392, 1.15712078883069226, -0.56341032896397069, -0.97348179246515461, -1.56634631955235446, -2.03358236992303745, 0.10016779686778672, -0.28982229431706279, 1.59649489283936457, 0.48088940342020419, 0.61889994518995724, -0.94638900654944842, 1.44036681871883545, 0.56879809230684088, -0.40555236689846115, 1.76515791462870041, 1.208382291775918752, 2.296985822638620811, 0.63608517570432352, -0.54113478089643728, 1.89167325112076917, -0.74545011136225907, 2.66767101857698704, -0.02967504673446225, -1.98204239178352045, -0.28372150043265964, 1.51795039241265502, 1.43503462291130686, -1.86148873042323007, 0.83836086563695189, 1.80568061458128929, -0.76801487986712270 }, new[] { -0.258095233962713142, 0.204551989108527394, -0.099597816050241796, -0.172088894203436537, -0.276893526060515187, -0.359489970968497496, 0.017707332105432151, -0.051233827412659624, 0.282223091214101301, 0.085010039539794926, 0.109407087029950338, -0.167299521042878729, 0.254623286228045786, 0.100550247049034749, -0.071692207190039153, 0.312038782824764749, 0.213613828195123352, 0.406053562869282277, 0.112445035288190932, -0.095660018276941854, 0.334403745914174673, -0.131778207195130101, 0.471582066802652984, -0.005245856694491492, -0.350378903957332773, -0.050155349231088902, 0.268338253994942301, 0.253680678274516299, -0.329067826096150775, 0.148202663293328177, 0.319202251806880595, -0.135767132401553529 }, new[] { -1.46000712101570392, 1.15712078883069226, -0.56341032896397069, 0.97348179246515461, -1.56634631955235446, 2.03358236992303745, 0.10016779686778672, 0.28982229431706279, 1.59649489283936457, -0.48088940342020419, 0.61889994518995724, 0.94638900654944842, 1.44036681871883545, -0.56879809230684088, -0.40555236689846115, -1.76515791462870041, 1.208382291775918752, -2.296985822638620811, 0.63608517570432352, 0.54113478089643728, 1.89167325112076917, 0.74545011136225907, 2.66767101857698704, 0.02967504673446225, -1.98204239178352045, 0.28372150043265964, 1.51795039241265502, -1.43503462291130686, -1.86148873042323007, -0.83836086563695189, 1.80568061458128929, 0.76801487986712270 }, new[] { -0.0456252225317407476, 0.0361600246509591330, -0.017606572780124084, -0.030421306014536081, -0.048948322486011077, -0.063549449060094920, 0.003130243652118335, -0.009056946697408212, 0.0498904654012301429, 0.0150277938568813810, 0.019340623287186164, -0.029574656454670263, 0.045011463084963608, 0.017774940384588778, -0.012673511465576911, 0.055161184832146888, 0.0377619466179974610, 0.0717808069574569003, 0.019877661740760110, -0.016910461903013665, 0.059114789097524036, -0.023295315980070596, 0.083364719330530845, -0.000927345210451945, -0.0619388247432350139, -0.0088662968885206138, 0.047435949762895469, 0.044844831965978339, -0.058171522825725940, 0.026198777051154746, 0.056427519205665290, -0.024000464995847585 } }; double[][] a32C = { new[] { -0.151443166092505834, -1.308563954923198090, 1.244058936325143007, -1.434392792279571653, -1.105324127259872307, -1.528329335338557865, -0.060884434278954178, -1.13372709101066608, 1.002720860253378163, 1.717218822886712110, 1.062676103603080428, -1.433258891213431473, 1.49134454751956007, 0.48916776214349496, -0.51494251390467968, 1.651791582176155218, 1.208382291775918752, 2.296985822638620811, 0.745475322710542044, -0.654501113348982475, 1.840695522320044552, -0.825080441525604990, 2.223894860163863861, -0.51654493139844530, -1.388268359197534037, 0.952607919033848279, 1.679002623559395916, 0.591129826217703575, -2.32251092271571222, 1.34361390022143147, -0.00178865070782441, -1.228925879681539749 }, new[] { -0.037860791523126458, -0.327140988730799523, 0.311014734081285752, -0.358598198069892913, -0.276331031814968077, -0.382082333834639466, -0.015221108569738544, -0.283431772752666519, 0.250680215063344541, 0.429304705721678028, 0.265669025900770107, -0.358314722803357868, 0.372836136879890017, 0.122291940535873739, -0.128735628476169919, 0.412947895544038804, 0.302095572943979688, 0.574246455659655203, 0.186368830677635511, -0.163625278337245619, 0.460173880580011138, -0.206270110381401247, 0.555973715040965965, -0.129136232849611326, -0.347067089799383509, 0.238151979758462070, 0.419750655889848979, 0.147782456554425894, -0.580627730678928055, 0.335903475055357867, -0.000447162676956103, -0.307231469920384937 }, new[] { -0.151443166092505834, -1.308563954923198090, -0.001788650707824411, -1.228925879681539749, -2.322510922715712221, 1.343613900221431469, 1.679002623559395916, 0.591129826217703575, -1.388268359197534037, 0.952607919033848279, 2.223894860163863861, -0.516544931398445303, 1.840695522320044552, -0.825080441525604990, 0.745475322710542044, -0.654501113348982475, 1.208382291775918752, 2.296985822638620811, -0.514942513904679676, 1.651791582176155218, 1.491344547519560067, 0.489167762143494958, 1.062676103603080428, -1.433258891213431473, 1.002720860253378163, 1.717218822886712110, -0.060884434278954178, -1.133727091010666075, -1.105324127259872307, -1.528329335338557865, 1.244058936325143007, -1.434392792279571653 }, new[] { -0.0094651978807816146, -0.0817852471826998806, 0.0777536835203214379, -0.0896495495174732283, -0.0690827579537420192, -0.0955205834586598666, -0.0038052771424346361, -0.0708579431881666297, 0.0626700537658361352, 0.1073261764304195069, 0.0664172564751925267, -0.0895786807008394671, 0.0932090342199725042, 0.0305729851339684349, -0.0321839071190424798, 0.1032369738860097011, 0.0755238932359949220, 0.1435616139149138007, 0.0465922076694088777, -0.0409063195843114047, 0.1150434701450027845, -0.0515675275953503119, 0.1389934287602414913, -0.0322840582124028314, -0.0867667724498458773, 0.0595379949396155175, 0.1049376639724622447, 0.0369456141386064734, -0.1451569326697320138, 0.0839758687638394668, -0.0001117906692390257, -0.0768078674800962343 } }; double[][] tests = { t4, t8, t16, t32 }; double[][][] ansr = { a4R, a8R, t16R, a32R }; double[][][] ansc = { a4C, a8C, t16C, a32C }; #endregion var fftObject = new LomontFFT(); int[] ab = { 1, 1, 0, 1, 1, -1, -1, 1 }; // A,B parameter pairs var success = true; // single test action makes debugging easier Action <int, int> testAction = (testIndex, paramIndex) => { var test = tests[testIndex]; fftObject.A = ab[2 * paramIndex]; fftObject.B = ab[2 * paramIndex + 1]; var answerReal = ansr[testIndex][paramIndex]; var answerComplex = ansc[testIndex][paramIndex]; success &= Test(fftObject.RealFFT, test, answerReal); success &= Test(fftObject.FFT, test, answerComplex); success &= Test(fftObject.TableFFT, test, answerComplex); }; for (var testIndex = 0; testIndex < tests.Length; testIndex++) { for (var t = 0; t < ab.Length / 2; t++) { testAction(testIndex, t); } } return(success); }
public Fft(int winsize, IWindowFunction window) { this.winsize = winsize; this.fftsize = 2 * winsize; fftwData = fftwf_malloc(fftsize * sizeof(float)); fftwPlan = fftwf_plan_r2r_1d(fftsize, fftwData, fftwData, FFTW_R2HC, FFTW_ESTIMATE | FFTW_DESTROY_INPUT); fft = new float[fftsize]; window.Initialize(winsize); win = window; data = new float[fftsize]; lomonFFT = new Lomont.LomontFFT(); }
/// <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; }
/* 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 AudioService() { lomonFFT = new Lomont.LomontFFT(); }
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 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; }
/// /// <summary> * Create an FFT transformer for a given sample size. This preallocates /// * resources appropriate to that block size. A specified window /// * function will be applied to all input data. /// * </summary> /// * <param name="size"> The number of samples in a block that we will /// * be asked to transform. Must be a power of 2. </param> /// * <param name="window"> Window function to apply to all input data. /// * Its block size must be the same as the size /// * parameter. </param> /// * <exception cref="IllegalArgumentException"> Invalid parameter. </exception> /// public FFTTransformer(int size, Window window) { if (!IsPowerOf2(size)) { throw new System.ArgumentException("size for FFT must" + " be a power of 2 (was " + size + ")"); } windowFunc = window; transformer = new LomontFFT(); blockSize = size; // Allocate working data arrays. xre = new double[blockSize]; }