我想在C#中实现希尔伯特变换。从this文章中我看到最快的FFT开源实现似乎是FFTW,所以我下载了这个例子并用它来学习如何使用fftw包装器来实现C#。
我有一个200,000点的电流信号,我用它进行测试。通过fft获得希尔伯特变换相对简单:
到目前为止,我已经完成了所有这些工作。唯一的问题是逆fft。我用fftw得不到与matlab相同的结果。
RealArray _input;
ComplexArray _fft;
void ComputeFFT()
{
_fft = new ComplexArray(_length / 2 + 1);
_input.Set(Data);
_plan = Plan.Create1(_length, _input, _fft, Options.Estimate);
_plan.Execute();
}
到目前为止,我只有一个只有正频率的fft。因此,我不需要将负频率乘以零:它们甚至不存在。使用以下代码,我可以恢复原始信号:
double[] ComputeIFFT(ComplexArray input)
{
double[] temp = new double[_length];
RealArray output = new RealArray(_length);
_plan = Plan.Create1(_length, input, output, Options.Estimate);
_plan.Execute();
temp = output.ToArray();
for (int i = 0; i < _length; ++i)
{
temp[i] /= _length;
}
return temp;
}
当我尝试从信号中获得复数逆时,问题出现了。
void ComputeHilbert()
{
double[] fft = FFT.ToArray();
double[] h = new double[_length / 2 + 1];
double[] temp = new double[_length * 2];
bool fftLengthIsOdd = (_length | 1) == 1;
h[0] = 1;
for (int i = 1; i < _length / 2; i++) h[i] = 2;
if (!fftLengthIsOdd) h[(_length / 2)] = 1;
for (int i = 0; i <= _length / 2; i++)
{
temp[2 * i] = fft[2*i] * h[i];
temp[2 * i + 1] = fft[2*i + 1] * h[i];
}
ComplexArray _tempHilbert = new ComplexArray(_length);
_tempHilbert.Set(temp);
_hilbert = ComputeIFFT(_tempHilbert);
_hilbertComputed = true;
}
重要的是要注意,当我在ToArray()
对象上应用ComplexArray
方法时,我得到一个double[]
的结果,其长度是原始对象的两倍数组,实部和虚部连续。对于包含&#34; 3 + 1i&#34;的ComplexArray
对象,我会得到带有[3,1]的双向量。
所以,在这一刻,我所拥有的是:
[DC Frequency, 2*positive frequencies, Nyquist Frequency, zeros]
如果我将这些数据导出到Matlab并计算IFFT,我会得到与其hilbert(信号)相同的结果。
但是,如果我尝试应用fftw提供的IFFT,我会从Nyquist Frequency到最终得到奇怪的值(也就是说,fftw的零点混乱)。
这是我用来执行此操作的ifft:
double[] ComputeIFFT(ComplexArray input)
{
double[] temp;
ComplexArray output = new ComplexArray(_length);
_plan = Plan.Create1(_length, input, output, Direction.Backward, Options.Estimate);
_plan.Execute();
temp = output.ToArray();
for (int i = 0; i < _length; ++i)
{
temp[i] /= _length;
}
return temp;
}
所以,总而言之,我的问题就是我用来计算ifft的方式。它似乎与零一起运行良好。或者也许Matlab能够理解它必须应用一些不同的方法,我应该手动完成,但我不知道如何。
非常感谢您的帮助,非常感谢!
答案 0 :(得分:0)
所以问题是ComputeIFFT功能。在for循环中,我正在做我&lt; _length,但temp数组的长度为2 * _length,因为它包含实数和虚数值。
这就是为什么我只有一半的价值正确。
正确的代码是:
double[] ComputeIFFT(ComplexArray input)
{
double[] temp;
ComplexArray output = new ComplexArray(_length);
_plan = Plan.Create1(_length, input, output, Direction.Backward, Options.Estimate);
_plan.Execute();
temp = output.ToArray();
for (int i = 0; i < temp.Length; ++i)
{
temp[i] /= _length;
}
return temp;
}
我希望这对于试图在C#中通过FFTW实现希尔伯特变换的人来说非常有用。