我已经使用自定义的FFT实现分解了一些时间序列数据。通过设计,我的FFT实现提供了一组cos和正弦波,然后我可以将它们相加,以重新生成原始信号。这工作得很好,没有问题,所以我知道提取的正弦波和cos波在振幅、周期和相位方面是正确的。
我使用的数据有1024个样本,它给出了512个cos波和512个正弦波的属性(例如,每个波的振幅、相位和周期数据)。
为了节省数据存储,我试图找到/理解波的振幅之间的数学关系。而不是必须保存每个正弦和cos波的每个振幅,我想简单地保存一些系数,我可以用来在代码中重建振幅。
FFT Sine Waves with Amplitudes
从上图可以看出,有一组功率曲线系数大致符合振幅数据,但对于我的用例来说,这是不够准确的。
由于我有所有的源数据以及每个波的生成属性,在执行完FFT之后,是否有可以使用的简单公式或可以执行的转换来生成代码中的振幅?我知道振幅与实值和虚值有关,但是由于空间要求,我不能存储所有的实值和虚值。
作为我如何将这个问题保存到周期数据的示例,我发现每个波的周期是简单的Math.Power(waveIndex,-1)。因此,对于波形周期,我不需要存储数据,只需在代码中重新生成即可。
我目前找不到正弦波中振幅之间的关系,甚至找不到cos和正弦振幅之间的关系,但是FFT背后的理论和数学超出了我的能力范围,所以我希望有一个简单的公式或概念可以实现。
在回复之后,我添加了下面的代码,用于获取正弦和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]);
}
}发布于 2020-03-06 02:13:56
实际上,快速傅立叶变换只返回复系数S(w)=a+jb
对于N点快速傅立叶变换,abs(S(w)) * 2/N将是(接近)频率为w的正弦分量的幅度。
这假设正弦分量的频率接近fft bin的中心,否则功率将在两个相邻bin之间“分割”。
你感兴趣的频率是通过所有的fft窗口呈现的。
发布于 2020-03-06 02:23:52
FFT的输出与输入具有相同的自由度。没有简单的公式(除了FFT本身)可以将FFT结果彼此关联,因为如果任何FFT输入发生变化,所有FFT输出都会发生变化。
每个FFT复数bin结果的正弦和余弦之间的关系与该频率( bin中心)的正弦输入分量的相位有关,相对于起始和结束循环。如果相位改变,正弦和余弦分量也会改变。请参阅: atan2()
https://stackoverflow.com/questions/60551270
复制相似问题