1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
| .386
.model flat,stdcall
option casemap:none
include windows.inc
include kernel32.inc
include user32.inc
include gdi32.inc
includelib kernel32.lib
includelib user32.lib
includelib gdi32.lib
.const
N equ 512
SIZE_X_CLIENT equ N + 30
SIZE_Y_CLIENT equ 480
lgN equ 9
.data
ClassName db "FFTClass",0
AppName db "FFT sin Hz27:Amp10 + Hz32:Amp20 + Hz148:Amp30",0
F dword 2 * N dup (0)
F2 dword 2 * N dup (0)
W dword 2 * N dup (0)
Fout dword 2 * N dup (0)
.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hFile HANDLE ?
Pen dd ?
Brush dd ?
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
GenerateF proto :LPDWORD, :DWORD, :DWORD, :DWORD ;функция генерирование синусоиды
SumF proto :LPDWORD, :LPDWORD ;функция суммирования сигналов
FFT_make proto :DWORD, :LPDWORD, :BOOL ;функция расчёта поворотных множителей для БПФ
FFT_binary_inversion proto :DWORD ;функция бинарной инверсии индекса
FFT_calc proto :LPDWORD, :LPDWORD, :LPDWORD, :BOOL ;БПФ
.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke GetCommandLine
mov CommandLine,eax
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
invoke ExitProcess,eax
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc :WNDCLASSEX
LOCAL msg :MSG
LOCAL hwnd :HWND
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.lpszMenuName,NULL
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, ADDR wc
INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
CW_USEDEFAULT,SIZE_X_CLIENT,SIZE_Y_CLIENT,NULL,NULL,\
hInst,NULL
mov hwnd,eax
invoke ShowWindow, hwnd,SW_SHOWNORMAL
invoke UpdateWindow, hwnd
.WHILE TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam
ret
WinMain endp
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL Ps :PAINTSTRUCT
LOCAL Rect :RECT
LOCAL hDC,hCDC :HDC
LOCAL X,Y,p,my,dwBytes :DWORD
.IF uMsg==WM_CREATE
invoke GenerateF,ADDR F,N,27,10
invoke GenerateF,ADDR F2,N,32,20
invoke SumF,ADDR F,ADDR F2
invoke GenerateF,ADDR F2,N,148,30
invoke SumF,ADDR F,ADDR F2 ;суммирование синусоид
invoke CreatePen, PS_SOLID, 0, 04040FFh
mov [Pen],eax
invoke CreateSolidBrush, 0FFFFFFh
mov [Brush], eax
.ELSEIF uMsg==WM_PAINT
invoke BeginPaint, [hWnd], ADDR Ps
mov [hDC], eax
invoke CreateCompatibleDC, [hDC]
mov [hCDC], eax
invoke SelectObject, [hDC], [Pen]
invoke SelectObject, [hDC], [Brush]
invoke GetClientRect,hWnd,ADDR Rect
;вывод сигнала
mov ebx,Rect.bottom
shr ebx,2
mov Y,ebx
mov X,10
invoke MoveToEx, [hDC], N + 10,ebx, 0
invoke LineTo, [hDC], X , ebx
lea esi,F
.WHILE [X] != N + 10
fld dword ptr [esi]
fistp dword ptr [p]
mov ebx,Y
sub ebx,dword ptr [p]
invoke LineTo, [hDC], X, ebx
inc X
add esi,8
.ENDW
;true = БПФ
invoke FFT_make,N,ADDR W,TRUE
invoke FFT_calc,ADDR W,ADDR F,ADDR Fout,TRUE
;вывод результата преобразования
mov eax,Rect.bottom
shr eax,2
imul eax,eax,3
mov Y,eax
mov X,10
invoke MoveToEx, [hDC], N + 10,Y, 0
invoke LineTo, [hDC], X , Y
lea esi,Fout
mov my,5
.WHILE [X] != N /2 + 10
fld dword ptr [esi+4]
fchs
fild dword ptr my
fmulp st(1),st
fistp dword ptr [p]
mov ebx,Y
sub ebx,dword ptr [p]
; invoke MoveToEx, [hDC], X,Y, 0
invoke LineTo, [hDC], X, ebx
inc X
add esi,8
.ENDW
.ELSEIF uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp
; суммирование сигналов
SumF proc lpF1:LPDWORD, lpF2:LPDWORD
mov cx,N
mov esi,lpF1 ;буфер 1 и 2 волны
mov edi,lpF2
@@:
fld dword ptr [esi]
fld dword ptr [edi]
faddp st(1),st ;суммирование Re через FPU
fstp dword ptr [esi]
add esi,8
add edi,8
loop @b
Ret
SumF EndP
:генерирование выборок синусоиды с заданной частотой и амплитудой
GenerateF proc lpF:LPDWORD, Len:DWORD, Freq:DWORD, Amp:DWORD
LOCAL T:DWORD
fild Amp ;занести амплитуду в сопроцессор
fldpi ;занести Pi
fild Len ;число отсчетов = N
;расчет периода
fild Freq ;занести частоту
fdivp st(1),st ;period = число отсчетов / частоту
fld1
fadd st,st ;
fdivp st(1),st ;ST < period / 2
fdivp st(1),st ;ST < Pi / period / 2 - множитель в радианах
mov esi,lpF
xor edi,edi
mov T,0
.WHILE [T] != N
fild dword ptr [T] ;занести T
fmul st,st(1) ;T * Pi / period / 2
fsin ;взять sin
fmul st,st(2) ;* на амплитуду
fstp dword ptr [esi];сохранить в буффер как Re
add esi,8
inc [T]
.ENDW
Ret
GenerateF EndP
; функция расчёта поворотных множителей для БПФ
FFT_make proc Len:DWORD, lpW: LPDWORD, flag: BOOL
fldpi
fld1
fadd st,st
fmulp st(1),st ;2Pi
fild Len
fdivp st(1),st ;2Pi/Len
fld st
fchs
mov esi,lpW ;адрес массива множителей
mov ecx,0
.WHILE ecx != Len
fadd st,st(1)
fld st
fsincos
fstp dword ptr [esi] ;Re <- cos
add esi,4
.IF flag == TRUE
fchs ;если прямое БПФ,взять противоположный sin
.ENDIF
fstp dword ptr [esi] ;Im <- sin
add esi,4
inc ecx
.ENDW
Ret
FFT_make EndP
; функция бинарной инверсии индекса
FFT_binary_inversion proc i: DWORD
; int j = 0 ;
; while (p-- > 0)
; {
; j <<= 1 ;
; j |= i & 1;
; i >>= 1;
; }
xor eax,eax
mov ebx,i
mov ecx,lgN
.WHILE ecx != 0
shl eax,1
push ebx
and ebx,1
or eax,ebx
pop ebx
shr ebx,1
dec ecx
.ENDW
Ret ;return eax
FFT_binary_inversion EndP
FFT_calc proc lpW:LPDWORD, lpIn:LPDWORD, lpOut:LPDWORD, flag:BOOL
LOCAL i, j, k, y, z, h, r, m, nom, n, n2 :DWORD
LOCAL re, im, re1, im1, re2, im2 :DWORD
mov n, N ; число точек БПФ
mov n2, N / 2; n/2
mov i,0
mov esi,lpIn
mov edi,lpOut
; копировать элементы массива `in` в массив `out` с битовой инверсией
.WHILE i < N
invoke FFT_binary_inversion,i
shl eax,3 ;j
mov ebx,i ;k
shl ebx,3
push [esi + eax]
pop [edi + ebx]
push [esi + eax + 4]
pop [edi + ebx + 4]
push [esi + ebx]
pop [edi + eax]
push [esi + ebx + 4]
pop [edi + eax + 4]
inc i
.ENDW
; выполнение бабочек
mov i,0
.WHILE i < lgN
mov eax,i
inc eax
mov m,0
bts m,eax ;через сколько эл-тов бабочка * 2
mov eax,m
shl eax,1
mov r,eax ;размер группы * 2
mov nom,0 ;номер группы * r
mov k,0 ;номер эл-та в группе * 2
mov y,0 ;индекс W * 2
mov z,0
mov eax,lgN
sub eax,i
mov h,0
bts h,eax ;шаг для W * 2 = 1 << (lgN - i)
mov eax,n2
mov j,eax
mov esi,lpW
.WHILE j > 0
mov eax,k
.IF eax>=m
mov y,0
mov k,0
mov eax,r
add nom,eax
mov eax,nom
mov z,eax
.ENDIF
; c <= W[y]
mov eax,y
push dword ptr [esi+4*eax]
pop re
push dword ptr [esi+4*eax+4]
pop im
; c2 <= Fout[z + m]
mov eax,z
add eax,m
push [edi+4*eax]
pop re2
push [edi+4*eax+4]
pop im2
add eax,1
push eax ;z + m
; c1 <= c2 * c
fld dword ptr [re2]
fld dword ptr [re]
fmulp st(1),st
fld dword ptr im2
fld dword ptr im
fmulp st(1),st
fsubp st(1),st
fstp dword ptr re1
fld dword ptr im2
fld dword ptr re
fmulp st(1),st
fld dword ptr re2
fld dword ptr im
fmulp st(1),st
faddp st(1),st
fstp dword ptr im1
; c2 <= Fout[z]
mov eax,z
push [edi+4*eax]
pop re2
push [edi+4*eax+4]
pop im2
add eax,1
; Fout[z] <= c2 + c1
; F out[z + m] <= c2 - c1
pop ebx ; z + m
fld dword ptr im2
fld dword ptr im1
fld st
fadd st,st(2)
fstp dword ptr [edi +4* eax]
fsubp st(1),st
fstp dword ptr [edi + 4*ebx]
fld dword ptr re2
fld dword ptr re1
fld st
fadd st,st(2)
fstp dword ptr [edi + 4*eax - 4]
fsubp st(1),st
fstp dword ptr [edi + 4*ebx - 4]
add k,2
add z,2
mov eax,h
add y,eax
dec j
.ENDW
inc i
.ENDW
;нормировка если прямое БПФ
.IF flag == TRUE
fld1
fild dword ptr n
fdivp st(1),st
fstp dword ptr re
fld re ;re = 1. / N;
.WHILE n > 0
fld dword ptr [edi]
fmul st,st(1)
fstp dword ptr [edi]
add edi,4
fld dword ptr [edi]
fmul st,st(1)
fstp dword ptr [edi]
add edi,4
dec n
.ENDW
.ENDIF
Ret
FFT_calc EndP
end start |