求FFT算法例子或控件,对WAV声音频率进行抽取处理(300分)

  • 主题发起人 主题发起人 skadon
  • 开始时间 开始时间
S

skadon

Unregistered / Unconfirmed
GUEST, unregistred user!
哪位朋友有此类资料,请不吝指教。
我想实现声音的EQ功能,要求31段均衡,使用过MMTOOLS,不准确。COOL EDIT 1.0的31段均衡很准确,希望达到它的水平。
1、对WAV声音数据进行从16Hz--20kHz的频率抽取。
2、按31段EQ均衡进行调节。
3、合成数据,输出WAV文件。

以上1、3步需要FFT算法。我找资料,了解一点点FFT算法,不明白怎么按频率抽取。请各位指教,成功后可以公开代码。
已在大富翁全文检索,没有有效资料。分不够可以加到1000。
 
虽然是学电子的...天天用FFT 但还是不太会

找了几个资料 算作支持 也不知道有没有用

{
ト
Area: U-PASCAL |61 トトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトト
Msg#: 5727 Date: 07-05-94 08:14
From: Bschor@vms.cis.pitt.edu Read: Yes Replied: No
To: All Mark:
Subj: FFT Algorithm in Pascal
トトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトトト
From: bschor@vms.cis.pitt.edu

Over the past several weeks, there have been questions about the Fast
Fourier Transform, including requests for a version of the algorithm. The
following is one such implementation, optimized for clarity (??) at the
possible expense of a few percentage points in speed (it's pretty darn
fast). It is written in "vanilla" Pascal, so it should work with all
variants of the language.

Note that buried in the comments is a reasonable reference for the
algorithm.
}


PROGRAM fft (input, output);

{****************************************}
{ }
{ Bob Schor }
{ Eye and Ear Institute }
{ 203 Lothrop Street }
{ Pittsburgh, PA 15213 }
{ }
{****************************************}

{ test routine for FFT in Pascal -- includes real and complex }

{ Version 1.6 -- first incarnation }
{ Version 10.7 -- upgrade, allow in-place computation of coefficients }
{ Version 14.6 -- comments added for didactic purposes }

CONST
version = 'FFT Version 14.6';

CONST
maxarraysize = 128;
halfmaxsize = 64;
maxfreqsize = 63;
TYPE
dataindextype = 1 .. maxarraysize;
cmpxindextype = 1 .. halfmaxsize;
freqindextype = 1 .. maxfreqsize;
complex = RECORD
realpart, imagpart : real
end;

dataarraytype = RECORD
CASE (r, c) OF
r : (rp : ARRAY [dataindextype] OF real);
c : (cp : ARRAY [cmpxindextype] OF complex)
end;

cstermtype = RECORD
cosineterm, sineterm : real
end;

fouriertype = RECORD
dcterm : real;
noiseterm : real;
freqterms : ARRAY [freqindextype] OF cstermtype
end;

mixedtype = RECORD
CASE (dtype, ctype) OF
dtype : (dataslot : dataarraytype);
ctype : (coefslot : fouriertype)
end;


CONST
twopi = 6.2831853;
VAR
data : dataarraytype;
didx : dataindextype;
fidx : freqindextype;
coefficients : fouriertype;
mixed : mixedtype;

{ A note on declarations, above. Pascaldo
es not have a base type of
"complex", but it is fairly simple, given the strong typing in the
language, to define such a type. One needs to write procedures (see
below) that implement the common arithmetic operators. Functions
would be even better, from a logical standpoint, but the language
standarddo
es not permit returning a record type from a function.
. The FFT, strictly speaking, is a technique for transforming a
complex array of points-in-time into a complex array of points-in-
Fourier space (complex numbers that represent the gain and phase of
the response at discrete frequencies). One typically has data,
representing samples taken at some fixed sampling rate, for which
one wants the Fourier transform, to compute a power spectrum, for
example. Such data, of course, are "real" quantities. One could
take these N points, make them the real part of a complex array of
size N (setting the imaginary part to zero), and take the FFT.
However, in the interest of speed (the first F of FFT means "fast",
after all), one can alsodo
a trick where the N "real" points are
identified with the real, imaginary, real, imaginary, etc. points of
a complex array of size N/2. The FFT now takes about half the time,
and one needs todo
some final twiddling to obtain the sine/cosine
coefficients of the size N real array from the coefficients of the
size N/2 complex array.
. To clarify the dual interpretation of the data array as either
N reals or N/2 complex points, the tagged type "dataarraytype" was
defined. On input, it represents the complex data;
on output from the
complex FFT, it represents the complex Fourier coefficients. A final
transformation on these complex coefficients can convert them into a
series of real sine/cosine terms;
for this purpose, the tagged type
"mixed" was defined for the real FFT.
. Finally, note that this, and most, FFT routines get their
speed when the number of points is a power of 2. This is because
the speed comes from a divide-and-conquer approach -- todo
an FFT
of N points,do
two FFTs of N/2 points and combine the results. }


PROCEDURE fftofreal (VAR mixed : mixedtype;
realpoints : integer);

{ This routine performs a forward Fourier transform of an array
"mixed", which on input is assumed to consist of "realpoints" data
points and on output consists of a set of Fourier coefficients (a
DC term, (N/2 - 1) sine and cosine terms, and a residual "noise"
term). }

CONST
twopi = 6.2831853;
VAR
index, minusindex : freqindextype;
temp1, temp2, temp3, w : complex;
baseangle : real;

