Пример #1
0
        /// <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);
        }
Пример #2
0
        /// <summary>
        /// Выделение поддиапазона гармоник из сонограммы
        /// </summary>
        /// <param name="sonogram"> Исходная сонограмма. </param>
        /// <param name="lowFreq"> Частота нижней гармоники выделяемого диапазона. </param>
        /// <param name="highFreq"> Частота верхней гармоники выделяемого диапазона. </param>
        /// <param name="lowHarmIdx"> Нижний индекс гармоники. </param>
        /// <param name="highHarmIdx"> Верхний индекс гармоники. </param>
        /// <param name="fftObj"> Объект FFT, для которого вызывается функция. </param>
        /// <param name="sampleRate"> Частота семплирования. </param>
        /// <param name="harmReverse"> Требуется реверс гармоник? </param>
        /// <returns> Выделенный поддиапазон сонограммы. </returns>
        public static double[][] SubBand(double[][] sonogram, double lowFreq, double highFreq,
                                         out int lowHarmIdx, out int highHarmIdx,
                                         ExactFFT.CFFT_Object fftObj,
                                         int sampleRate,
                                         bool harmReverse = false)
        {
            if (sonogram == null)
            {
                throw new Exception("ExactPlotter::SubBand(): (sonogram == null)");
            }

            lowHarmIdx  = (int)ExactFFT.FFT_Node(lowFreq, sampleRate, fftObj.N, fftObj.IsComplex);
            highHarmIdx = (int)ExactFFT.FFT_Node(highFreq, sampleRate, fftObj.N, fftObj.IsComplex);

            return(SubBand(sonogram, lowHarmIdx, highHarmIdx, harmReverse));
        }
Пример #3
0
        /// <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);
        }
Пример #4
0
        /// <summary>
        /// Перевод значений массива double в форму dB
        /// </summary>
        /// <param name="sonogram"> Данные для обработки. </param>
        /// <param name="zero_db_level"> Значение "нулевого" уровня. </param>
        /// <param name="fftObj"> Объект FFT, для которого вызывается функция. </param>
        public static void dB_Scale(double[][] sonogram, double zero_db_level,
                                    ExactFFT.CFFT_Object fftObj)
        {
            int plotRowsCount;

            if (sonogram == null)
            {
                throw new Exception("ExactPlotter::dB_Scale(): (sonogram == null)");
            }

            // Считываем количество строк, которые имеет сонограмма...
            plotRowsCount = sonogram.Length;

            // Работаем по всем строкам сонограммы...
            Parallel.For(0, plotRowsCount, frame =>
            {
                ExactFFT.dB_Scale(sonogram[frame], zero_db_level, fftObj);
            });
        }
Пример #5
0
        /// <summary>
        /// Исследование результатов комплексного FFT (идентично CFFT из MathCAD)
        /// </summary>
        /// <param name="FFT_T"> Выходной набор векторов коэффициентов. </param>
        /// <param name="usePolyphase"> Использовать полифазное FFT? </param>
        /// <param name="isMirror"> Зеркальное отображение спектра? </param>
        /// <param name="fftObj"> Объект FFT, для которого вызывается функция. </param>
        /// <returns> Результат разбора выходных данных CFFT. </returns>
        public static CFFT_ExploreResult ComplexExplore(double[][] FFT_T,
                                                        bool usePolyphase, bool isMirror,
                                                        ExactFFT.CFFT_Object fftObj)
        {
            int plotRowsCount;
            CFFT_ExploreResult res;

            res = new CFFT_ExploreResult();

            if (FFT_T == null)
            {
                throw new Exception("ExactPlotter::ComplexExplore(): (FFT_T == null)");
            }

            // Считываем количество строк, которые имеет сонограмма...
            plotRowsCount = FFT_T.Length;

            // Подготавливаем выходные массивы...
            res.Mag = new double[plotRowsCount][];
            res.Arg = new double[plotRowsCount][];

            // Работаем по всем строкам сонограммы...
            Parallel.For(0, plotRowsCount, frame =>
            {
                // Количество гармоник равно размеру кадра FFT
                res.Mag[frame] = new double[fftObj.N];
                res.Arg[frame] = new double[fftObj.N];

                // Извлечение данных FFT из комплексной сонограммы (режим COMPLEX)
                ExactFFT.CFFT_ComplexExplore(FFT_T[frame],
                                             res.Mag[frame], res.Arg[frame],
                                             usePolyphase,
                                             isMirror,
                                             fftObj);
            });

            return(res);
        }
Пример #6
0
        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);
        }