在哪里可以找到免费、非常快速且可靠的 C# 中 FFT 实现?
那可以用在一个产品上吗?或者有什么限制吗?
做 AForge 的那个人做得相当不错,但这不是商业质量。从中学习很好,但你可以看出他也在学习,所以他有一些非常严重的错误,比如假设图像的大小而不是使用每个像素的正确位数。
我不是要打他,我尊重他学习所有这些并告诉我们如何去做。我认为他现在是博士,或者至少他即将成为博士,所以他真的很聪明,只是不是一个商业可用的图书馆。
在处理傅里叶变换和复杂图像/数字时,Math.Net 库有其自身的怪异之处。就像,如果我没记错的话,它会以人类可见的格式输出傅立叶变换,如果您想查看变换的图片,这对人类来说很好,但是当您期望数据处于特定状态时,它就不是很好了格式(正常格式)。我可能弄错了,但我只记得有一些奇怪之处,所以我实际上去了他们用于傅里叶东西的原始代码,它工作得更好。(ExocortexDSP v1.2 http://www.exocortex.org/dsp/)
在处理来自 FFT 的数据时,Math.net 还有一些我不喜欢的其他古怪之处,我不记得它是什么我只知道从 ExoCortex DSP 库中获得我想要的东西要容易得多。我不是数学家或工程师。对那些人来说,这可能很有意义。
所以!我使用从 Math.Net 所基于的 ExoCortex 提取的 FFT 代码,没有其他任何东西,而且效果很好。
最后,我知道它不是 C#,但我已经开始考虑使用 FFTW ( http://www.fftw.org/ )。这个人已经做了一个 C# 包装器,所以我打算检查一下,但还没有真正使用它。( http://www.sdss.jhu.edu/~tamas/bytes/fftwcsharp.html )
哦!我不知道你这样做是为了学校还是工作,但不管怎样,iTunes 大学的斯坦福教授都会提供一个很棒的免费系列讲座。
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 power-of-2-length-only C# FFT implementation。
我没有将它的性能与其他 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;
}
}
http://www.exocortex.org/dsp/是一个带有 FFT 算法的开源 C# 数学库。
这是另一个;Ooura FFT 的 C# 端口。它相当快。该软件包还包括重叠/添加卷积和一些其他 DSP 的东西,在 MIT 许可下。
https://github.com/hughpyle/inguz-DSPUtil/blob/master/Fourier.cs
一个老问题,但它仍然出现在谷歌搜索结果中......
可以在以下位置找到一个非常不受限制的 MIT 许可 C#/.NET 库,
https://www.codeproject.com/articles/1107480/dsplib-fft-dft-fourier-transform-library-for-net
这个库速度很快,因为它在多个内核上并行线程,并且非常完整并且可以使用。
Numerical Recipes 网站 (http://www.nr.com/) 有一个 FFT,如果您不介意输入的话。我正在开展一个项目,将 Labview 程序转换为 C# 2008、.NET 3.5 以获取数据和然后看频谱。不幸的是,Math.Net 使用了最新的 .NET 框架,所以我不能使用那个 FFT。我尝试了 Exocortex 之一 - 它有效,但结果与 Labview 结果相匹配,而且我不知道足够的 FFT 理论来了解导致问题的原因。所以我在数字食谱网站上尝试了 FFT,它奏效了!我还能够对 Labview 低旁瓣窗口进行编程(并且必须引入比例因子)。
您可以在他们的网站上以访客身份阅读数字食谱书的章节,但这本书非常有用,我强烈建议购买它。即使您最终使用 Math.NET FFT。
对于针对英特尔处理器调整的多线程实现,我会查看英特尔的 MKL 库。它不是免费的,但价格实惠(不到 100 美元)而且速度极快——但您需要通过 P/Invokes 将其称为 C dll。Exocortex 项目在 6 年前停止开发,所以如果这是一个重要项目,我会小心使用它。