{ The following procedures implement complex arithmetic -- }

PROCEDURE cadd (a, b : complex;
VAR c : complex);

{ c := a + b }

begin
{ cadd }
WITH cdo

begin

realpart := a.realpart + b.realpart;
imagpart := a.imagpart + b.imagpart
END
end;


PROCEDURE csubtract (a, b : complex;
VAR c : complex);

{ c := a - b }

begin
{ csubtract }
WITH cdo

begin

realpart := a.realpart - b.realpart;
imagpart := a.imagpart - b.imagpart
END
end;


PROCEDURE cmultiply (a, b : complex;
VAR c : complex);

{ c := a * b }

begin
{ cmultiply }
WITH cdo

begin

realpart := a.realpart*b.realpart - a.imagpart*b.imagpart;
imagpart := a.realpart*b.imagpart + b.realpart*a.imagpart
END
end;


PROCEDURE conjugate (a : complex;
VAR b : complex);

{ b := a* }

begin
{ conjugate }
WITH bdo

begin

realpart := a.realpart;
imagpart := -a.imagpart
END
end;


PROCEDURE forwardfft (VAR data : dataarraytype;
complexpoints : integer);


{ The basic FFT is a recursive routine that basically works as
follows:
1) The FFT is a linear operator, so the FFT of a sum is simply
. the sum of the FFTs of each addend.

2) The FFT of a time series shifted in time is the FFT of the
. unshifted series adjusted by a twiddle factor which looks
. like a (complex) root of 1 (an nth root of unity).
3) Consider N points, equally spaced in time, for which you
. want an FFT. Start by splitting the series into odd and
. even samples, giving you two series with N/2 points,
. equally spaced, but with the second series delayed in time
. by one sample. Take the FFT of each series. Using property
. 2), adjust the FFT of the second series for the time delay.
. Now using property 1), since the original N points is simply
. the sum of the two N/2 series, the FFT we want is simply the
. sum of the FFTs of the two sub-series (with the adjustment
. in the second for the time delay).
4) This is essentially a recursive definition. Todo
an N-point
. FFT,do
two N/2 point FFTs and combine the answers. All we
. need to stop the recursion is to know how todo
a 2-point
. FFT: if a and b are the two (complex) input points, the
. two-point FFT equations are A := a+b;
B := a-b.
5) The FFT is rarely coded in its fully-recursive form. It
. turns out to be fairly simple to "unroll" the recursion and
. reorder it a bit, which simplifies the computation of the
. roots-of-unity complex twiddle factors. The only drawback
. is that the output array ends up scrambled -- if the array
. indices are represented as going from 0 to M-1, then
if one
. represents the array index as a binary number, one needs to
. bit-reverse the number to get the proper place in the array.
. Thus, the next step is to swap values by bit-reversing the
. indices.
6) There are numerous references on the FFT. A reasonable one
. is "Numerical Recipes" by Press et al., Cambridge University
. Press, which I believe exists in several language flavors. }

CONST
twopi = 6.2831853;

PROCEDUREdo
complextransform;

VAR
partitionsize, halfsize, offset,
lowindex, highindex : dataindextype;
baseangle, angle : real;
bits : integer;
w, temp : complex;

begin
{do
complextransform }
partitionsize := complexpoints;
WITH datado

REPEAT
halfsize := partitionsize DIV 2;
baseangle := twopi/partitionsize;
FOR offset := 1 TO halfsizedo

begin

angle := baseangle * pred(offset);
w.realpart := cos(angle);
w.imagpart := -sin(angle);
lowindex := offset;
REPEAT
highindex := lowindex + halfsize;
csubtract (cp[lowindex], cp[highindex], temp);
cadd (cp[lowindex], cp[highindex], cp[lowindex]);
cmultiply (temp, w, cp[highindex]);
lowindex := lowindex + partitionsize
UNTIL lowindex >= complexpoints
end;

partitionsize := partitionsize DIV 2
UNTIL partitionsize = 1
end;


PROCEDURE shufflecoefficients;

VAR
lowindex, highindex : dataindextype;
bits : integer;

FUNCTION log2 (index : integer) : integer;

{ Recursive routine, where "index" is assumed a power of 2.
Note the routine will fail (by endless recursion) if
"index" <= 0. }

begin
{ log2 }
IF index = 1
then
log2 := 0
else
log2 := succ(log2(index DIV 2))
end;


FUNCTION bitreversal (index, bits : integer) : integer;

{ Takes an index, in the range 1 .. 2**bits, and computes a
bit-reversed index in the same range. It first undoes the
offset of 1, bit-reverses the "bits"-bit binary number,
then
redoes the offset. Thus if bits = 4, the range is
1 .. 16, and bitreversal (1, 4) = 9,
bitreversal (16, 4) = 16, etc. }

FUNCTION reverse (bits, stib, bitsleft : integer) : integer;

{ Recursive bit-reversing function, transforms "bits" into
bit-reversed "stib. It's pretty easy to convert this to
an iterative form, but I think the recursive form is
easier to understand, and should entail a trivial penalty
in speed (in the overall algorithm). }

begin
{ reverse }
IF bitsleft = 0
then
reverse := stib
else

IF odd (bits)
then
reverse := reverse (bits DIV 2, succ (stib * 2),
pred (bitsleft))
else
reverse := reverse (bits DIV 2, stib * 2,
pred (bitsleft))
end;


