Delphi-int.ru: портал программистов

Вход Регистрация | Забыли пароль?

Просмотр кода

Идентификатор: 2b7d3f01 Описание: FFT Delphi Код загружен: 23 июня 2011, 18:03 (mirt.steelwater)

  1. type
  2. { массив действительных чисел }
  3. PDoubleArray = ^TDoubleArray;
  4. TDoubleArray = array [0..0] of Double;
  5. { функция }
  6. PDoubleFunction = ^TDoubleFunction;
  7. TDoubleFunction = function (const anArray: PDoubleArray;
  8. const X: WORD) : Double;
  9. { параметры вызова функции }
  10. PDoubleFunctionParams = ^TDoubleFunctionParams;
  11. TDoubleFunctionParams = packed record
  12. X1 : WORD;
  13. X2 : WORD;
  14. dX : WORD;
  15. end;
  16.  
  17. function spectr_pool (const anArray: PDoubleArray;
  18. const X: WORD) : Double;
  19. begin
  20. Result := anArray^ [2*x];
  21. end;
  22.  
  23. function fft_pool (const anArray: PDoubleArray;
  24. const X: WORD) : Double;
  25. begin
  26. Result := sqr ( anArray^ [x] );
  27. end;
  28.  
  29. function entropy_pool (const anArray: PDoubleArray;
  30. const X: WORD) : Double;
  31. begin
  32. Result := anArray^ [x];
  33. end;
  34.  
  35. function Frequency (const aValue: Double;
  36. const anArray: PDoubleArray;
  37. const aLength: WORD;
  38. const aPrecision: Double = 0.001) : Double;
  39. var
  40. I : WORD;
  41. Count : WORD;
  42. begin
  43. Result := 0;
  44. try
  45. Count := 0;
  46. for I := 0 to (aLength - 1) do
  47. begin
  48. if ( abs (aValue - anArray^ [I]) <= aPrecision ) then
  49. Inc (Count);
  50. Continue;
  51. end;
  52. Result := Count / aLength;
  53. except on E: Exception do
  54. raise Exception.CreateFmt ('%s : %s',[ERR_FREQUENCY,E.Message]);
  55. end;
  56. end;
  57.  
  58. function Entropy (const anArray: PDoubleArray;
  59. const aLength: WORD;
  60. const aPrecision: Double = 0.001) : Double;
  61. var
  62. I : WORD;
  63. Frq : Double;
  64. begin
  65. Result := 0;
  66. try
  67. for I := 0 to (aLength - 1) do
  68. begin
  69. Frq := Frequency (anArray^ [I],
  70. anArray,
  71. aLength,
  72. aPrecision);
  73. if ( Frq > 0 ) then
  74. Result := Result + Frq * log2 (1/Frq);
  75. Continue;
  76. end;
  77. except on E: Exception do
  78. raise Exception.CreateFmt ('%s : %s',[ERR_ENTROPY,E.Message]);
  79. end;
  80. end;
  81.  
  82. procedure FFT (var anArray: PDoubleArray;
  83. const aLength: WORD;
  84. const doInverse: Boolean = FALSE);
  85. var
  86. nn : WORD;
  87. ii : Integer;
  88. jj : Integer;
  89. n : Integer;
  90. m : Integer;
  91. mMax : Integer;
  92. i : Integer;
  93. j : Integer;
  94. iSign : Integer;
  95. iStep : Integer;
  96. wTemp : Double;
  97. wR : Double;
  98. wI : Double;
  99. wpR : Double;
  100. wpI : Double;
  101. tempR : Double;
  102. tempI : Double;
  103. theta : Double;
  104. begin
  105. try
  106. case doInverse of
  107. TRUE : iSign := 1;
  108. FALSE : iSign := -1;
  109. end;
  110. nn := aLength;
  111. n := 2*nn;
  112. j := 1;
  113. ii := 1;
  114. while ( ii <= nn ) do
  115. begin
  116. i := 2*ii - 1;
  117. if ( j > i ) then
  118. begin
  119. tempR := anArray^ [j-1];
  120. tempI := anArray^ [j];
  121. anArray^ [j-1] := anArray^ [i-1];
  122. anArray^ [j] := anArray^ [i];
  123. anArray^ [i-1] := tempR;
  124. anArray^ [i] := tempI;
  125. end;
  126. m := n div 2;
  127. while ( ( m >= 2) and ( j > m ) ) do
  128. begin
  129. j := j - m;
  130. m := m div 2;
  131. end;
  132. j := j + m;
  133. Inc (ii);
  134. end;
  135. mMax := 2;
  136. while ( n > mMax ) do
  137. begin
  138. iStep := 2*mMax;
  139. theta := 2 * Pi / (iSign*mMax);
  140. wpR := -2.0 * sqr ( sin (0.5*theta) );
  141. wpI := sin (theta);
  142. wR := 1.0;
  143. wI := 0.0;
  144. ii := 1;
  145. while ( ii <= mMax div 2 ) do
  146. begin
  147. m := 2*ii - 1;
  148. jj := 0;
  149. while ( jj <= (n-m) div iStep ) do
  150. begin
  151. i := m + jj*iStep;
  152. j := i + mMax;
  153. tempR := wR * anArray^ [j-1] - wI * anArray^ [j];
  154. tempI := wR * anArray^ [j] + wI * anArray^ [j-1];
  155. anArray^ [j-1] := anArray^ [i-1] - tempR;
  156. anArray^ [j] := anArray^ [i] - tempI;
  157. anArray^ [i-1] := anArray^ [i-1] + tempR;
  158. anArray^ [i] := anArray^ [i] + tempI;
  159. Inc (jj);
  160. end;
  161. wTemp := wR;
  162. wR := wR*wpR - wI*wpI + wR;
  163. wI := wI*wpR + wTemp*wpI + wI;
  164. Inc (ii);
  165. end;
  166. mMax := iStep;
  167. end;
  168. if doInverse then
  169. begin
  170. i := 1;
  171. while ( i <= 2*nn ) do
  172. begin
  173. anArray^ [i-1] := anArray^ [i-1] / nn;
  174. Inc (i);
  175. end;
  176. end;
  177. except on E: Exception do
  178. raise Exception.CreateFmt ('%s : %s',[ERR_FFT,E.Message]);
  179. end;
  180. end;
  181.  
  182. function DrawFunction (const aCanvas: TCanvas;
  183. const aRect: TRect;
  184. const aFunction: TDoubleFunction;
  185. const anArray: PDoubleArray;
  186. const aParams: TDoubleFunctionParams;
  187. const aBackGroundColor: TColor;
  188. const aBackColor: TColor;
  189. const aFrontColor: TColor;
  190. const drawAxes: Boolean = TRUE;
  191. const drawLines: Boolean = TRUE;
  192. const drawSubGraph: Boolean = FALSE) : Boolean;
  193. var
  194. x1, x2 : WORD; { область определения функции }
  195. y1, y2 : Double; { область значения функции }
  196. x : WORD; { локальное значение аргумента }
  197. y : Double; { локальное значение функции }
  198. dx : WORD; { приращение аргумента }
  199. x0, y0 : Integer; { начало координат }
  200. Left : Integer;
  201. Bottom : Integer;
  202. Width : Integer;
  203. Height : Integer;
  204. ScaleX : Double; { масштаб по оси x }
  205. ScaleY : Double; { масштаб по оси y }
  206. begin
  207. Result := FALSE;
  208. try
  209. x1 := aParams.X1;
  210. x2 := aParams.X2;
  211. dx := aParams.dX;
  212. with aCanvas do
  213. begin
  214. Brush.Color := aBackGroundColor;
  215. Pen.Color := aFrontColor;
  216. Rectangle (aRect);
  217. if ( ( x2 < 0 ) or ( x1 < 0 ) ) then
  218. Left := (aRect.Right - aRect.Left) div 2
  219. else
  220. Left := aRect.Left + 8;
  221. Width := (aRect.Right - aRect.Left) - 18;
  222. Bottom := (aRect.Bottom - aRect.Top) - 5;
  223. Height := (aRect.Bottom - aRect.Top) - 22;
  224. y1 := aFunction (anArray,x1);
  225. y2 := aFunction (anArray,x1);
  226. x := x1;
  227. repeat
  228. y := aFunction (anArray,x);
  229. if ( y < y1 ) then
  230. y1 := y;
  231. if ( y > y2 ) then
  232. y2 := y;
  233. x := x + dx;
  234. until ( x >= x2 );
  235. if ( abs (y2-y1) < dx ) then Exit;
  236. ScaleX := Width / abs (x2-x1);
  237. ScaleY := Height / abs (y2-y1);
  238. x0 := Left;
  239. y0 := Bottom - abs ( round (y1*ScaleY) );
  240. if drawAxes then
  241. begin
  242. MoveTo (Left,Bottom);
  243. LineTo ( Left, Bottom-Height );
  244. MoveTo (Left,y0);
  245. LineTo ( x0+Width, y0 );
  246. end;
  247. Pen.Color := aBackColor;
  248. x := x1;
  249. repeat
  250. y := aFunction (anArray,x);
  251. if ( y > dx ) then
  252. Pixels [ x0 + round (x*ScaleX), y0 - round (y*ScaleY)-1 ] := aFrontColor
  253. else
  254. Pixels [ x0 + round (x*ScaleX), y0 - round (y*ScaleY){+1} ] := aFrontColor;
  255. MoveTo ( x0 + round (x*ScaleX), y0 - round (y*ScaleY) );
  256. if not drawLines then
  257. x := x + dx
  258. else
  259. begin
  260. if drawSubGraph then
  261. begin
  262. LineTo ( x0 + round (x*ScaleX), y0 );
  263. x := x + dx;
  264. end
  265. else
  266. begin
  267. x := x + dx;
  268. y := aFunction (anArray,x);
  269. LineTo ( x0 + round (x*ScaleX), y0 - round (y*ScaleY) );
  270. end;
  271. end;
  272. until ( x >= x2 );
  273. Result := TRUE;
  274. end;
  275. except on E: Exception do
  276. raise Exception.CreateFmt ('%s : %s',[ERR_DRAW_FUNCTION,E.Message]);
  277. end;
  278. end;
  279.  
  280. // пример использования
  281. procedure TfmRandomTestDialog.GetData;
  282. var
  283. I : WORD;
  284. Rect : TRect;
  285. Params : TDoubleFunctionParams;
  286. begin
  287. try
  288. { array [2n] + i*array [2n+1] }
  289. for I := 0 to ( 2 * f_PoolLength - 1 ) do
  290. begin
  291. f_Pool^ [I] := TCrypto.Random (f_PoolLength,0,f_RandomType);
  292. f_Pool^ [I+1] := 0;
  293. end;
  294. Rect.Left := 4;
  295. Rect.Right := ptSpectr.Width - 4;
  296. Rect.Top := 4;
  297. Rect.Bottom := ptSpectr.Height - 4;
  298. Params.X1 := 1;
  299. Params.X2 := f_PoolLength;
  300. Params.dX := 2;
  301. DrawFunction (ptSpectr.Canvas,
  302. Rect,
  303. spectr_pool,
  304. f_Pool,
  305. Params,
  306. clBlack,
  307. clMaroon,
  308. clRed,
  309. TRUE,
  310. FALSE);
  311.  
  312. if f_EntropyPoolIndex >= f_EntropyPoolLength then
  313. f_EntropyPoolIndex := 0;
  314. Inc (f_EntropyPoolIndex);
  315. f_EntropyPool^ [f_EntropyPoolIndex] := Entropy ( f_Pool, 2*f_PoolLength );
  316. Rect.Left := 4;
  317. Rect.Right := ptEntropy.Width - 4;
  318. Rect.Top := 4;
  319. Rect.Bottom := ptEntropy.Height - 4;
  320. Params.X1 := 0;
  321. Params.X2 := f_EntropyPoolLength div 2;
  322. Params.dX := 1;
  323. DrawFunction (ptEntropy.Canvas,
  324. Rect,
  325. entropy_pool,
  326. f_EntropyPool,
  327. Params,
  328. clBlack,
  329. clMaroon,
  330. clRed,
  331. TRUE,
  332. TRUE,
  333. TRUE);
  334.  
  335. FFT (f_Pool,f_PoolLength);
  336. Rect.Left := 4;
  337. Rect.Right := ptFFT.Width - 4;
  338. Rect.Top := 4;
  339. Rect.Bottom := ptFFT.Height - 4;
  340. Params.X1 := 2;
  341. Params.X2 := f_PoolLength;
  342. Params.dX := 1;
  343. DrawFunction (ptFFT.Canvas,
  344. Rect,
  345. fft_pool,
  346. f_Pool,
  347. Params,
  348. clBlack,
  349. clMaroon,
  350. clRed,
  351. TRUE,
  352. TRUE,
  353. TRUE);
  354. except on E: Exception do
  355. raise EClass.Create ([self,'GetData',ERR_TFMRANDOMTESTDIALOG_GET_DATA,E],
  356. ['{649B92D2-A503-4A91-B356-E790FAAF526D}']);
  357. end;
  358. end;

Ссылка на данный код:

На главную страницу сервиса обмена кодом »