/// <summary> /// Извлечение данных из комплексной сонограммы (L+R) /// </summary> /// <param name="FFT_T"> Выходной набор векторов коэффициентов. </param> /// <param name="usePolyphase"> Использовать полифазное FFT? </param> /// <param name="fftObj"> Объект FFT, для которого вызывается функция. </param> /// <returns> Результат разбора выходных данных CFFT. </returns> public static CFFT_ExploreResult Explore(double[][] FFT_T, bool usePolyphase, ExactFFT.CFFT_Object fftObj) { int plotRowsCount; CFFT_ExploreResult res; res = new CFFT_ExploreResult(); if (FFT_T == null) { throw new Exception("ExactPlotter::Explore(): (FFT_T == null)"); } // Считываем количество строк, которые имеет сонограмма... plotRowsCount = FFT_T.Length; // Подготавливаем выходные массивы... res.MagL = new double[plotRowsCount][]; res.MagR = new double[plotRowsCount][]; res.ACH = new double[plotRowsCount][]; res.ArgL = new double[plotRowsCount][]; res.ArgR = new double[plotRowsCount][]; res.PhaseLR = new double[plotRowsCount][]; // Работаем по всем строкам сонограммы... Parallel.For(0, plotRowsCount, frame => { // Количество гармоник в два раза меньше размера кадра FFT res.MagL[frame] = new double[fftObj.N >> 1]; res.MagR[frame] = new double[fftObj.N >> 1]; res.ACH[frame] = new double[fftObj.N >> 1]; res.ArgL[frame] = new double[fftObj.N >> 1]; res.ArgR[frame] = new double[fftObj.N >> 1]; res.PhaseLR[frame] = new double[fftObj.N >> 1]; // Извлечение данных FFT из комплексной сонограммы ExactFFT.CFFT_Explore(FFT_T[frame], res.MagL[frame], res.MagR[frame], res.ACH[frame], res.ArgL[frame], res.ArgR[frame], res.PhaseLR[frame], usePolyphase, fftObj); }); return(res); }
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); }