using KLHZ.Trader.Core.Math.Declisions.Utils; using MathNet.Numerics; using MathNet.Numerics.IntegralTransforms; namespace KLHZ.Trader.Core.Tests { public class FFTTests { [Test] public static void Test1() { // Размер сигнала int N = 1024; // Генерируем случайный сигнал var signal = new float[N]; Random random = new Random(); for (int i = 0; i < N; i++) { signal[i] = (float)System.Math.Cos(0.01 * i);// (float)random.NextDouble() * 2 - 1; } // нормированный случайный сигнал [-1, 1] // Выполняем прямое преобразование Фурье Complex32[] fftResult = signal.Select(s => new Complex32(s, 0)).ToArray(); Fourier.Forward(fftResult); // Выделяем первые 10 гармоник (включая нулевую) var firstTenHarmonics = fftResult.AsSpan(0, 10).ToArray(); //Копируем первые 11 элементов (нулевая и первые 10) // Вычисляем амплитуды и фазы гармоник double[] amplitudes = new double[firstTenHarmonics.Length]; double[] phases = new double[firstTenHarmonics.Length]; for (int k = 0; k < firstTenHarmonics.Length; k++) { amplitudes[k] = firstTenHarmonics[k].Magnitude / N; phases[k] = firstTenHarmonics[k].Phase; } // Последний индекс сигнала int lastPointIndex = N - 1; // Реконструкция последней точки сигнала double reconstructedLastPoint = 0; double reconstructedFirstPoint = 0; for (int k = 1; k < firstTenHarmonics.Length; k++) // начинаем с первой гармоники { reconstructedLastPoint += amplitudes[k] * System.Math.Cos((2 * System.Math.PI * k * lastPointIndex) / N + phases[k]); } for (int k = 1; k < firstTenHarmonics.Length; k++) // начинаем с первой гармоники { reconstructedFirstPoint += amplitudes[k] * System.Math.Cos((2 * System.Math.PI * k * 1) / N + phases[k]); } Console.WriteLine($"Реконструированное значение последней точки: {reconstructedLastPoint}"); } public static Complex32[] InverseFourierManual(Complex32[] spectrum) { int N = spectrum.Length; Complex32[] result = new Complex32[N]; for (int t = 0; t < N; t++) { Complex32 sum = Complex32.Zero; for (int k = 0; k < N; k++) { double angle = 2 * System.Math.PI * k * t / N; sum += spectrum[k] * Complex32.Exp(new Complex32(0, (float)angle)); } result[t] = sum / N; } return result; } [Test] public static void Test() { var da = new List(); var da2 = new List(); var dates = new List(); var dt = DateTime.UtcNow; var dt1 = dt; var dt2 = dt.AddSeconds(3600); var T1 = TimeSpan.FromMinutes(10); var T2 = TimeSpan.FromMinutes(7); var T3 = TimeSpan.FromMinutes(30); while (dt < dt2) { dt = dt.AddSeconds(1); var phase = (dt - dt1).TotalSeconds / T1.TotalSeconds * 2 * System.Math.PI; var phase2 = (dt - dt1).TotalSeconds / T2.TotalSeconds * 2 * System.Math.PI; var phase3 = (dt - dt1).TotalSeconds / T3.TotalSeconds * 2 * System.Math.PI; da.Add((float)System.Math.Cos(phase) + (float)System.Math.Sin(phase2) + (float)System.Math.Sin(phase3)); dates.Add(dt); } var start = da.ToArray(); var harms = FFT.GetHarmonics(da.Select(d => (decimal)d).ToArray(), dates.Last() - dates.First(), TimeSpan.FromSeconds(7), TimeSpan.FromSeconds(70)); var damax = da.Max(); var damin = da.Min(); for (int i = 0; i < da.Count; i++) { da[i] = da[i] / (damax - damin); } foreach (var d in dates) { da2.Add((float)FFT.CalcAmplitude(harms, dates.First(), d)); } var da2max = da2.Max(); var da2min = da2.Min(); for (int i = 0; i < da2.Count; i++) { da2[i] = da2[i] / (da2max - da2min); } damax = da.Max(); damin = da.Min(); da2max = da2.Max(); da2min = da2.Min(); //var tem = arrv.Select(a => Complex32.Abs(a)).ToArray(); //var s = tem.Sum(); //Fourier.Inverse(arrv); //var res = arrv.Select(a => a.Real).ToArray(); var diffs = new List(); for (int i = 0; i < da2.Count; i++) { var diff = (da2[i] - da[i]) / (damax - damin); diffs.Add(diff); } } [Test] public static void CalcHarmonyPeriodTest1() { var period1 = FFT.CaclHarmonycPeriod(TimeSpan.FromHours(1), 1000, 1); var period2 = FFT.CaclHarmonycPeriod(TimeSpan.FromHours(1), 1000, 2); var period3 = FFT.CaclHarmonycPeriod(TimeSpan.FromHours(1), 1000, 3); var period4 = FFT.CaclHarmonycPeriod(TimeSpan.FromHours(1), 1000, 4); } [Test] public static void CalcPhaseRangeForMax_Sin() { var res = FFT.CalcPhaseRangeFoxMax(1, 0, 0, 0.001); Assert.IsTrue(res.min < System.Math.PI / 2); Assert.IsTrue(res.min > System.Math.PI / 2 * 0.9); Assert.IsTrue(res.max > System.Math.PI / 2); Assert.IsTrue(res.max < System.Math.PI / 2 * 1.1); } [Test] public static void CalcPhaseRangeForMin_Sin() { var res = FFT.CalcPhaseRangeFoxMin(1, 0, 0, 0.001); Assert.IsTrue(res.min < 3 * System.Math.PI / 2); Assert.IsTrue(res.min > 3 * System.Math.PI / 2 * 0.9); Assert.IsTrue(res.max > 3 * System.Math.PI / 2); Assert.IsTrue(res.max < 3 * System.Math.PI / 2 * 1.1); } [Test] public static void CalcPhaseRangeForMax_MinusSin() { var res = FFT.CalcPhaseRangeFoxMax(-1, 0, 0, 0.001); Assert.IsTrue(res.min < 3 * System.Math.PI / 2); Assert.IsTrue(res.min > 3 * System.Math.PI / 2 * 0.9); Assert.IsTrue(res.max > 3 * System.Math.PI / 2); Assert.IsTrue(res.max < 3 * System.Math.PI / 2 * 1.1); } [Test] public static void CalcPhaseRangeForMax_Cos() { var res = FFT.CalcPhaseRangeFoxMax(0, 1, 0, 0.001); Assert.IsTrue(res.min < System.Math.PI * 2); Assert.IsTrue(res.min > System.Math.PI * 2 * 0.9); Assert.IsTrue(res.max > 0); Assert.IsTrue(res.max < System.Math.PI * 2 * 0.1); } [Test] public static void CalcPhaseRangeForMin_Cos() { var res = FFT.CalcPhaseRangeFoxMin(0, 1, 0, 0.001); Assert.IsTrue(res.min < System.Math.PI); Assert.IsTrue(res.min > System.Math.PI * 0.9); Assert.IsTrue(res.max > System.Math.PI); Assert.IsTrue(res.max < System.Math.PI * 1.1); } [Test] public static void CalcPhaseRangeForMax_CosWithShift() { var res = FFT.CalcPhaseRangeFoxMax(0, 1, System.Math.PI / 2, 0.001); Assert.IsTrue(res.min < 3 * System.Math.PI / 2); Assert.IsTrue(res.min > 3 * System.Math.PI / 2 * 0.9); Assert.IsTrue(res.max > 3 * System.Math.PI / 2); Assert.IsTrue(res.max < 3 * System.Math.PI / 2 * 1.1); } [Test] public static void CalcPhaseRangeForMax_CosWithShift2() { var res = FFT.CalcPhaseRangeFoxMax(0, 1, -System.Math.PI / 2, 0.001); Assert.IsTrue(res.min < System.Math.PI / 2); Assert.IsTrue(res.min > System.Math.PI / 2 * 0.9); Assert.IsTrue(res.max > System.Math.PI / 2); Assert.IsTrue(res.max < System.Math.PI / 2 * 1.1); } [Test] public static void TrimValues_Test1() { var da = new List(); var dates = new List(); var dt = DateTime.UtcNow; var dt1 = dt; var dt2 = dt.AddSeconds(3600); var i = 0; while (dt < dt2) { da.Add(i); dates.Add(dt); dt = dt.AddSeconds(1); i++; } var res = FFT.TrimValues(dates.ToArray(), da.ToArray(), TimeSpan.FromSeconds(30)); var res2 = FFT.TrimValues(dates.ToArray(), da.ToArray(), TimeSpan.FromSeconds(4011)); } } }