begin
{ bitreversal }
bitreversal := succ (reverse (pred(index), 0, bits))
end;


PROCEDURE swap (VAR a, b : complex);

VAR
temp : complex;

begin
{ swap }
temp := a;
a := b;
b := temp
end;


begin
{ shufflecoefficients }
bits := log2 (complexpoints);
WITH datado

FOR lowindex := 1 TO complexpointsdo

begin

highindex := bitreversal(lowindex, bits);
IF highindex > lowindex
then
swap (cp[lowindex], cp[highindex])
END
end;


PROCEDURE dividebyn;

{ This procedure is needed to get FFT to scale correctly. }

VAR
index : dataindextype;

begin
{ dividebyn }
WITH datado

FOR index := 1 TO complexpointsdo

WITH cp[index]do

begin

realpart := realpart/complexpoints;
imagpart := imagpart/complexpoints

END
end;


begin
{ forwardfft }
do
complextransform;
shufflecoefficients;
dividebyn
end;


{ Note that the data slots and coefficient slots in the mixed
data type share storage. From the first complex coefficient,
we can derive the DC and noise term;
from pairs of the remaining
coefficients, we can derive pairs of sine/cosine terms. }


begin
{ fftofreal }
forwardfft (mixed.dataslot, realpoints DIV 2);
temp1 := mixed.dataslot.cp[1];
WITH mixed.coefslot, temp1do

begin

dcterm := (realpart + imagpart)/2;
noiseterm := (realpart - imagpart)/2
end;

baseangle := -twopi/realpoints;
FOR index := 1 TO realpoints DIV 4do

begin

minusindex := (realpoints DIV 2) - index;
WITH mixed.dataslotdo

begin

conjugate (cp[succ(minusindex)], temp2);
cadd (cp[succ(index)], temp2, temp1);
csubtract (cp[succ(index)], temp2, temp2)
end;

w.realpart := sin(index*baseangle);
w.imagpart := -cos(index*baseangle);
cmultiply (w, temp2, temp2);
cadd (temp1, temp2, temp3);
csubtract (temp1, temp2, temp2);
conjugate (temp2, temp2);
WITH mixed.coefslot.freqterms[index], temp3do

begin

cosineterm := realpart/2;
sineterm := -imagpart/2
end;

WITH mixed.coefslot.freqterms[minusindex], temp2do

begin

cosineterm := realpart/2;
sineterm := imagpart/2
END
END
end;


FUNCTION omegat (f : freqindextype;
t : dataindextype) : real;

{ computes omega*t for particular harmonic, index }

begin
{ omegat }
omegat := twopi * f * pred(t) / maxarraysize
end;


{ main test routine starts here }

begin

WITH mixed.dataslotdo

FOR didx := 1 TO maxarraysizedo

rp[didx] := (23
+ 13 * sin(omegat (7, didx))
+ 28 * cos(omegat (22, didx)));
fftofreal (mixed, maxarraysize);
WITH mixed.coefslotdo

writeln ('DC = ', dcterm:10:2, ' ':5, 'Noise = ', noiseterm:10:2);
FOR fidx := 1 TO maxfreqsizedo

begin

WITH mixed.coefslot.freqterms[fidx]do

write (fidx:4, round(cosineterm):4, round(sineterm):4, ' ':4);
IF fidx MOD 4 = 0
then
writeln
end;

writeln;
writeln ('The expected result should have been:');
writeln (' DC = 23, noise = 0, ');
writeln (' sine 7th harmonic = 13, cosine 22nd harmonic = 28')
end.


 
FFT algorithm: Correct version, maybe...
In case anybody's wondering those FFT routines I posted a
week or so ago are simply wrong, incorrect, give the wrong answer.

Actually, I _did_ check the thing before posting it. Was a
funny bug: I started with a simple FFT that I checked _very_
carefully. then
I started tweaking. What got checked at each stage
was Parseval's theorem: I'd take an array of random numbers and
verify that the sum of the squares was the same before and after the
Fourier transform. (Making this come out right is one reason I like to
put the 1/sqrt(N) in the definition.) I was getting the right answer
until I changed the sines and cosines to a lookup table - I wrote shr
in the index where I meant shl.
I would have thought that a BIG error like that would show
up when I checked the sum of the squares, which is why I thought
my post was at least correct. But the amusing aspect of this
particular bug is that if I use cos(AnythingWhatever) at that spot
the sum of the squares will be preserved, as long as I use
sin(AnythingWhatever) at the corresponding spot. (Exercise: if a, b,
z, w are complex numbers with |a| = |b| = 1 then


|z + a*w|^2 + |z - a*w|^ 2 = |z + b*w|^2 + |z - b*w|^ 2 .

Hence my wrong FFT is ging to satisfy Parseval...)

Last night I looked at the graphs of a few simple FT's
- they looked very strange...

If anyone's curious I'm pretty sure the following is correct. I
think. (If anyone wonder's what the point is, the recursive routine
makes a lot more sense to me than the unwrapped routine from
Numerical Recipes;
right now it's about 50% slower, which is fast
enough for my purposes, eg I can take the FFT of an array of 64K
complexes in about 0.8 seconds.)

unit cplxfft2;

interface

type
PScalar = ^TScalar;
TScalar =do
uble;

PComplex = ^TComplex;
TComplex = record
r, i : TScalar;
end;


