klhztrader/KLHZ.Trader.Core.Tests/FFTTests.cs

245 lines
9.5 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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<float>();
var da2 = new List<float>();
var dates = new List<DateTime>();
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<float>();
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<decimal>();
var dates = new List<DateTime>();
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));
}
}
}