Я разложил некоторые данные временных рядов, используя собственную реализацию FFT. Конструктивно моя реализация FFT дает мне набор кос и синусоидальных волн, которые затем я могу суммировать для регенерации исходного сигнала. Это хорошо работает без проблем, поэтому я знаю, что извлеченные синусоидальные и cos-волны верны с точки зрения амплитуды, периода и фазы.
Используемые мной данные имеют 1024 выборки, что дает мне свойства 512 cos-волн и 512 синусоидальных волн (например, данные по амплитуде, фазе и периоду для каждой волны).
Чтобы сэкономить на хранении данных, я пытаюсь найти / понять математическое соотношение между амплитудами волн. Вместо того, чтобы сохранять каждую амплитуду для каждой синусоидальной и косинусоидальной волны, я хотел бы просто сохранить некоторые коэффициенты, которые позже я смогу использовать для перестройки амплитуд в коде.
БПФ Синусоидальные волны с амплитудами
Из приведенного выше изображения вы можете видеть, что существует набор коэффициентов кривой мощности, которые приблизительно соответствуют данным амплитуды, однако для моего случая использования это не достаточно точно.
Поскольку у меня есть все исходные данные вместе со сгенерированными свойствами каждой волны, есть ли простая формула, которую я могу использовать, или преобразование, которое я могу выполнить, чтобы сгенерировать амплитуды в коде после того, как я выполнил БПФ? Я знаю, что амплитуды связаны с действительными и мнимыми значениями, однако я не могу хранить все действительные и мнимые значения из-за требований к пространству.
В качестве примера того, как я сохраняю эту проблему для данных периода, Я обнаружил, что период каждой волны просто Math.Power (waveIndex, -1). Поэтому для периодов волн мне не нужно хранить данные, я могу просто восстановить их в коде.
В настоящее время я не могу найти взаимосвязь между амплитудами в синусоидальной волне или даже взаимосвязь между cos и синусоидальными амплитудами, однако теория и математика, лежащие в основе БПФ, мне недоступны, поэтому я надеюсь, что существует простая формула или Концепция, которую я могу реализовать.
После ответов, которые я добавил нижеприведенный код, который я использую для получения значений синусоидальной и косоволны, этот фрагмент кода может помочь тем, кто отвечает.
internal void GetSineAndCosWavesBasic(double[] outReal, double[] outImag, int numWaves, out double[,] sineValues, out double[,] cosValues)
{
// the real and imag values from Cooley-Tukey decimation-in-time radix-2 FFT are passed in
// and we want to generate the cos and sine values for each sample for each wave
var length = outReal.Length;
var lengthDouble = (double)length;
var halfLength = lengthDouble / 2.0;
sineValues = new double[numWaves, length];
cosValues = new double[numWaves, length];
var Pi2 = 2 * Math.PI;
for (var waveIdx = 0; waveIdx < numWaves; waveIdx++)
{
for (var sampleIdx = 0; sampleIdx < length; sampleIdx++)
{
// first value case and middle value case
var reX = outReal[waveIdx] / halfLength;
if (sampleIdx == 0)
{
reX = outReal[waveIdx] / lengthDouble;
}
else if (sampleIdx == halfLength)
{
reX = outReal[waveIdx] / lengthDouble;
}
// precompute the value that gets sine/cos applied
var tmp = (Pi2 * waveIdx * sampleIdx) / lengthDouble;
// get the instant cos and sine values
var valueCos = Math.Cos(tmp) * reX;
var valueSin = Math.Sin(tmp) * (-outImag[waveIdx] / halfLength);
// update the sine and cos values for this wave for this sample
cosValues[waveIdx, sampleIdx] = valueCos;
sineValues[waveIdx, sampleIdx] = valueSin;
}
}
}
И ниже показано, как я получаю значения амплитуды и фазы, хотя в настоящее время я нигде их не использую.
internal void CalculateMagAndPhaseBasic(double[] outReal, double[] outImag, out double[] mag, out double[] phase)
{
// the real and imag values from Cooley-Tukey decimation-in-time radix-2 FFT are passed in
// and we want to generate the magnitude and phase values
var length = outReal.Length;
mag = new double[(length / 2) +1];
phase = new double[(length / 2) + 1];
for (var i = 0; i <= length / 2; i++)
{
mag[i] = Math.Pow((outReal[i] * outReal[i]) + (outImag[i] * outImag[i]), 0.5);
phase[i] = Math.Atan2(outImag[i], outReal[i]);
}
}