PScalars = ^TScalars;
TScalars = array[0..High(integer) div SizeOf(TScalar) - 1]
of TScalar;
PComplexes = ^TComplexes;
TComplexes = array[0..High(integer)
div SizeOf(TComplex) - 1]
of TComplex;

TOtherComplex = record
rr, ii : TScalar;
end;


{Strange trick to allow nested with's
with two complexes...}

const
TrigTableDepth: word = 0;
CosTable : PScalars = nil;
SinTable : PScalars = nil;

procedure InitTrigTables(Depth: word);

procedure ComplexFFT(Depth: word;
Src, Dest: PComplexes);
{REQUIRES allocating

(integer(1) shl Depth) * SizeOf(TComplex)

bytes for Src Dest before call!}


implementation

proceduredo
ComplexFFT(Depth: word;
Src: PComplexes;
SrcSpacing: word;
Dest: PComplexes);
{the recursive part called by FFT when ready}
var j, N: integer;
Temp: TOtherComplex;
Shift: word;
c, s: extended;
begin

N:= integer(1) shl (Depth - 1);

{NOTE the case Depth = 0do
esn't come up -
if anyone ever _does_ want the FT of an array of
length 1 it was handled in the outer ComplexFFT function }

if Depth = 1 then

begin

Dest^[0]:= Src^[0];
Dest^[N]:= Src^[srcSpacing];
end
else

begin

do
ComplexFFT(Depth - 1, Src, SrcSpacing * 2, Dest);
do
ComplexFFT(Depth - 1,
@Src^[srcSpacing],
SrcSpacing * 2,
@Dest^[N]);
end;


Shift:= TrigTableDepth - Depth;

for j:= 0 to N - 1do

begin

c:= CosTable^[j shl Shift];
s:= SinTable^[j shl Shift];

// Bug was here - NOW this is the same as
// c:= cos(j*Pi/N);
// s:= -sin(j*Pi/N);

with Tempdo

begin

with Dest^[j+N]do

begin

rr:= c*r - s*i;
ii:= c*i + s*r;
r:= Dest^[j].r - rr;
i:= Dest^[j].i - ii;
end;


with Dest^[j]do

begin

r:= r + rr;
i:= i + ii;
end;

end;

end;


end;



procedure ComplexFFT(Depth: word;
Src, Dest: PComplexes);
var j, N: integer;
Normalizer: extended;
begin

if Depth = 0 then

begin

Dest^[0]:=Src^[0];
exit;
end;


N:= integer(1) shl depth;

if Depth > TrigTableDepth then

InitTrigTables(Depth);

DoComplexFFT(Depth, Src, 1, Dest);

Normalizer:= 1 / sqrt(N) ;

for j:=0 to N - 1do

with Dest^[j]do

begin

R:= R * Normalizer;
I:= I * Normalizer;
end;


end;



procedure InitTrigTables(Depth: word);
var j, N: integer;
{Um, only half of this table ever gets used here - the
other half is used else
where...}
begin


N:= integer(1) shl depth;
ReAllocMem(CosTable, N * SizeOf(TScalar));
ReAllocMem(SinTable, N * SizeOf(TScalar));
for j:=0 to N - 1do

begin

CosTable^[j]:= cos(-(2*Pi)*j/N);
SinTable^[j]:= sin(-(2*Pi)*j/N);
end;

TrigTableDepth:= Depth;

end;


initialization

;

finalization
ReAllocMem(CosTable, 0);
ReAllocMem(SinTable, 0);

end.


--
David Ullrich

Oh well...

 
提供者: JACK BAKKER

{
> I'm Looking for a source for a FFT of the Soundblaster
> Input. Could somebody help me?

Do you know the basics of Fourier Transformation?
Not that you need to, for this routine, but it might be handy to know.
Anyhow, here's something I still didn't test:
}

Program FOURIER;

{ Real FFT with single sine look-up per pass }

Const
Asize = 4096;
{ Size of array goes here }
PI2 = 1.570796327;
{ PI/2 }
F = 16;
{ Format constants }
D = 6;
{ " " }

Type
Xform = (Fwd,Inverse);
{ Transform types }
Xary = Array[1..Asize] of Real;

Var
I,j,N,modulo : Integer;
F1 : Text;
{ File of Real;}
X : Xary;
{ Array to transform }
Inv : Xform;
{ Transform type - Forward or Inverse }
w : Real;
{ Frequency of wave }

{*****************************************************************************}

Procedure Debug;
{ Used to print intermediate results }

Var I3 : Integer;

begin

For I3 := 1 to Ndo

Writeln((I3-1):3,X[I3]:F:D);
end;

{ Debug }

{*****************************************************************************}

Function Ibitr(j,nu : Integer) : Integer;
{ Function to bit invert the number j by nu bits }

Var
i,j2,ib : Integer;

begin

ib := 0;
{ Default return integer }
For i := 1 to nudo

begin

j2 := j Div 2;
{ Divide by 2 and compare lowest bits }
{ ib isdo
ubled and bit 0 set to 1 if j is odd }
ib := ib*2 + (j - 2*j2);
j := j2;
{ For next pass }
end;

{For}
ibitr := ib;
{ Return bit inverted value }
end;

{ Ibitr }

{*****************************************************************************}

Procedure Expand;

Var
i,nn2,nx2 : Integer;

begin

nn2 := n div 2;
nx2 := n + n;
For i := 1 to nn2do
x[i+n] := x[i+nn2];
{ Copy IM to 1st half IM position }
For i := 2 to nn2do

