Math.net 在处理来自 FFT 的数据时还有其他一些我不喜欢的瑕疵。我不记得那是什么了,我只知道使用 ExoCortex DSP 库更容易获得我想要的结果。虽然我不是数学家或工程师,但对于这些人来说,可能很合理。
因此!我使用从 ExoCortex 获取的 FFT 代码,Math.Net 就是基于它的,没有其他东西,它运行得很好。
最后,我知道这不是 C#,但我已经开始研究使用 FFTW (http://www.fftw.org/)。这位大佬已经制作了一个 C# 包装器,所以我打算看看它,但实际上还没有使用过(http://www.sdss.jhu.edu/~tamas/bytes/fftwcsharp.html)。
哦!我不知道你是为了学校还是工作做这个,但无论如何,斯坦福大学的一位教授在 iTunes University 上提供了一系列绝佳的免费讲座。
https://podcasts.apple.com/us/podcast/the-fourier-transforms-and-its-applications/id384232849
AForge.net 是一个带有快速傅里叶变换支持的免费(开源)库。(使用情况请参见 Sources/Imaging/ComplexImage.cs,实现方式请参见 Sources/Math/FourierTransform.cs)
Math.NET的Iridium库提供了一个快速、定期更新的数学相关函数集合,包括FFT算法。它基于LGPL许可证,因此您可以在商业产品中免费使用。
我看到这是一个旧帖子,但是无论如何,这是一份我在2010年编写的免费(MIT许可证)1-D 2的幂长度的C# FFT实现。
我还没有将其性能与其他C# FFT实现进行比较。我主要编写它是为了比较Flash/ActionScript和Silverlight/C#的性能。后者更快,至少在数字处理方面。
/**
* Performs an in-place complex FFT.
*
* Released under the MIT License
*
* Copyright (c) 2010 Gerald T. Beauregard
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
public class FFT2
{
// Element for linked list in which we store the
// input/output data. We use a linked list because
// for sequential access it's faster than array index.
class FFTElement
{
public double re = 0.0; // Real component
public double im = 0.0; // Imaginary component
public FFTElement next; // Next element in linked list
public uint revTgt; // Target position post bit-reversal
}
private uint m_logN = 0; // log2 of FFT size
private uint m_N = 0; // FFT size
private FFTElement[] m_X; // Vector of linked list elements
/**
*
*/
public FFT2()
{
}
/**
* Initialize class to perform FFT of specified size.
*
* @param logN Log2 of FFT length. e.g. for 512 pt FFT, logN = 9.
*/
public void init(
uint logN )
{
m_logN = logN;
m_N = (uint)(1 << (int)m_logN);
// Allocate elements for linked list of complex numbers.
m_X = new FFTElement[m_N];
for (uint k = 0; k < m_N; k++)
m_X[k] = new FFTElement();
// Set up "next" pointers.
for (uint k = 0; k < m_N-1; k++)
m_X[k].next = m_X[k+1];
// Specify target for bit reversal re-ordering.
for (uint k = 0; k < m_N; k++ )
m_X[k].revTgt = BitReverse(k,logN);
}
/**
* Performs in-place complex FFT.
*
* @param xRe Real part of input/output
* @param xIm Imaginary part of input/output
* @param inverse If true, do an inverse FFT
*/
public void run(
double[] xRe,
double[] xIm,
bool inverse = false )
{
uint numFlies = m_N >> 1; // Number of butterflies per sub-FFT
uint span = m_N >> 1; // Width of the butterfly
uint spacing = m_N; // Distance between start of sub-FFTs
uint wIndexStep = 1; // Increment for twiddle table index
// Copy data into linked complex number objects
// If it's an IFFT, we divide by N while we're at it
FFTElement x = m_X[0];
uint k = 0;
double scale = inverse ? 1.0/m_N : 1.0;
while (x != null)
{
x.re = scale*xRe[k];
x.im = scale*xIm[k];
x = x.next;
k++;
}
// For each stage of the FFT
for (uint stage = 0; stage < m_logN; stage++)
{
// Compute a multiplier factor for the "twiddle factors".
// The twiddle factors are complex unit vectors spaced at
// regular angular intervals. The angle by which the twiddle
// factor advances depends on the FFT stage. In many FFT
// implementations the twiddle factors are cached, but because
// array lookup is relatively slow in C#, it's just
// as fast to compute them on the fly.
double wAngleInc = wIndexStep * 2.0*Math.PI/m_N;
if (inverse == false)
wAngleInc *= -1;
double wMulRe = Math.Cos(wAngleInc);
double wMulIm = Math.Sin(wAngleInc);
for (uint start = 0; start < m_N; start += spacing)
{
FFTElement xTop = m_X[start];
FFTElement xBot = m_X[start+span];
double wRe = 1.0;
double wIm = 0.0;
// For each butterfly in this stage
for (uint flyCount = 0; flyCount < numFlies; ++flyCount)
{
// Get the top & bottom values
double xTopRe = xTop.re;
double xTopIm = xTop.im;
double xBotRe = xBot.re;
double xBotIm = xBot.im;
// Top branch of butterfly has addition
xTop.re = xTopRe + xBotRe;
xTop.im = xTopIm + xBotIm;
// Bottom branch of butterly has subtraction,
// followed by multiplication by twiddle factor
xBotRe = xTopRe - xBotRe;
xBotIm = xTopIm - xBotIm;
xBot.re = xBotRe*wRe - xBotIm*wIm;
xBot.im = xBotRe*wIm + xBotIm*wRe;
// Advance butterfly to next top & bottom positions
xTop = xTop.next;
xBot = xBot.next;
// Update the twiddle factor, via complex multiply
// by unit vector with the appropriate angle
// (wRe + j wIm) = (wRe + j wIm) x (wMulRe + j wMulIm)
double tRe = wRe;
wRe = wRe*wMulRe - wIm*wMulIm;
wIm = tRe*wMulIm + wIm*wMulRe;
}
}
numFlies >>= 1; // Divide by 2 by right shift
span >>= 1;
spacing >>= 1;
wIndexStep <<= 1; // Multiply by 2 by left shift
}
// The algorithm leaves the result in a scrambled order.
// Unscramble while copying values from the complex
// linked list elements back to the input/output vectors.
x = m_X[0];
while (x != null)
{
uint target = x.revTgt;
xRe[target] = x.re;
xIm[target] = x.im;
x = x.next;
}
}
/**
* Do bit reversal of specified number of places of an int
* For example, 1101 bit-reversed is 1011
*
* @param x Number to be bit-reverse.
* @param numBits Number of bits in the number.
*/
private uint BitReverse(
uint x,
uint numBits)
{
uint y = 0;
for (uint i = 0; i < numBits; i++)
{
y <<= 1;
y |= x & 0x0001;
x >>= 1;
}
return y;
}
虽然这是一个老问题,但它仍然出现在谷歌搜索结果中...
你可以在下面的链接找到一个非常宽松的MIT许可证的C# / .NET库:
https://www.codeproject.com/articles/1107480/dsplib-fft-dft-fourier-transform-library-for-net
该库具有快速的并行线程和多核心处理能力,且已经非常完备并可直接使用。
如果要针对英特尔处理器进行多线程实现,我建议使用英特尔的MKL库。虽然它不是免费的,但价格实惠(不到100美元),速度非常快 - 但您需要通过P/Invokes调用其C dll。 Exocortex项目在6年前停止了开发,因此如果这是一个重要的项目,我建议小心使用。