/// <summary> /// Построение комплексной сонограммы /// </summary> /// <param name="FFT_S"> Вектор входных данных /// ("левый" и "правый" каналы - чет./нечет.). </param> /// <param name="FFT_S_Offset"> Смещение данных для анализа во /// входном векторе FFT_S. </param> /// <param name="useTaperWindow"> Использовать взвешивающее окно? </param> /// <param name="recoverAfterTaperWindow"> Аннигилировать действие /// взвешивающего окна на обратном проходе? </param> /// <param name="useNorm"> Использовать нормализацию 1/N? </param> /// <param name="direction"> Направление преобразования (true - прямое). </param> /// <param name="usePolyphase"> Использовать полифазное FFT? </param> /// <param name="remainArrayItemsLRCount"> Остаток необработанных данных в исходном /// массиве (количество элементов, включая Re/Im). </param> /// <param name="fftObj"> Объект FFT, для которого вызывается функция. </param> /// <returns> Сонограмма. </returns> public static double[][] Process(double[] FFT_S, int FFT_S_Offset, bool useTaperWindow, bool recoverAfterTaperWindow, bool useNorm, bool direction, bool usePolyphase, out int remainArrayItemsLRCount, ExactFFT.CFFT_Object fftObj) { int plotRowsCount, frameOffset; double[][] FFT_T; if (FFT_S == null) { throw new Exception("ExactPlotter::Process(): (FFT_S == null)"); } // Вычисляем количество строк сонограммы... plotRowsCount = GetPlotRowsCount(FFT_S, FFT_S_Offset, out remainArrayItemsLRCount, fftObj); // Обрабатываем все фреймы... FFT_T = new double[plotRowsCount][]; Parallel.For(0, plotRowsCount, frame => { // Умножение на 2 треб. для real -> complex FFT_T[frame] = new double[fftObj.N << 1]; frameOffset = FFT_S_Offset + frame * fftObj.WindowStep << 1; ExactFFT.CFFT_Process(FFT_S, frameOffset, FFT_T[frame], useTaperWindow, recoverAfterTaperWindow, useNorm, direction, usePolyphase, fftObj); }); return(FFT_T); }
private static void Main(string[] args) { int i, j, frameWidth, polyDiv2, windowStep, N, N2, depth; // double kaiserBeta; double ACH_Difference, sampFreq, trueFreq, exactFreq, exactFreqDiff; double[] FFT_S, FFT_T, MagC, MagL, MagR, ACH, ArgC, ArgL, ArgR, PhaseLR; int FFT_S_Offset; bool useTaperWindow, recoverAfterTaperWindow, useNorm, direction, usePolyphase, isMirror, isComplex; ExactFFT.CFFT_Object fftObj; ExactFFT.CFFT_SelfTestResult selfTestResult; ExactFFT.IsDumpMode = true; // *************************************************** Console.WriteLine("ExactFFT TEST \"C#\" 8.40, (c) DrAF, 2016"); // *************************************************** // * КОНСТРУКТОР // *************************************************** frameWidth = 4096; //kaiserBeta = 28; // 28 polyDiv2 = 1; windowStep = frameWidth / 3; isComplex = false; ExactFFT.TaperWindow taperWindow = ExactFFT.TaperWindow.BLACKMAN_HARRIS_92dbPS; fftObj = ExactFFT.CFFT_Constructor_Cosine(frameWidth, taperWindow, polyDiv2, windowStep, isComplex); //fftObj = ExactFFT.CFFT_Constructor_Kaiser(frameWidth, beta, polyDiv2, windowStep, isComplex); // *************************************************** // * САМОДИАГНОСТИКА // *************************************************** ACH_Difference = 1000; selfTestResult = ExactFFT.SelfTest_RND(ACH_Difference, fftObj); Console.WriteLine("Process & Explore: {0} ms / {1} ms", (selfTestResult.CFFT_Process_time * 1000).ToString("F4"), (selfTestResult.CFFT_Explore_time * 1000).ToString("F4")); Console.WriteLine("Self-test result: {0}", selfTestResult.AllOK); // Источник и приемник FFT_S = new double[frameWidth << 1]; FFT_T = new double[frameWidth << 1]; // (Количество точек FFT / 2) - количество гармоник вместе с нулевой N = fftObj.N; N2 = N >> 1; // Массивы результатов Фурье-анализа MagC = new double[N]; MagL = new double[N2]; MagR = new double[N2]; ACH = new double[N2]; ArgC = new double[N]; ArgL = new double[N2]; ArgR = new double[N2]; PhaseLR = new double[N2]; // Читаем все данные из файла с тестовым сигналом if (!File.Exists("3600_Hz_STEREO_36000_SampleRate_36_deg_65536.raw")) { Console.WriteLine("\nCan't open 3600_Hz_STEREO_36000_SampleRate_36_deg_65536.raw!"); return; } byte[] testSignalBytes = File.ReadAllBytes("3600_Hz_STEREO_36000_SampleRate_36_deg_65536.raw"); for (i = 0, j = 0; i < (frameWidth << 1); ++i, j += 2) { FFT_S[i] = (double)BitConverter.ToInt16(testSignalBytes, j); } DebugHelper.WriteDoubles(ExactFFT.DumpName, "FFT_S.double", FFT_S); // Прямой прогон FFT useTaperWindow = true; FFT_S_Offset = 0; recoverAfterTaperWindow = false; useNorm = true; direction = true; usePolyphase = false; isMirror = true; ExactFFT.CFFT_Process(FFT_S, FFT_S_Offset, FFT_T, useTaperWindow, recoverAfterTaperWindow, useNorm, direction, usePolyphase, fftObj); DebugHelper.WriteDoubles(ExactFFT.DumpName, "FFT_T.double", FFT_T); ExactFFT.CFFT_Explore(FFT_T, MagL, MagR, ACH, ArgL, ArgR, PhaseLR, usePolyphase, fftObj); DebugHelper.WriteDoubles(ExactFFT.DumpName, "MagL.double", MagL); DebugHelper.WriteDoubles(ExactFFT.DumpName, "MagR.double", MagR); DebugHelper.WriteDoubles(ExactFFT.DumpName, "PhaseLR.double", PhaseLR); ExactFFT.CFFT_ComplexExplore(FFT_T, MagC, ArgC, usePolyphase, isMirror, fftObj); DebugHelper.WriteDoubles(ExactFFT.DumpName, "MagC.double", MagC); DebugHelper.WriteDoubles(ExactFFT.DumpName, "ArgC.double", ArgC); // Вычисление точной частоты sampFreq = 36000; trueFreq = 3600; depth = 20; exactFreq = ExactFFT.ExactFreqAuto(MagL, depth, sampFreq, fftObj); exactFreqDiff = Math.Abs(exactFreq - trueFreq); DebugHelper.WriteDouble(ExactFFT.DumpName, "exactFreq.double", exactFreq); DebugHelper.WriteDouble(ExactFFT.DumpName, "trueFreq.double", trueFreq); DebugHelper.WriteDouble(ExactFFT.DumpName, "exactFreqDiff.double", exactFreqDiff); // *************************************************** // * ДЕСТРУКТОР // *************************************************** FFT_S = null; FFT_T = null; MagC = null; MagL = null; MagR = null; ACH = null; ArgC = null; ArgL = null; ArgR = null; PhaseLR = null; ExactFFT.CFFT_Destructor(fftObj); }