begin

x[nx2-i+2] := -x[i+n];
{ Replicate 2nd half Imag as negative }
x[n-i+2] := x;
{ Replicate 2nd half Real as mirror image }
end;

n := nx2;
{ We havedo
ubled number of points }
end;


{*****************************************************************************}

Procedure Post(inv : Xform);
{ Post processing for forward real transforms and pre-processing for inverse
real transforms, depending on state of the variable inv. }

Var
nn2,nn4,l,i,m,ipn2,mpn2 : Integer;
arg,rmsin,rmcos,ipcos,ipsin,ic,is1,rp,rm,ip,im : Real;

begin

nn2 := n div 2;
{ n is global }
nn4 := n div 4;
{ imax represents PI/2 }
For l := 1 to nn4do

{ Start at ends of array and work towards middle }
begin

i := l+1;
{ Point near begin
ning }
m := nn2-i+2;
{ Point near end }
ipn2 := i+nn2;
{ Avoids recalculation each time }
mpn2 := m+nn2;
{ Calcs ptrs to imaginary part }
rp := x+x[m];
rm := x-x[m];
ip := x[ipn2]+x[mpn2];
im := x[ipn2]-x[mpn2];
{ Take cosine of PI/2 }
arg := (Pi2/nn4)*(i-1);
ic := Cos(arg);
{ Cosine term is minus if inverse }
If inv = Inverse then
ic := -ic;
Is1 := Sin(arg);
ipcos := ip*ic;
{ Avoid remultiplication below }
ipsin := ip*is1;
rmsin := rm*is1;
rmcos := rm*ic;
x := (rp + ipcos - rmsin)/2.0;
{* Combine for real-1st pt }
x[ipn2] := (im - ipsin - rmcos)/2.0;
{* Imag-1st point }
x[m] := (rp - ipcos + rmsin)/2.0;
{* Real - last pt }
x[mpn2] := -(im +ipsin +rmcos)/2.0;
{* Imag, last pt }
end;

{ For }
x[1] := x[1]+x[nn2+1];
{** For first complex pair}
x[nn2+1] := 0.0;
{**}
end;

{ Post }

{*****************************************************************************}

Procedure Shuffl(inv : Xform);
{ This procedure shuffels points from alternate real-imaginary to
1st-half real, 2nd-half imaginary order if inv=Fwd, and reverses the
process if inv=Inverse. Algorithm is much like Cooley-Tukey:
Starts with large cells and works to smaller ones for Fwd
Starts with small cells and increases if inverse }

Var
i,j,k,ipcm1,celdis,celnum,parnum : Integer;
xtemp : Real;

begin

{ Choose whether to start with large cells and godo
wn or start with small
cells and increase }

Case inv Of

Fwd: begin

celdis := n div 2;
{ Distance between cells }
celnum := 1;
{ One cell in first pass }
parnum := n div 4;
{ n/4 pairs per cell in 1st pass }
end;

{ Fwd case }

Inverse: begin

celdis := 2;
{ Cells are adjacent }
celnum := n div 4;
{ n/4 cells in first pass }
parnum := 1;
end;

{ Inverse case }

end;

{ Case }

Repeat { Until cells large if Fwd or small if Inverse }
i := 2;
For j:= 1 to celnumdo

begin

For k := 1 to parnumdo
{do
all pairs in each cell }
begin

Xtemp := x;
ipcm1 := i+celdis-1;
{ Index of other pts }
x := x[ipcm1];
x[ipcm1] := xtemp;
i := i+2;
end;

{ For k }

{ End of cell, advance to next one }
i := i+celdis;
end;

{ For j }

{ Change values for next pass }

Case inv Of
Fwd: begin

celdis := celdis div 2;
{ Decrease cell distance }
celnum := celnum * 2;
{ More cells }
parnum := parnum div 2;
{ Less pairs per cell }
end;

{ Case Fwd }

Inverse: begin

celdis := celdis * 2;
{ More distance between cells }
celnum := celnum div 2;
{ Less cells }
parnum := parnum * 2;
{ More pairs per cell }
end;

{ Case Inverse }
end;

{ Case }

Until (((inv = Fwd) And (Celdis < 2)) Or ((inv=Inverse) And (celnum = 0)));

end;

{ Shuffl }

{*****************************************************************************}

Procedure FFT(inv : Xform);
{ Fast Fourier transform procedure operating on data in 1st half real,
2nd half imaginary order and produces a complex result }

Var
n1,n2,nu,celnum,celdis,parnum,ipn2,kpn2,jpn2,
i,j,k,l,i2,imax,index : Integer;
arg,cosy,siny,r2cosy,r2siny,i2cosy,i2siny,picons,
y,deltay,k1,k2,tr,ti,xtemp : Real;

begin

{ Calculate nu = log2(n) }
nu := 0;
n1 := n div 2;
n2 := n1;
While n1 >= 2do

begin

nu := nu + 1;
{ Increment power-of-2 counter }
n1 := n1 div 2;
{ divide by 2 until zero }
end;

{ Shuffel the data into bit-inverted order }
For i := 1 to n2do

begin

k := ibitr(i-1,nu)+1;
{ Calc bit-inverted position in array }
If i>k then
{ Prevent swapping twice }
begin

ipn2 := i+n2;
kpn2 := k+n2;
tr := x[k];
{ Temp storage of real }
ti := x[kpn2];
{ Temp imag }
x[k] := x;
x[kpn2] := x[ipn2];
x := tr;
x[ipn2] := ti;
end;

