RealFourier.cs
using System;
using System.Collections.Generic;
using System.Text;
namespace FFT
{
public class RealFourier
{
private int size;
private double[] real;
private double[] img;
public RealFourier(double[] data)
{
if (data == null)
return;
size = data.Length;
real = new double[data.Length / 2 + 1];
img = new double[data.Length / 2 + 1];
if (data.Length == 1)
{
real[0] = data[0];
img[0] = 0.0;
}
else if (data.Length == 2)
{
double scale = 1 / Math.Sqrt(2);
real[0] = (data[0] + data[1]) * scale;
real[1] = (data[0] - data[1]) * scale;
img[0] = 0.0;
img[1] = 0.0;
}
else
{
RealFourier even = new RealFourier(data.Even());
RealFourier odd = new RealFourier(data.Odd());
double PI = Math.Acos(-1);
double alpha = -2.0 * PI / data.Length;
double scale = 1 / Math.Sqrt(2);
for (int k = 0; k <= data.Length / 2; k++)
{
double cos = Math.Cos( alpha * k);
double sin = Math.Sin( alpha * k);
real[k] = scale* (even.R(k) + cos * odd.R(k) - sin * odd.Y(k));
img[k] = scale* (even.Y(k) + sin * odd.R(k) + cos * odd.Y(k));
}
}
}
public int Size { get { return size; } }
public int Count { get { return size / 2 + 1; } }
public double[] Real { get { return real; } }
public double[] Img { get { return img; } }
public double Power(int index)
{
double r = R(index);
double y = Y(index);
return r * r + y * y;
}
public double Module(int index)
{
return Math.Sqrt(Power(index));
}
public double R(int index)
{
index %= size;
if (index <= size / 2)
return real[index];
return real[size - index];
}
public double Y(int index)
{
index %= size;
if (index <= size / 2)
return img[index];
return -img[size - index];
}
public double PeakFreq(double freq)
{
int pos = 0;
double max = Module(0);
for (int index = 1; index <= size / 2; index++)
{
double m = Module(index) + Module(2 * index) + Module(3 * index);
if (max < m)
{
max = m;
pos = index;
}
}
if (pos == 0 || pos == size / 2)
return F(pos, freq);
double yMinus = Math.Log(Module(pos - 1));
double yZero = Math.Log(Module(pos));
double yPlus = Math.Log(Module(pos + 1));
double delta = (yMinus - yPlus) / (yMinus + yPlus - 2 * yZero);
return freq * (pos + delta) / (double)size;
}
public double F(int index, double freq)
{
index %= size;
if (index > size / 2)
index = size - index;
return freq * index / (double)size;
}
private void Process(double[] data)
{
double PI = Math.Acos(-1);
double alpha = -2.0 * PI / data.Length;
double sinAlpha = Math.Sin(alpha);
double cosAlpha = Math.Cos(alpha);
double scale = 1.0 / Math.Sqrt(data.Length);
real.Set(0.0);
img.Set(0.0);
double sinKalpha = 0.0;
double cosKalpha = 1.0;
for (int k = 0; k <= data.Length / 2; k++)
{
double sin = 0.0;
double cos = 1.0;
for (int index = 0; index < data.Length; index++)
{
real[k] += data[index] * cos;
img[k] += data[index] * sin;
IncrementAlpha(ref sin, ref cos, sinKalpha, cosKalpha);
}
IncrementAlpha(ref sinKalpha, ref cosKalpha, sinAlpha, cosAlpha);
}
real.Scale(scale);
img.Scale(scale);
}
private void IncrementAlpha(ref double sin, ref double cos, double sinAlpha, double cosAlpha)
{
double sinTmp = sin;
double cosTmp = cos;
sin = sinTmp * cosAlpha + cosTmp * sinAlpha;
cos = cosTmp * cosAlpha - sinTmp * sinAlpha;
}
}
}