Ïóáëèêóþ ïðèñëàííûé ÷èòàòåëåì àëãîðèòì:
{$A+,B-,C+,D+,E-,F-,G+,H+,I+,J+,K-,L+,M-,N+,O-,P+,Q-,R-,S-,T-,U-,V+,W-,X+,Y+ ,Z1} {$MINSTACKSIZE $00004000} {$MAXSTACKSIZE $00100000} {$IMAGEBASE $00400000} {$APPTYPE GUI} unit Main; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Buttons, ExtCtrls, ComCtrls, Menus; type TfmMain = class(TForm) MainMenu1: TMainMenu; N1: TMenuItem; N2: TMenuItem; StatusBar1: TStatusBar; N3: TMenuItem; imgInfo: TImage; Panel1: TPanel; btnStart: TSpeedButton; procedure btnStartClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); end; var fmMain: TfmMain; implementation Uses PFiles; {$R *.DFM} function Power2(lPower: Byte): LongInt; begin Result := 1 Shl lPower; end; procedure ClassicDirect(Var aSignal, aSpR, aSpI: Array Of Double; N: LongInt); var lSrch : LongInt; var lGarm : LongInt; var dSumR : Double; var dSumI : Double; begin for lGarm := 0 to N div 2 - 1 do begin dSumR := 0; dSumI := 0; for lSrch := 0 to N - 1 do begin dSumR := dSumR + aSignal[lSrch] * Cos(lGarm * lSrch / N * 2 * PI); dSumI := dSumI + aSignal[lSrch] * Sin(lGarm * lSrch / N * 2 * PI); end; aSpR[lGarm] := dSumR; aSpI[lGarm] := dSumI; end; end; procedure ClassicInverce(Var aSpR, aSpI, aSignal: Array Of Double; N: LongInt); var lSrch : LongInt; var lGarm : LongInt; var dSum : Double; begin for lSrch := 0 to N-1 do begin dSum := 0; for lGarm := 0 to N div 2 -1 do dSum := dSum + aSpR[lGarm] * Cos(lSrch * lGarm * 2 * Pi / N) + aSpI[lGarm] * Sin(lSrch * lGarm * 2 * Pi / N); aSignal[lSrch] := dSum*2; end; end; Function InvertBits(BF, DataSize, Power: Word) : Word; Var BR : Word; Var NN : Word; Var L : Word; Begin br:= 0; nn:= DataSize; For l:= 1 To Power Do Begin NN:= NN Div 2; If (BF >= NN) Then Begin BR:= BR + Power2(l - 1); BF:= BF - NN End; End; InvertBits:=BR; End; Procedure FourierDirect(Var RealData,VirtData,ResultR,ResultV: Array Of Double; DataSize: LongInt); Var A1 : Real; Var A2 : Real; Var B1 : Real; Var B2 : Real; Var D2 : Word; Var C2 : Word; Var C1 : Word; Var D1 : Word; Var I : Word; Var J : Word; Var K : Word; Var Cosin : Real; Var Sinus : Real; Var wIndex : Word; Var Power : Word; Begin C1:= DataSize Shr 1; C2:= 1; for Power:=0 to 15 //hope it will be faster then round(ln(DataSize)/ln(2)) do if Power2(Power)=DataSize then Break; For I:= 1 To Power Do Begin D1:= 0; D2:= C1; For J:= 1 To C2 Do Begin wIndex:=InvertBits(D1 Div C1, DataSize, Power); Cosin:= +(Cos((2 * Pi / DataSize)*wIndex)); Sinus:= -(Sin((2 * Pi / DataSize)*wIndex)); For K:= D1 To D2 - 1 Do Begin A1:= RealData[K]; A2:= VirtData[K]; B1:= ((Cosin * RealData[K + C1] - Sinus * VirtData[K + C1]) ); B2:= ((Sinus * RealData[K + C1] + Cosin * VirtData[K + C1]) ); RealData[K]:= A1 + B1 ; VirtData[K]:= A2 + B2 ; RealData[K + C1]:= A1 - B1; VirtData[K + C1]:= A2 - B2; End; Inc(D1,C1 * 2); Inc(D2,C1 * 2); End; C1:=C1 Div 2; C2:=C2 * 2; End; For I:= 0 To DataSize Div 2 -1 Do Begin ResultR[I]:= + RealData[InvertBits(I, DataSize, Power)]; ResultV[I]:= - VirtData[InvertBits(I, DataSize, Power)]; End; End; Procedure Hartley(iSize: LongInt;Var aData : Array Of Double); Type taDouble = Array[0..MaxLongInt Div SizeOf(Double)-1] Of Double; Var prFI,prFN,prGI : ^taDouble; Var rCos,rSin : Double; Var rA,rB,rTemp : Double; Var rC1,rC2,rC3,rC4 : Double; Var rS1,rS2,rS3,rS4 : Double; Var rF0,rF1,rF2,rF3 : Double; Var rG0,rG1,rG2,rG3 : Double; Var iK1,iK2,iK3,iK4 : LongInt; Var iSrch,iK,iKX : LongInt; Begin iK2:=0; For iK1:=1 To iSize-1 Do Begin iK:=iSize Shr 1; Repeat iK2:=iK2 Xor iK; If (iK2 And iK)<>0 Then Break; iK:=iK Shr 1; Until False; If iK1>iK2 Then Begin rTemp:=aData[iK1]; aData[iK1]:=aData[iK2]; aData[iK2]:=rTemp; End; End; iK:=0; While (1 Shl iK)<iSize Do Inc(iK); iK:=iK And 1; If iK=0 Then Begin prFI:=@aData; prFN:=@aData; prFN := @prFN[iSize]; While Word(prFI)<Word(prFN) Do Begin rF1:=prFI^[0]-prFI^[1]; rF0:=prFI^[0]+prFI^[1]; rF3:=prFI^[2]-prFI^[3]; rF2:=prFI^[2]+prFI^[3]; prFI^[2]:=rF0-rF2; prFI^[0]:=rF0+rF2; prFI^[3]:=rF1-rF3; prFI^[1]:=rF1+rF3; prFI := @prFI[4]; End; End Else Begin prFI:=@aData; prFN:=@aData; prFN := @prFN[iSize]; prGI:=prFI; prGI := @prGI[1]; While Word(prFI)<Word(prFN) Do begin rC1:=prFI^[0]-prGI^[0]; rS1:=prFI^[0]+prGI^[0]; rC2:=prFI^[2]-prGI^[2]; rS2:=prFI^[2]+prGI^[2]; rC3:=prFI^[4]-prGI^[4]; rS3:=prFI^[4]+prGI^[4]; rC4:=prFI^[6]-prGI^[6]; rS4:=prFI^[6]+prGI^[6]; rF1:=rS1-rS2; rF0:=rS1+rS2; rG1:=rC1-rC2; rG0:=rC1+rC2; rF3:=rS3-rS4; rF2:=rS3+rS4; rG3:=Sqrt(2)*rC4; rG2:=Sqrt(2)*rC3; prFI^[4]:=rF0-rF2; prFI^[0]:=rF0+rF2; prFI^[6]:=rF1-rF3; prFI^[2]:=rF1+rF3; prGI^[4]:=rG0-rG2; prGI^[0]:=rG0+rG2; prGI^[6]:=rG1-rG3; prGI^[2]:=rG1+rG3; prFI := @prFI[8]; prGI := @prGI[8]; End; End; If iSize<16 Then Exit; Repeat Inc(iK,2); iK1:=1 Shl iK; iK2:=iK1 Shl 1; iK4:=iK2 Shl 1; iK3:=iK2+iK1; iKX:=iK1 Shr 1; prFI:=@aData; prGI:=prFI; prGI := @prGI[iKX]; prFN:=@aData; prFN := @prFN[iSize]; Repeat rF1:= prFI^[000]-prFI^[iK1]; rF0:= prFI^[000]+prFI^[iK1]; rF3:= prFI^[iK2]-prFI^[iK3]; rF2:= prFI^[iK2]+prFI^[iK3]; prFI^[iK2]:=rF0-rF2; prFI^[000]:=rF0+rF2; prFI^[iK3]:=rF1-rF3; prFI^[iK1]:=rF1+rF3; rG1:=prGI^[0]-prGI^[iK1]; rG0:=prGI^[0]+prGI^[iK1]; rG3:=Sqrt(2)*prGI^[iK3]; rG2:=Sqrt(2)*prGI^[iK2]; prGI^[iK2]:=rG0-rG2; prGI^[000]:=rG0+rG2; prGI^[iK3]:=rG1-rG3; prGI^[iK1]:=rG1+rG3; prGI := @prGI[iK4]; prFI := @prFI[iK4]; Until Not (Word(prFI)<Word(prFN)); rCos:=Cos(Pi/2/Power2(iK)); rSin:=Sin(Pi/2/Power2(iK)); rC1:=1; rS1:=0; For iSrch:=1 To iKX-1 Do Begin rTemp:=rC1; rC1:=(rTemp*rCos-rS1*rSin); rS1:=(rTemp*rSin+rS1*rCos); rC2:=(rC1*rC1-rS1*rS1); rS2:=(2*(rC1*rS1)); prFN:=@aData; prFN := @prFN[iSize]; prFI:=@aData; prFI := @prFI[iSrch]; prGI:=@aData; prGI := @prGI[iK1-iSrch]; Repeat rB:=(rS2*prFI^[iK1]-rC2*prGI^[iK1]); rA:=(rC2*prFI^[iK1]+rS2*prGI^[iK1]); rF1:=prFI^[0]-rA; rF0:=prFI^[0]+rA; rG1:=prGI^[0]-rB; rG0:=prGI^[0]+rB; rB:=(rS2*prFI^[iK3]-rC2*prGI^[iK3]); rA:=(rC2*prFI^[iK3]+rS2*prGI^[iK3]); rF3:=prFI^[iK2]-rA; rF2:=prFI^[iK2]+rA; rG3:=prGI^[iK2]-rB; rG2:=prGI^[iK2]+rB; rB:=(rS1*rF2-rC1*rG3); rA:=(rC1*rF2+rS1*rG3); prFI^[iK2]:=rF0-rA; prFI^[0]:=rF0+rA; prGI^[iK3]:=rG1-rB; prGI^[iK1]:=rG1+rB; rB:=(rC1*rG2-rS1*rF3); rA:=(rS1*rG2+rC1*rF3); prGI^[iK2]:=rG0-rA; prGI^[0]:=rG0+rA; prFI^[iK3]:=rF1-rB; prFI^[iK1]:=rF1+rB; prGI := @prGI[iK4]; prFI := @prFI[iK4]; Until Not (LongInt(prFI) < LongInt(prFN)); End; Until Not (iK4<iSize); End; Procedure HartleyDirect( Var aData : Array Of Double; iSize : LongInt); Var rA,rB : Double; Var iI,iJ,iK : LongInt; Begin Hartley(iSize,aData); iJ:=iSize-1; iK:=iSize Div 2; For iI:=1 To iK-1 Do Begin rA:=aData[ii]; rB:=aData[ij]; aData[iJ]:=(rA-rB)/2; aData[iI]:=(rA+rB)/2; Dec(iJ); End; End; Procedure HartleyInverce( Var aData : Array Of Double; iSize : LongInt); Var rA,rB : Double; Var iI,iJ,iK : LongInt; Begin iJ:=iSize-1; iK:=iSize Div 2; For iI:=1 To iK-1 Do Begin rA:=aData[iI]; rB:=aData[iJ]; aData[iJ]:=rA-rB; aData[iI]:=rA+rB; Dec(iJ); End; Hartley(iSize,aData); End; //not tested procedure HartleyDirectComplex(real,imag: Array of Double;n: LongInt); var a,b,c,d : double; q,r,s,t : double; i,j,k : LongInt; begin j:=n-1; k:=n div 2; for i:=1 to k-1 do begin a := real[i]; b := real[j]; q:=a+b; r:=a-b; c := imag[i]; d := imag[j]; s:=c+d; t:=c-d; real[i] := (q+t)*0.5; real[j] := (q-t)*0.5; imag[i] := (s-r)*0.5; imag[j] := (s+r)*0.5; dec(j); end; Hartley(N,Real); Hartley(N,Imag); end; //not tested procedure HartleyInverceComplex(real,imag: Array Of Double;N: LongInt); var a,b,c,d :double; q,r,s,t :double; i,j,k :longInt; begin Hartley(N,real); Hartley(N,imag); j:=n-1; k:=n div 2; for i:=1 to k-1 do begin a := real[i]; b := real[j]; q:=a+b; r:=a-b; c := imag[i]; d := imag[j]; s:=c+d; t:=c-d; imag[i] := (s+r)*0.5; imag[j] := (s-r)*0.5; real[i] := (q-t)*0.5; real[j] := (q+t)*0.5; dec(j); end; end; procedure DrawSignal(var aSignal: Array Of Double;N,lColor : LongInt); var lSrch : LongInt; var lHalfHeight : LongInt; begin with fmMain do begin lHalfHeight := imgInfo.Height Div 2; imgInfo.Canvas.MoveTo(0,lHalfHeight); imgInfo.Canvas.Pen.Color := lColor; for lSrch := 0 to N-1 do begin imgInfo.Canvas.LineTo(lSrch,Round(aSignal[lSrch]) + lHalfHeight); end; imgInfo.Repaint; end; end; procedure DrawSpector(var aSpR, aSpI: Array Of Double;N, lColR, lColI : LongInt); var lSrch : LongInt; var lHalfHeight : LongInt; begin with fmMain do begin lHalfHeight := imgInfo.Height Div 2; for lSrch := 0 to N Div 2 do begin imgInfo.Canvas.Pixels[lSrch ,Round(aSpR[lSrch]/N) + lHalfHeight] := lColR; imgInfo.Canvas.Pixels[lSrch + N Div 2 ,Round(aSpI[lSrch]/N) + lHalfHeight] := lColI; end; imgInfo.Repaint; end; end; const N = 512; var aSignalR : Array[0..N-1] Of Double;// var aSignalI : Array[0..N-1] Of Double;// var aSpR, aSpI : Array[0..N Div 2-1] Of Double;// var lFH : LongInt; procedure TfmMain.btnStartClick(Sender: TObject); const Epsilon = 0.00001; var lSrch : LongInt; var aBuff : Array[0..N-1] Of ShortInt; begin if lFH > 0 then begin // Repeat if F.Read(lFH,@aBuff,N) <> N then begin Exit; end; for lSrch := 0 to N-1 do begin aSignalR[lSrch] := ShortInt(aBuff[lSrch]+$80); aSignalI[lSrch] := 0; end; imgInfo.Canvas.Rectangle(0,0,imgInfo.Width,imgInfo.Height); DrawSignal(aSignalR, N, $D0D0D0); // ClassicDirect(aSignalR, aSpR, aSpI, N); //result in aSpR & aSpI, aSignal unchanged // FourierDirect(aSignalR, aSignalI, aSpR, aSpI, N); //result in aSpR & aSpI, aSiggnalR & aSignalI modified HartleyDirect(aSignalR, N); //result in source aSignal ;-) DrawSpector(aSignalR, aSignalR[N Div 2 -1], N, $80, $8000); DrawSpector(aSpR, aSpI, N, $80, $8000); { for lSrch := 0 to N div 2 -1 do begin //comparing classic & Hartley if (Abs(aSpR[lSrch] - aSignal[lSrch]) > Epsilon) or ((lSrch > 0) And (Abs(aSpI[lSrch] - aSignal[N - lSrch]) > Epsilon)) then MessageDlg('Error comparing',mtError,[mbOK],-1); end;} HartleyInverce(aSignalR, N); //to restore original signal with HartleyDirect // ClassicInverce(aSpR, aSpI, aSignalR, N); //to restore original signal with ClassicDirect or FourierDirect for lSrch := 0 to N -1 do aSignalR[lSrch]:= aSignalR[lSrch]/N; //scaling DrawSignal(aSignalR, N, $D00000); Application.ProcessMessages; // Until False; end; end; procedure TfmMain.FormCreate(Sender: TObject); begin lFH := F.Open('input.pcm', ForRead); end; procedure TfmMain.FormClose(Sender: TObject; var Action: TCloseAction); begin F.Close(lFH); end; end. |
Denis Furman [000705]