{ If }
end;

{ For }

{do
first pass specially, since it has no multiplications }
i := 1;
While i <= n2do

begin

k := i+1;
kpn2 := k+n2;
ipn2 := i+n2;
k1 := x+x[k];
{ Save this sum }
x[k] := x-x[k];
{ Diff to k's }
x := k1;
{ Sum to I's }
k1 := x[ipn2]+x[kpn2];
{ Sum of imag }
x[kpn2] := x[ipn2]-x[kpn2];
x[ipn2] := k1;
i := i+2;
end;

{ While }

{ Set up deltay for 2nd pass, deltay=PI/2 }
deltay := PI2;
{ PI/2 }
celnum := n2 div 4;
parnum := 2;
{ Number of pairs between cell }
celdis := 2;
{ Distance between cells }


{ Each pass after 1st starts here }
Repeat { Until number of cells becomes zero }

{ Writeln(Lst,'After Nth Pass:');
### }
{ Debug;
}

{ Each new cell starts here }
index := 1;
y := 0;
{ Exponent of w }
{do
the number of pairs in each cell }
For i2 := 1 To parnumdo

begin

If y <> 0 then

begin
{ Use sines and cosines if y is not zero }
cosy := cos(y);
{ Calc sine and cosine }
siny := sin(y);
{ Negate sine terms if transform is inverse }
If inv = Inverse then
siny := -siny;
end;

{ If }
{ These are the fundamental equations of the FFT }
For l := 0 to celnum-1do

begin

i := (celdis*2)*l + index;
j := i+celdis;
ipn2 := i + n2;
jpn2 := j + n2;
If y = 0 then
{ Special case for y=0 -- No sine or cosine terms }
begin

k1 := x+x[j];
k2 := x[ipn2]+x[jpn2];
x[j] := x-x[j];
x[jpn2] := x[ipn2]-x[jpn2];
End { If-then
}
else

begin

r2cosy := x[j]*cosy;
{ Calc intermediate constants }
r2siny := x[j]*siny;
i2cosy := x[jpn2]*cosy;
i2siny := x[jpn2]*siny;
{ Butterfly }
k1 := x + r2cosy + i2siny;
k2 := x[ipn2] - r2siny + i2cosy;
x[j] := x - r2cosy - i2siny;
x[jpn2] := x[ipn2] + r2siny - i2cosy;
end;

{ else
}
{ Replace the i terms }
x := k1;
x[ipn2] := k2;

{ Advance angle for next pair }
end;

{ For l }

Y := y + deltay;
index := index + 1;
end;

{ For i2 }

{ Passdo
ne - change cell distance and number of cells }
celnum := celnum div 2;
parnum := parnum * 2;
celdis := celdis * 2;
deltay := deltay/2;

Until celnum = 0;

end;

{ FFT }

{*****************************************************************************}

begin
{ * Main program * }
For i := 0 To Asize-1do

begin

x := 0.0;
end;


{ Write('Enter number of points: ');
Readln(n);}
n := 32;
If (n > Asize) then

begin

Writeln('Too large, will use maximum');
n := Round(asize/2.0);
end;

For i := 2 to ndo
x := Exp((1-i)*0.25);
{ Create Real array }
x[1] := 0.5;
Writeln('Input Array:');
Debug;
Shuffl(Fwd);
FFT(Fwd);
Post(Fwd);
For i:= 1 to ndo
x := x*8/n;
Writeln('Forward FFT with real array first:');
Debug;
end.


 
提供者: MARCEL HOOGEVEEN

{
From: marcel.hoogeveen@hacom.wlink.nl (Marcel Hoogeveen)

GR> FFT stands for Fast Fourier Transform. It is a quick way to conver
GR> timedo
main data (ie oscilliscopy data with time on the x-axis) to
GR> frequencydo
main (frequency on the x-axis, like a frequency spectrum
GR> analyzer). This is a usefull data analysis method. I would also like
GR> to get some source for this.


This is what i have of FFT source code, it should work if you tweak it a bit.
(It did for me when i used it in my analasis program).
Don't ask me how it works, i know how a DFT works but a FFT well .. just use
the source. :)

}
Program FFT;
Const Twopi=6.283185303;

Type Curve=array[1..nfft] of real;

Var {This is for you to find out}

{ Calculation of the Discrete Fourier Transfor }
{ Using a Fast Fourier Transform algorithm }
{ }
{ XR and XI are array of reals !!! }
{ They contain on entry the input sequence and }
{ on return the transfrom }
{ ISI defines the transform direction }
{ If ISI=-1 then
forward, if ISI=1 then
invert }
{ }
{ The dimension is 2**M }

Procedure RFFT (VAR XR,XI:Curve;
N:integer;
ISI:Integer);
Var
M,NV2,LE,LE1,IP,I,J,K,L: Integer;
C,THETA,UR,UI,TR,TI:Real;

begin

M:=Round(LN(N)/LN(2));
NV2:= N DIV 2;
J:=1;
For I:= 1 to N-1do

begin

If (I=N)
end;

end;

If ISI=-1 then

begin

For I:= 1 TO Ndo

begin

XR:=4*XR/N;
XI:=4*XI/N;
end;

end;

end;



begin

For I := 1 to NUMSAMdo

begin

FREAL:=SAMPLEBUFFER;
FIMAG:=0;
end;

RFFT(FREAL,FIMAG,NUMSAM,-1);
DC:=FREAL[1]/2;
For I:= 1 to NUMSAMdo

FREAL:=FREAL*FREAL+fIMAG*FIMAG;
end.
 
我试试能不能弄明白。有没有中文说明的呀?
 
Sorry 没有。。。。
 
试一试WaveGain吧,我就使用它的CODE完成的 WAVE EQ
 
下载地址 我也想学学
 
http://www.maazl.de/project/mp3/mp3gain.html
 
wavegain里没找到可以EQ的部分啊?qince你怎么实现的?能不能分享一下?我要的是可以实现31段均衡的。
 
dcdspfilter
找这个参考一下吧
 
学习中。。。
 
dcdspfilter是调用Directd的,没有FFT源码。
现在已经知道N个采样点经FFT后转换后得到N个复数,即时域变成频域,却不明白如何调整各频率段的振幅,qince你说实现了EQ,可否赐教?
X[1..N]是wav采样数据,FFT转换得到实数XR[1..N],虚数XI[1..N],如何调整这N个频率段的振幅?再FFT逆转换?

以下是一份资料,我没看懂,贴出来,轻能看明白的朋友指教我上面的问题,谢谢。
嵌入式系统中FFT算法研究

作 者:华东交通大学 肖宛昂
     北京航天指挥控制中心 张向荣

摘 要:首先分析实数FFT算法的推导过程,然后给出一种具体实现FFT算法的C语言程序,可以直接应用于需要FFT运算的单片机或DSP等嵌入式系统中。


关键词:嵌入式系统 FFT算法 单片机 DSP


  目前国内有关数字信号处理的教材在讲解快速傅里叶变换(FFT)时,都是以复数FFT为重点,实数FFT算法都是一笔带过,书中给出的具体实现程序多为BASIC或FORTRAN程序并且多数不能真正运行。鉴于目前在许多嵌入式系统中要用到FFT运算,如以DSP为核心的交流采样系统、频谱分析、相关分析等。本人结合自己的实际开发经验,研究了实数的FFT算法并给出具体的C语言函数,读者可以直接应用于自己的系统中。

1 倒位序算法分析

  按时间抽取(DIT)的FFT算法通常将原始数据倒位序存储,最后按正常顺序输出结果X(0),X(1),...,X(k),...。假设一开始,数据在数组 float dataR[128]中,我们将下标i表示为(b6b5b4b3b2b1b0)b,倒位序存放就是将原来第i个位置的元素存放到第(b0b1b2b3b4b5b6)b的位置上去.由于C语言的位操作能力很强,可以分别提取出b6、b5、b4、b3、b2、b1、b0,再重新组合成b0、b1、b2、b3、b4、b5、b6,即是倒位序的位置。程序段如下(假设128点FFT):
/* i为原始存放位置,最后得invert_pos为倒位序存放位置 */
 int b0=b1=b2=b3=b4=b5=6=0;
 b0=i&amp;0x01;
b1=(i/2)&amp;0x01;
b2=(i/4)&amp;0x01;
 b3=(i/8)&amp;0x01;
b4=(i/16)&amp;0x01;
b5=(i/32)&amp;0x01;
 b6=(i/64)&amp;0x01;
/*以上语句提取各比特的0、1值*/
 invert_pos=x0*64+x1*32+x2*16+x3*8+x4*4+x5*2+x6;

  大家可以对比教科书上的倒位序程序,会发现这种算法充分利用了C语言的位操作能力,非常容易理解而且位操作的速度很快。

2 实数蝶形运算算法的推导

  我们首先看一下图1所示的蝶形图。
    
蝶形公式:
X(K) = X’(K) + X’(K+B)W PN ,
X(K+B) = X’(K) - X’(K+B) W PN
其中W PN= cos(2πP/N)- jsin(2πP/N)。
设 X(K+B) = XR(K+B) + jXI(K+B),
X(K) = XR(K) + jXI(K) ,
有:
XR(K)+jXI(K)= XR’(K)+jXI’(K)+[ XR’(K+B) + jXI’(K+B)]*[ cos(2πP/N)-jsin(2πP/N)];
继续分解得到下列两式:
XR(K)= XR’(K)+ XR’(K+B) cos(2πP/N)+ XI’(K+B) sin (2πP/N) (1)
XI(K)= XI’(K)-XR’(K+B) sin(2πP/N)+XI’(K+B)cos (2πP/N) (2)

  需要注意的是: XR(K)、XR’(K)的存储位置相同,所以经过(1)、(2)后,该位置上的值已经改变,而下面求X(K+B)要用到X’(K),因此在编程时要注意保存XR’(K)和XI’(K)到TR和TI两个临时变量中。

  同理: XR(K+B)+jXI(K+B)= XR’(K)+jXI’(K)- [ XR’(K+B)+jXI’(K+B)] *[ cos(2πP/N)-jsin(2πP/N)]继续分解得到下列两式:
XR(K+B)= XR’(K)-XR’(K+B) cos(2πP/N)- XI’(K+B) sin (2πP/N) (3)
XI(K+B)= XI’(K)+ XR’(K+B) sin(2πP/N)- XI’(K+B) cos (2πP/N) (4)
注意:
  ① 在编程时, 式(3)、(4)中的XR’(K)和 XI’(K)分别用TR和TI代替。

  ② 经过式(3)后, XR(K+B)的值已变化,而式(4)中要用到该位置上的上一级值,所以在执行式(3)前要先将上一级的值XR’(K+B)保存。

  ③ 在编程时, XR(K)和 XR’(K), XI(K)和 XI’(K)使用同一个变量。
  通过以上分析,我们只要将式(1)、(2)、(3)、(4)转换成C语言语句即可。要注意变量的中间保存,详见以下程序段。

/* 蝶形运算程序段 ,dataR[]存放实数部分,dataI[]存放虚部*/
/* cos、sin函数做成表格,直接查表加快运算速度 */
TR=dataR[k];
TI=dataI[k];
temp=dataR[k+b];/*保存变量,供后面语句使用*/
dataR[k]=dataR[k]+dataR[k+b]*cos_tab[p]+dataI[k+b]*sin_tab[p];
dataI[k]=dataI[k]-dataR[k+b]*sin_tab[p]+dataI[k+b]*cos_tab[p];
dataR[k+b]=TR-dataR[k+b]*cos_tab[p]-dataI[k+b]*sin_tab[p];
dataI[k+b]=TI+temp*sin_tab[p]-dataI[k+b]*cos_tab[p];

3 DIT FFT 算法的基本思想分析

  我们知道N点FFT运算可以分成LOGN2 级,每一级都有N/2个碟形。DIT FFT的基本思想是用3层循环完成全部运算(N点FFT)。

  第一层循环:由于N=2m需要m级计算,第一层循环对运算的级数进行控制。

  第二层循环:由于第L级有2L-1个蝶形因子(乘数),第二层循环根据乘数进行控制,保证对于每一个蝶形因子第三层循环要执行一次,这样,第三层循环在第二层循环控制下,每一级要进行2L-1次循环计算。

  第三层循环:由于第L级共有N/2L个群,并且同一级内不同群的乘数分布相同,当第二层循环确定某一乘数后,第三层循环要将本级中每个群中具有这一乘数的蝶形计算一次,即第三层循环每执行完一次要进行N/2L个碟形计算。

  可以得出结论:在每一级中,第三层循环完成N/2L个碟形计算;第二层循环使第三层循环进行 2L-1次,因此,第二层循环完成时,共进行2L-1 *N/2L=N/2个碟形计算。实质是:第二、第三层循环完成了第L级的计算。

  几个要注意的数据:

  ① 在第L级中,每个碟形的两个输入端相距b=2L-1个点。

  ② 同一乘数对应着相邻间隔为2L个点的N/2L个碟形。

  ③ 第L级的2L-1个碟形因子WPN 中的P,可表示为p = j*2m-L,其中j = 0,1,2,...,(2L-1-1)。

  以上对嵌入式系统中的FFT算法进行了分析与研究。读者可以将其算法直接应用到自己的系统中,欢迎来信共同讨论。(Email:xiaowanang@163.net)

  附128点DIT FFT函数:
/* 采样来的数据放在dataR[ ]数组中,运算前dataI[ ]数组初始化为0 */
void FFT(float dataR[],float dataI[])
{int x0,x1,x2,x3,x4,x5,x6;
int L,j,k,b,p;
float TR,TI,temp;
/********** following code invert sequence ************/
for(i=0;i<128;i++)
{ x0=x1=x2=x3=x4=x5=x6=0;
x0=i&amp;0x01;
x1=(i/2)&amp;0x01;
x2=(i/4)&amp;0x01;
x3=(i/8)&amp;0x01;x4=(i/16)&amp;0x01;
x5=(i/32)&amp;0x01;
x6=(i/64)&amp;0x01;
xx=x0*64+x1*32+x2*16+x3*8+x4*4+x5*2+x6;
dataI[xx]=dataR;
}
for(i=0;i<128;i++)
{ dataR=dataI;
dataI=0;
}
/************** following code FFT *******************/
for(L=1;L<=7;L++) { /* for(1) */
b=1;
i=L-1;
while(i>0)
{b=b*2;
i--;} /* b= 2^(L-1) */
for(j=0;j<=b-1;j++) /* for (2) */
{ p=1;
i=7-L;
while(i>0) /* p=pow(2,7-L)*j;
*/
{p=p*2;
i--;}
p=p*j;
for(k=j;k<128;k=k+2*b) /* for (3) */
{ TR=dataR[k];
TI=dataI[k];
temp=dataR[k+b];
dataR[k]=dataR[k]+dataR[k+b]*cos_tab[p]+dataI[k+b]*sin_tab[p];
dataI[k]=dataI[k]-dataR[k+b]*sin_tab[p]+dataI[k+b]*cos_tab[p];
dataR[k+b]=TR-dataR[k+b]*cos_tab[p]-dataI[k+b]*sin_tab[p];
dataI[k+b]=TI+temp*sin_tab[p]-dataI[k+b]*cos_tab[p];
} /* END for (3) */
} /* END for (2) */
} /* END for (1) */
for(i=0;i<32;i++){ /* 只需要32次以下的谐波进行分析 */
w=sqrt(dataR*dataR+dataI*dataI);
w=w/64;}
w[0]=w[0]/2;
} /* END FFT */
 
我有几个fft函数,我都用过,是c写的,不知你用不。
 
找了个现成的,搞定。
 

Similar threads

S
回复
0
查看
3K
SUNSTONE的Delphi笔记
S
S
回复
0
查看
2K
SUNSTONE的Delphi笔记
S
后退
顶部