uCPUFFT.pas 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. (*
  2. This FFT demo code from http://www.vssoft.bg.
  3. Contact at [email protected].
  4. 06 June 2009
  5. *)
  6. unit uCPUFFT;
  7. interface
  8. uses
  9. System.SysUtils,
  10. System.Types,
  11. System.Math;
  12. type
  13. TProcessMode = (module, phase, real, imag);
  14. TComplex = record
  15. real, imag: Double;
  16. end;
  17. PComplexArray = ^TComplexDynArray;
  18. TComplexDynArray = array of TComplex;
  19. TComplex2DArray = array of TComplexDynArray;
  20. TByte2DArray = array of TByteDynArray;
  21. // perform fft (sgn=1) or inverse fft (sgn=-1) on cx[nx]
  22. procedure ftu(sgn: TValueSign; nx: integer; cx: TComplexDynArray); overload;
  23. // perform 2Dfft (sgn=1) or inverse 2Dfft (sgn=-1) on cx[len,len]
  24. procedure ftu(sgn: TValueSign; len: integer; cArr: TComplex2DArray); overload;
  25. // reorder quadrants to move 0 to the center (after fft on real signal)
  26. procedure Reorder(inp: TComplexDynArray); overload; // 1D
  27. procedure Reorder(inp: TComplex2DArray); overload // 2D
  28. // normalize cArr to [0,255] using function defined by mode and store result in buf
  29. // on return, cArr.Real contains result before normalization
  30. procedure Normalize(cArr: TComplexDynArray; buf: TByteDynArray;
  31. mode: TProcessMode); overload; // 1D
  32. procedure Normalize(cArr: TComplex2DArray; buf: TByte2DArray;
  33. mode: TProcessMode); overload; // 2D
  34. //-----------------------------------------
  35. implementation
  36. //-----------------------------------------
  37. // some complex arithmetic
  38. function CAdd(c1, c2: TComplex): TComplex;
  39. begin
  40. Result.Real := c1.Real + c2.Real;
  41. Result.imag := c1.imag + c2.imag;
  42. end;
  43. function CSubt(c1, c2: TComplex): TComplex;
  44. begin
  45. Result.Real := c1.Real - c2.Real;
  46. Result.imag := c1.imag - c2.imag;
  47. end;
  48. function CMult(c1, c2: TComplex): TComplex; overload;
  49. begin
  50. Result.Real := c1.Real * c2.Real - c1.imag * c2.imag;
  51. Result.imag := c1.Real * c2.imag + c1.imag * c2.Real;
  52. end;
  53. function CMult(c: TComplex; i: integer): TComplex; overload;
  54. begin
  55. Result.Real := c.Real * i;
  56. Result.imag := c.imag * i;
  57. end;
  58. function CMult(c: TComplex; d: Double): TComplex; overload;
  59. begin
  60. Result.Real := c.Real * d;
  61. Result.imag := c.imag * d;
  62. end;
  63. // return y = 2^i >= n
  64. function pad2(n: integer): integer;
  65. begin
  66. Result := 1;
  67. while (Result < n) do
  68. Result := Result * 2;
  69. end;
  70. (*
  71. Complex fourier transform with unitary scaling:
  72. 1 nx-1 sgn*2*pi*i * j*(k-1)/nx
  73. cx(k) = -------- * sum cx(j) * e
  74. sqrt(nx) j=0 for k=1,2,...,nx=2**integer
  75. In some applications the scale factor 1/sqrt(nx) is omitted in fft: factor=1,
  76. wheras in the inverse fft, it is set to: factor=1/nx.
  77. *)
  78. // Apply fft/ifft on cArr[nx] and store result in cArr:
  79. procedure ftu(sgn: TValueSign; nx: integer; cx: TComplexDynArray);
  80. var
  81. scale, arg: Double;
  82. cw, cdel, ct: TComplex;
  83. i, j, k, m, istep: integer;
  84. begin
  85. if (nx <> pad2(nx)) then
  86. raise Exception.Create('ftu: number of samples is not a power of 2');
  87. scale := 1 / sqrt(nx);
  88. for i := 0 to nx - 1 do
  89. cx[i] := CMult(cx[i], scale);
  90. j := 0;
  91. for i := 0 to nx - 1 do
  92. begin
  93. if (i <= j) then
  94. begin
  95. ct := cx[j];
  96. cx[j] := cx[i];
  97. cx[i] := ct;
  98. end;
  99. m := nx div 2;
  100. while ((j >= m) and (m > 1)) do
  101. begin
  102. j := j - m;
  103. m := m div 2;
  104. end;
  105. j := j + m;
  106. end;
  107. k := 1;
  108. repeat
  109. istep := 2 * k;
  110. cw.Real := 1;
  111. cw.imag := 0;
  112. arg := sgn * Pi / k;
  113. cdel.Real := cos(arg);
  114. cdel.imag := sin(arg);
  115. for m := 0 to k - 1 do
  116. begin
  117. i := m;
  118. while i < nx do
  119. begin // for i=m to nx step istep
  120. ct := CMult(cw, cx[i + k]);
  121. cx[i + k] := CSubt(cx[i], ct);
  122. cx[i] := CAdd(cx[i], ct);
  123. Inc(i, istep);
  124. end;
  125. cw := CMult(cw, cdel);
  126. end;
  127. k := istep;
  128. until (k >= nx);
  129. end;
  130. (* first apply 1D ftu on cArr rows and then on cArr cols; store result in cArr *)
  131. procedure ftu(sgn: TValueSign; len: integer; cArr: TComplex2DArray);
  132. var
  133. i, j: integer;
  134. tmp: TComplexDynArray;
  135. begin
  136. // apply forward fft
  137. for i := 0 to len - 1 do // fft rows: up-down
  138. ftu(sgn, len, cArr[i]);
  139. // fft cols: left-right; uses tmp[rows]
  140. SetLength(tmp, len);
  141. for i := 0 to len - 1 do
  142. begin // for each col
  143. for j := 0 to len - 1 do // copy the i-th col of inp[rows,cols] to tmp[rows]
  144. tmp[j] := cArr[j, i];
  145. ftu(sgn, len, tmp); // fft on the i-th col
  146. for j := 0 to len - 1 do // copy result back from tmp to inp
  147. cArr[j, i] := tmp[j];
  148. end;
  149. end;
  150. procedure Reorder(inp: TComplexDynArray); overload; // 1D
  151. var
  152. tmp: TComplexDynArray;
  153. i, h, w: integer;
  154. begin
  155. w := Length(inp);
  156. h := w div 2;
  157. SetLength(tmp, h);
  158. for i := 0 to h - 1 do
  159. tmp[i] := inp[i + h];
  160. for i := 0 to h - 1 do
  161. inp[i + h] := inp[i];
  162. for i := 0 to h - 1 do
  163. inp[i] := tmp[i];
  164. end;
  165. procedure Reorder(inp: TComplex2DArray);
  166. overload // 2D
  167. var
  168. tmp: TComplex2DArray;
  169. i, j, h, w: integer;
  170. begin
  171. w := Length(inp);
  172. h := w div 2;
  173. SetLength(tmp, h, h);
  174. // left,up->tmp
  175. for i := 0 to h - 1 do
  176. for j := 0 to h - 1 do
  177. tmp[i, j] := inp[i, j];
  178. // down,right->left,up
  179. for i := 0 to h - 1 do
  180. for j := 0 to h - 1 do
  181. inp[i, j] := inp[i + h, j + h];
  182. // tmp->down,right
  183. for i := 0 to h - 1 do
  184. for j := 0 to h - 1 do
  185. inp[i + h, j + h] := tmp[i, j];
  186. // right,up->tmp
  187. for i := 0 to h - 1 do
  188. for j := 0 to h - 1 do
  189. tmp[i, j] := inp[i + h, j];
  190. // down,left->right,up
  191. for i := 0 to h - 1 do
  192. for j := 0 to h - 1 do
  193. inp[i + h, j] := inp[i, j + h];
  194. // tmp->down,left
  195. for i := 0 to h - 1 do
  196. for j := 0 to h - 1 do
  197. inp[i, j + h] := tmp[i, j];
  198. end;
  199. procedure Normalize(cArr: TComplexDynArray; buf: TByteDynArray;
  200. mode: TProcessMode); // 1D
  201. var
  202. j, len: integer;
  203. m, n, r: Double;
  204. begin
  205. len := Length(cArr); // len := Length(cArr)-1;
  206. // find max and min values of cArr to normalize result
  207. m := MinDouble;
  208. n := MaxDouble;
  209. for j := 0 to len - 1 do
  210. begin // for j:=1 to len do begin
  211. case mode of
  212. module:
  213. r := Hypot(cArr[j].Real, cArr[j].imag);
  214. phase:
  215. r := ArcTan2(cArr[j].imag, cArr[j].Real);
  216. real:
  217. r := cArr[j].Real;
  218. else
  219. r := cArr[j].imag;
  220. end;
  221. if m < r then
  222. m := r;
  223. if n > r then
  224. n := r;
  225. // reuse real part of cArr to store result
  226. cArr[j].Real := r;
  227. end;
  228. // normalize result in cArr.Real to [0,255] and copy it to buf
  229. for j := 0 to len - 1 do
  230. buf[j] := Trunc(255 * (cArr[j].Real - n) / (m - n));
  231. end;
  232. procedure Normalize(cArr: TComplex2DArray; buf: TByte2DArray;
  233. mode: TProcessMode); // 2D
  234. var
  235. i, j, len: integer;
  236. m, n, r: Double;
  237. begin
  238. len := Length(cArr);
  239. m := MinDouble;
  240. n := MaxDouble;
  241. for i := 0 to len - 1 do
  242. for j := 0 to len - 1 do
  243. begin
  244. case mode of
  245. module:
  246. r := Hypot(cArr[i, j].Real, cArr[i, j].imag);
  247. phase:
  248. r := ArcTan2(cArr[i, j].imag, cArr[i, j].Real);
  249. real:
  250. r := cArr[i, j].Real;
  251. else
  252. r := cArr[i, j].imag;
  253. end;
  254. if m < r then
  255. m := r;
  256. if n > r then
  257. n := r;
  258. cArr[i, j].Real := r;
  259. end;
  260. for i := 0 to len - 1 do // move cArr[Real] -> buf
  261. for j := 0 to len - 1 do
  262. buf[i, j] := Trunc(255 * (cArr[i, j].Real - n) / (m - n));
  263. end;
  264. end.