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
|
/*
* Copyright (c) 2020-2023 Vasile Vilvoiu <vasi@vilvoiu.ro>
*
* specgram is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include "test.hpp"
#include "../src/fft.hpp"
#include <vector>
#include <cmath>
void run_tests(const std::vector<double>& freqs, std::vector<ComplexWindow>& expected, std::size_t window_size, double fs)
{
constexpr double epsilon = 1e-9;
FFT fft(window_size);
for (std::size_t i = 0; i < freqs.size(); i++) {
auto f = freqs[i];
auto& exp = expected[i];
/* build input sinusoid */
ComplexWindow input(window_size);
for (std::size_t j = 0; j < window_size; j++) {
double ang = 2.0 * (double)M_PI * f * (double)j / fs;
input[j] = std::exp(std::complex<double>(0.0, ang)); /* e^jWt */
}
/* run fft */
auto out = fft.Compute(input);
/* check output */
EXPECT_EQ(exp.size(), out.size());
EXPECT_EQ(out.size(), input.size());
for (std::size_t j = 0; j < window_size; j++) {
EXPECT_LE(std::abs(out[j] - exp[j]), epsilon);
}
}
}
TEST(TestFFT, Widths)
{
std::unique_ptr<WindowFunction> wf = nullptr;
EXPECT_THROW_MATCH(FFT(0), std::runtime_error, "cannot compute zero-width fft");
EXPECT_THROW_MATCH(FFT(0, wf), std::runtime_error, "cannot compute zero-width fft");
for (std::size_t i = 1; i <= 1024; i ++) {
EXPECT_NO_THROW(FFT((std::size_t)i));
EXPECT_NO_THROW(FFT(i, wf));
}
}
TEST(TestFFT, SineWaveNumPyEven)
{
constexpr std::size_t window_size = 64;
constexpr double fs = 100.0;
const std::vector<double> freqs = { 3.0, 7.0, 20.4, 73.99 };
/* np.fft.fft */
/* x = np.exp(1j*np.arange(64)/100.*2.*np.pi*freq) */
/* y = np.roll(np.fft.fft(x, norm='backward')/64, 31) */
/* ', '.join([ 'std::complex<double>(' + str(np.real(v)) + ', ' + str(np.imag(v)) + ')' for v in y ]) */
std::vector<ComplexWindow> expected;
expected.push_back( { std::complex<double>(0.0011364399082407842, 0.0037200299561292), std::complex<double>(0.0009515739685700964, 0.003767495461954984), std::complex<double>(0.0007666366858405313, 0.0038149792855649307), std::complex<double>(0.0005807326673174448, 0.0038627113247387073), std::complex<double>(0.00039294770741610426, 0.003910926307574688), std::complex<double>(0.0002023305738351848, 0.003959868469016735), std::complex<double>(7.873227389015858e-06, 0.004009796629537003), std::complex<double>(-0.00019151142249060338, 0.004060989906553259), std::complex<double>(-0.0003970153117394664, 0.004113754337198283), std::complex<double>(-0.0006099659314767868, 0.004168430763259982), std::complex<double>(-0.0008318637302816663, 0.0042254044344547485), std::complex<double>(-0.0010644285791935196, 0.00428511693861086), std::complex<double>(-0.001309658530696504, 0.0043480812884119455), std::complex<double>(-0.0015699053626786605, 0.004414901317788825), std::complex<double>(-0.0018479732652960683, 0.0044862970204000395), std::complex<double>(-0.0021472498398232825, 0.004563138184418895), std::complex<double>(-0.0024718828905209034, 0.004646489784971126), std::complex<double>(-0.002827023244774289, 0.00473767432974892), std::complex<double>(-0.0032191646691682304, 0.0048383591346257745), std::complex<double>(-0.0036566297886540073, 0.00495068108649286), std::complex<double>(-0.004150281185257748, 0.005077429222375069), std::complex<double>(-0.0047145899789468575, 0.005222319094366223), std::complex<double>(-0.005369291107001319, 0.00539041777313413), std::complex<double>(-0.006142039359728516, 0.005588825801984906), std::complex<double>(-0.007072851572963645, 0.005827817758040963), std::complex<double>(-0.008221913702292494, 0.006122846768203896), std::complex<double>(-0.009684156610423107, 0.006498286935269102), std::complex<double>(-0.011618604162275184, 0.006994968648004948), std::complex<double>(-0.014313511187830565, 0.007686903167415906), std::complex<double>(-0.018351201842187338, 0.008723605924119329), std::complex<double>(-0.025111616221004485, 0.010459385314601924), std::complex<double>(-0.03884943914885365, 0.013986658728932906), std::complex<double>(-0.08231771909233432, 0.025147416078666444), std::complex<double>(0.95937990970918, -0.24231507569610178), std::complex<double>(0.07189379317136724, -0.014447370536964653), std::complex<double>(0.03770042078488748, -0.0056680046943137045), std::complex<double>(0.025670374048391335, -0.002579213679197473), std::complex<double>(0.019506938565479675, -0.0009967124172436687), std::complex<double>(0.015745410182965915, -3.091608032949975e-05), std::complex<double>(0.013200453994817302, 0.0006225176078349299), std::complex<double>(0.011356379185922846, 0.0010959955440124685), std::complex<double>(0.009952754098296613, 0.0014563852128320846), std::complex<double>(0.008843843711810469, 0.001741105007640234), std::complex<double>(0.007941715067969864, 0.0019727322748162327), std::complex<double>(0.007190151809250908, 0.0021657009217110022), std::complex<double>(0.006551524849122958, 0.0023296724556261393), std::complex<double>(0.005999685441054965, 0.002471360733549074), std::complex<double>(0.005515886531187638, 0.002595579180796733), std::complex<double>(0.005086326665187485, 0.002705871408550906), std::complex<double>(0.004700610083005978, 0.0028049065943252516), std::complex<double>(0.004350747480765651, 0.002894736042705284), std::complex<double>(0.004030488072764764, 0.0029769646826770663), std::complex<double>(0.003734861364865074, 0.0030528687202249563), std::complex<double>(0.003459855484679161, 0.0031234782291011363), std::complex<double>(0.0032021866679220207, 0.0031896363366720375), std::complex<double>(0.002959130939720979, 0.0032520424408114556), std::complex<double>(0.0027283990564880324, 0.0033112843193710976), std::complex<double>(0.0025080420506775284, 0.0033678623821644955), std::complex<double>(0.0022963787420282084, 0.0034222082829168015), std::complex<double>(0.002091939208738067, 0.0034746994333995805), std::complex<double>(0.0018934199633289022, 0.0035256705123138197), std::complex<double>(0.0016996477623491442, 0.0035754227573778835), std::complex<double>(0.0015095497899669345, 0.003624231620879917), std::complex<double>(0.001322128515090823, 0.0036723532252726683) } );
expected.push_back( { std::complex<double>(0.015394484773502443, -0.003663934604759035), std::complex<double>(0.015443603310133213, -0.00288321782161588), std::complex<double>(0.015492134943749819, -0.002111829594752479), std::complex<double>(0.015540320780970895, -0.0013459376442006565), std::complex<double>(0.015588395174029082, -0.0005818170478977258), std::complex<double>(0.015636590313811462, 0.00018422276263238557), std::complex<double>(0.01568514073330553, 0.000955909582467343), std::complex<double>(0.015734287908151713, 0.0017370815570099327), std::complex<double>(0.01578428514798632, 0.0025317649276281884), std::complex<double>(0.015835402993370558, 0.0033442598134123536), std::complex<double>(0.01588793537078272, 0.004179238041944349), std::complex<double>(0.0159422068167067, 0.005041857972922649), std::complex<double>(0.015998581168423967, 0.0059379026343396625), std::complex<double>(0.0160574722447201, 0.006873949487429545), std::complex<double>(0.016119357221469822, 0.007857583025538377), std::complex<double>(0.0161847936715469, 0.008897665615713115), std::complex<double>(0.016254441627466986, 0.010004688174372119), std::complex<double>(0.016329092605494346, 0.011191231492263268), std::complex<double>(0.016409708410620165, 0.012472583021960075), std::complex<double>(0.0164974739047916, 0.013867575604812929), std::complex<double>(0.01659387007725687, 0.01539974889083763), std::complex<double>(0.01670077725371774, 0.01709898980122534), std::complex<double>(0.01682062411495451, 0.019003901111547754), std::complex<double>(0.016956608237465854, 0.02116530684486247), std::complex<double>(0.017113031783737315, 0.023651587915709527), std::complex<double>(0.017295829270435478, 0.026557070765379616), std::complex<double>(0.017513429258618714, 0.030015723535583322), std::complex<double>(0.017778225622740618, 0.03422454121961255), std::complex<double>(0.01810922887294037, 0.039485687223377405), std::complex<double>(0.018537172292258403, 0.04628765309236464), std::complex<double>(0.01911520861393116, 0.05547527732857178), std::complex<double>(0.019943932470583528, 0.06864746583131454), std::complex<double>(0.021239544836988068, 0.08924063468939517), std::complex<double>(0.02356693123826964, 0.12623338221357489), std::complex<double>(0.029017651284121607, 0.2128700964137203), std::complex<double>(0.05711279641733627, 0.6594296406285025), std::complex<double>(-0.02278866396570616, -0.6105677045200859), std::complex<double>(0.0024644660463094426, -0.20918069709614537), std::complex<double>(0.007688175321638846, -0.1261522157681113), std::complex<double>(0.009953028540956447, -0.09015340470888761), std::complex<double>(0.0112229099600279, -0.06996921754706792), std::complex<double>(0.012038610989258711, -0.057004020958770885), std::complex<double>(0.012609159335509688, -0.047935414683695096), std::complex<double>(0.013032406872230898, -0.04120808773122451), std::complex<double>(0.013360274000072586, -0.03599678896491597), std::complex<double>(0.013622873670902385, -0.03182288672092623), std::complex<double>(0.013838876520537552, -0.028389619740997345), std::complex<double>(0.01402047755267639, -0.02550315399197398), std::complex<double>(0.01417598268165322, -0.023031470746001335), std::complex<double>(0.014311247461769018, -0.020881498632650833), std::complex<double>(0.014430521363548547, -0.018985694252115208), std::complex<double>(0.014536965721127323, -0.017293809637202603), std::complex<double>(0.014632983634032088, -0.015767648614726584), std::complex<double>(0.014720436964990286, -0.01437761772406444), std::complex<double>(0.014800793118436337, -0.01310039323963546), std::complex<double>(0.01487522679248349, -0.011917303869602224), std::complex<double>(0.014944692077488369, -0.010813184781997342), std::complex<double>(0.01500997456183012, -0.00977554940710674), std::complex<double>(0.01507172967648382, -0.00879397996790611), std::complex<double>(0.015130511393664356, -0.007859671328183274), std::complex<double>(0.015186794055997132, -0.006965084027800366), std::complex<double>(0.015240989246876115, -0.006103676136053813), std::complex<double>(0.015293459041738653, -0.005269692628663593), std::complex<double>(0.015344526597075839, -0.004457997080287789) } );
expected.push_back( { std::complex<double>(-0.0013311701662158028, -0.0030142476899852853), std::complex<double>(-0.0011452714264404205, -0.002981201026649672), std::complex<double>(-0.0009700718013955249, -0.0029500563129613504), std::complex<double>(-0.0008038956699534909, -0.0029205156787601655), std::complex<double>(-0.0006453189939982693, -0.002892325977047894), std::complex<double>(-0.0004931156098721213, -0.0028652692363728147), std::complex<double>(-0.00034621543704313473, -0.0028391552317208234), std::complex<double>(-0.00020367141713458197, -0.0028138156073530037), std::complex<double>(-6.463288937355507e-05, -0.0027890991438463426), std::complex<double>(7.167628108784019e-05, -0.0027648678700293735), std::complex<double>(0.00020597608456480662, -0.0027409937953751483), std::complex<double>(0.00033894622963263205, -0.0027173560901221218), std::complex<double>(0.00047124025971650996, -0.002693838575809057), std::complex<double>(0.0006034985633776302, -0.002670327412475364), std::complex<double>(0.0007363608368734509, -0.0026467088832294668), std::complex<double>(0.000870478518050468, -0.0026228671839123863), std::complex<double>(0.0010065277085762308, -0.002598682125951275), std::complex<double>(0.0011452231367036422, -0.002574026654241341), std::complex<double>(0.0012873337890297555, -0.0025487640683331176), std::complex<double>(0.0014337009658463504, -0.0025227448127883656), std::complex<double>(0.0015852597054426781, -0.0024958026686468736), std::complex<double>(0.0017430648017551648, -0.0024677501283395884), std::complex<double>(0.001908323043682771, -0.0024383726646143716), std::complex<double>(0.0020824338896707558, -0.0024074214999246822), std::complex<double>(0.0022670416463932254, -0.0023746043307883366), std::complex<double>(0.0024641034852182953, -0.0023395732366999966), std::complex<double>(0.002675979530417344, -0.0023019086654237197), std::complex<double>(0.0029055541600099717, -0.0022610978696988126), std::complex<double>(0.003156402199952918, -0.002216505363400137), std::complex<double>(0.0034330209488157267, -0.0021673316752035448), std::complex<double>(0.003741160875204245, -0.0021125545614914996), std::complex<double>(0.004088307944165389, -0.0020508432646349317), std::complex<double>(0.004484405659941753, -0.001980430157601267), std::complex<double>(0.004942968643374146, -0.001898912786639317), std::complex<double>(0.00548286033299387, -0.0018029378546630145), std::complex<double>(0.006131248194898636, -0.001687675882424894), std::complex<double>(0.006928759636159937, -0.0015459046572012139), std::complex<double>(0.007939021894871619, -0.00136631335505272), std::complex<double>(0.009267653285779113, -0.0011301265238509491), std::complex<double>(0.011103791178529516, -0.0008037217787076048), std::complex<double>(0.01382305150037558, -0.00032032699891681136), std::complex<double>(0.01829263337360936, 0.00047421721150983425), std::complex<double>(0.02706680626211775, 0.0020339757006903707), std::complex<double>(0.05237493648493236, 0.006532926366681464), std::complex<double>(0.9799694750269432, 0.1714286349868916), std::complex<double>(-0.05758529793130559, -0.013014375844271345), std::complex<double>(-0.027651517165224123, -0.007693137106855444), std::complex<double>(-0.018023141611111626, -0.0059815295629484615), std::complex<double>(-0.013254777260254676, -0.005133871684506283), std::complex<double>(-0.010397268142001426, -0.004625900829391433), std::complex<double>(-0.008486055284365222, -0.004286150232131929), std::complex<double>(-0.007112174634320465, -0.004041919575378426), std::complex<double>(-0.006072561511598134, -0.003857110657862203), std::complex<double>(-0.005254944933332008, -0.003711765402526431), std::complex<double>(-0.004592194116968747, -0.003593950170804075), std::complex<double>(-0.004041694154121686, -0.0034960894378036674), std::complex<double>(-0.0035750820366855863, -0.003413141196349112), std::complex<double>(-0.003172740232973811, -0.0033416180964668243), std::complex<double>(-0.002820659467935919, -0.003279029751202275), std::complex<double>(-0.0025085609163366038, -0.0032235489245193735), std::complex<double>(-0.0022287248589622777, -0.003173803305004455), std::complex<double>(-0.0019752339199748713, -0.003128740978442392), std::complex<double>(-0.0017434691295415057, -0.0030875408443711712), std::complex<double>(-0.001529765360273628, -0.0030495513640493503) } );
expected.push_back( { std::complex<double>(0.019856793027928893, 0.008542854368723037), std::complex<double>(0.020629191005336958, 0.010102118584172187), std::complex<double>(0.021507025025376887, 0.01187422987213899), std::complex<double>(0.02251869360725783, 0.01391651722111692), std::complex<double>(0.023703505035059465, 0.01630833350686496), std::complex<double>(0.02511751391438337, 0.019162837933809428), std::complex<double>(0.026843549170803976, 0.022647239872557293), std::complex<double>(0.02900942346783459, 0.02701955878757966), std::complex<double>(0.0318233379023139, 0.032700096815106786), std::complex<double>(0.03564896542263116, 0.04042301203315778), std::complex<double>(0.04118401107229258, 0.05159678367019237), std::complex<double>(0.049958237273165645, 0.06930959148889769), std::complex<double>(0.0661010967047164, 0.10189769216120209), std::complex<double>(0.10594461504143775, 0.18233106223426224), std::complex<double>(0.3705711082657033, 0.716540929966434), std::complex<double>(-0.18325775884770149, -0.4014909127341218), std::complex<double>(-0.06418743184011887, -0.16111987933332067), std::complex<double>(-0.03502668181352033, -0.10225215137126703), std::complex<double>(-0.021804036179945398, -0.07555917861211714), std::complex<double>(-0.01422861125862444, -0.060266428835155914), std::complex<double>(-0.009299677088207742, -0.05031623360278489), std::complex<double>(-0.005822368147869983, -0.04329648011382558), std::complex<double>(-0.0032268221692641173, -0.03805676939163527), std::complex<double>(-0.0012067540661173208, -0.033978794049702415), std::complex<double>(0.000417165770138706, -0.03070053573790346), std::complex<double>(0.0017569375400259112, -0.027995896110700094), std::complex<double>(0.0028861402754853955, -0.025716338850189247), std::complex<double>(0.003855125132541923, -0.023760218485911554), std::complex<double>(0.0046995289380975195, -0.022055593828777857), std::complex<double>(0.0054453005063065975, -0.020550081187340644), std::complex<double>(0.006111799915075641, -0.01920459776024419), std::complex<double>(0.006713781138413102, -0.017989359233757295), std::complex<double>(0.007262701046166444, -0.016881237262507686), std::complex<double>(0.007767607724873733, -0.015861966188158803), std::complex<double>(0.008235758082522629, -0.014916896261148182), std::complex<double>(0.008673056606462882, -0.01403410790617838), std::complex<double>(0.009084373206691438, -0.013203770081998759), std::complex<double>(0.009473777629742386, -0.01241766706261233), std::complex<double>(0.009844715267837319, -0.011668843525829174), std::complex<double>(0.010200141154965113, -0.010951334051101838), std::complex<double>(0.010542623733339446, -0.010259953642951765), std::complex<double>(0.010874426531246328, -0.009590132845256791), std::complex<double>(0.011197573580164481, -0.008937785681682717), std::complex<double>(0.01151390282278433, -0.008299201839228585), std::complex<double>(0.011825110679020333, -0.007670956701367818), std::complex<double>(0.012132790187372136, -0.0070498343509256545), std::complex<double>(0.012438464623119178, -0.0064327597039400275), std::complex<double>(0.012743618147782049, -0.0058167366366247975), std::complex<double>(0.01304972482423035, -0.005198789411669999), std::complex<double>(0.013358277213350193, -0.004575904949225801), std::complex<double>(0.013670815738263337, -0.00394497354843696), std::complex<double>(0.013988960057187593, -0.003302725554065234), std::complex<double>(0.014314443832277948, -0.0026456611674949386), std::complex<double>(0.01464915453593142, -0.001969970088537866), std::complex<double>(0.014995180327170139, -0.0012714368845648492), std::complex<double>(0.015354866607107925, -0.0005453268201855259), std::complex<double>(0.015730885697777423, 0.00021375480555370537), std::complex<double>(0.01612632429767439, 0.001012039208501533), std::complex<double>(0.016544795128854282, 0.0018568195048747314), std::complex<double>(0.016990581784981224, 0.002756743120633981), std::complex<double>(0.017468829668855997, 0.003722197243059673), std::complex<double>(0.01798580180816931, 0.004765825244168551), std::complex<double>(0.018549227494322237, 0.005903230488857658), std::complex<double>(0.019168786218798237, 0.0071539532725842445) } );
EXPECT_EQ(freqs.size(), expected.size());
run_tests(freqs, expected, window_size, fs);
}
TEST(TestFFT, SineWaveNumPyOdd)
{
constexpr std::size_t window_size = 63;
constexpr double fs = 100.0;
const std::vector<double> freqs = { 3.0, 7.0, 20.4, 73.99 };
/* np.fft.fft */
/* x = np.exp(1j*np.arange(63)/100.*2.*np.pi*freq) */
/* y = np.roll(np.fft.fft(x, norm='backward')/63, 31) */
/* ', '.join([ 'std::complex<double>(' + str(np.real(v)) + ', ' + str(np.imag(v)) + ')' for v in y ]) */
std::vector<ComplexWindow> expected;
expected.push_back( { std::complex<double>(0.00217254269981343, 0.004932473850246969), std::complex<double>(0.0019197215326714548, 0.005023495071189638), std::complex<double>(0.001667390731419688, 0.005114339749548654), std::complex<double>(0.0014142923867813762, 0.005205460760530313), std::complex<double>(0.0011591532162746802, 0.005297316514035213), std::complex<double>(0.0009006587191179457, 0.005390380259465014), std::complex<double>(0.0006374255456670661, 0.0054851500333369515), std::complex<double>(0.00036797082006193244, 0.005582159703811152), std::complex<double>(9.06769193930124e-05, 0.0056819916509703245), std::complex<double>(-0.00019625015210370737, 0.005785291753032028), std::complex<double>(-0.000494831195475788, 0.005892787543140417), std::complex<double>(-0.0008073762452668005, 0.00600531068490568), std::complex<double>(-0.0011365633296607622, 0.006123825327800352), std::complex<double>(-0.0014855395809572165, 0.00624946450917142), std::complex<double>(-0.0018580532118013865, 0.006383577668605563), std::complex<double>(-0.0022586286366787192, 0.0065277936955470675), std::complex<double>(-0.002692802797052767, 0.0066841060115835045), std::complex<double>(-0.0031674498080550076, 0.006854989450445007), std::complex<double>(-0.0036912355864386795, 0.007043563934139647), std::complex<double>(-0.0042752680890935394, 0.007253828573223385), std::complex<double>(-0.00493404950164158, 0.007491004475788174), std::complex<double>(-0.0056869082460827705, 0.007762050301938986), std::complex<double>(-0.006560219324763749, 0.00807646163680811), std::complex<double>(-0.007590971060726067, 0.00844755509609643), std::complex<double>(-0.00883273847067509, 0.008894618872670446), std::complex<double>(-0.010366198510190983, 0.009446698457783297), std::complex<double>(-0.012318801650086898, 0.0101496788443503), std::complex<double>(-0.014904481745228564, 0.01108058095942003), std::complex<double>(-0.01851208894235173, 0.01237939947005195), std::complex<double>(-0.02393022212430873, 0.014330047443979666), std::complex<double>(-0.033038840476588296, 0.01760935183489478), std::complex<double>(-0.05169646584607019, 0.024326510292069788), std::complex<double>(-0.11209166769305025, 0.04607012089767234), std::complex<double>(0.9240773354621242, -0.3269736745893375), std::complex<double>(0.09312362074973744, -0.027811929095666856), std::complex<double>(0.04972394136630158, -0.012187083080376719), std::complex<double>(0.03417969706117949, -0.006590810777400323), std::complex<double>(0.026158239093859, -0.0037029082090384376), std::complex<double>(0.021242818595589835, -0.001933247937880539), std::complex<double>(0.017908117137386024, -0.0007326815389663628), std::complex<double>(0.015486890366432226, 0.00013901373624559358), std::complex<double>(0.013640943990152556, 0.0008035953251330078), std::complex<double>(0.012180533584998023, 0.0013293754236001958), std::complex<double>(0.010990945200040523, 0.0017576535952502509), std::complex<double>(0.009998726073244908, 0.0021148744616220107), std::complex<double>(0.009154646288924418, 0.0024187618829576755), std::complex<double>(0.008424457963765912, 0.0026816458559464095), std::complex<double>(0.007783583553486793, 0.0029123748409993007), std::complex<double>(0.007213912996865523, 0.003117468861349317), std::complex<double>(0.006701793333728195, 0.0033018432851146867), std::complex<double>(0.006236722882790503, 0.003469278950202486), std::complex<double>(0.00581047758962972, 0.003622736698393158), std::complex<double>(0.005416511174847284, 0.0037645733352905963), std::complex<double>(0.005049533701972826, 0.0038966933552124147), std::complex<double>(0.00470520931691618, 0.004020657761683845), std::complex<double>(0.004379935332302352, 0.004137763601970687), std::complex<double>(0.004070677905686599, 0.004249103126561684), std::complex<double>(0.0037748477511413987, 0.004355608535751666), std::complex<double>(0.003490204573509287, 0.004458086385426821), std::complex<double>(0.0032147823486649275, 0.004557244487825675), std::complex<double>(0.002946829859553832, 0.004653713319882787), std::complex<double>(0.002684762442725135, 0.00474806339554579), std::complex<double>(0.0024271219555918864, 0.004840819678448151) } );
expected.push_back( { std::complex<double>(0.013797690554100824, -0.00714331660163881), std::complex<double>(0.014016053987041137, -0.006391704735539276), std::complex<double>(0.01423125522134486, -0.005650977228538982), std::complex<double>(0.014444414072389593, -0.0049172796508256495), std::complex<double>(0.01465660894190749, -0.004186900119291911), std::complex<double>(0.01486889889082396, -0.0034561933223218938), std::complex<double>(0.015082344881815507, -0.0027215074024289202), std::complex<double>(0.015298031103165194, -0.0019791105590670254), std::complex<double>(0.015517087291508731, -0.0012251142132293758), std::complex<double>(0.01574071304550388, -0.0004553893192535522), std::complex<double>(0.01597020527388729, 0.0003345281120122237), std::complex<double>(0.016206990167708414, 0.0011495470623589612), std::complex<double>(0.016452661457982926, 0.001995153189923179), std::complex<double>(0.016709027264598157, 0.0028775700841787216), std::complex<double>(0.016978168634868004, 0.0038039607569631054), std::complex<double>(0.01726251402747688, 0.004782684017895686), std::complex<double>(0.017564935703914868, 0.0058236262558691585), std::complex<double>(0.0178888765401769, 0.006938637927787573), std::complex<double>(0.018238519649094335, 0.008142117402458548), std::complex<double>(0.01861901921486601, 0.009451805498257134), std::complex<double>(0.019036820469171146, 0.010889886848135908), std::complex<double>(0.019500112221796633, 0.012484547520257926), std::complex<double>(0.020019481238149412, 0.014272227400166194), std::complex<double>(0.020608882407484534, 0.016300959531734018), std::complex<double>(0.021287118520642793, 0.018635463545536794), std::complex<double>(0.02208017241004312, 0.021365172937367796), std::complex<double>(0.023025025586043395, 0.024617378900798906), std::complex<double>(0.024176200710537013, 0.028579749669005602), std::complex<double>(0.025617601097388015, 0.03354108234256665), std::complex<double>(0.027485431886716677, 0.03997019808883333), std::complex<double>(0.030016541534849023, 0.04868233464172951), std::complex<double>(0.03366253339078348, 0.06123192092420843), std::complex<double>(0.03940465933484665, 0.0809964480617513), std::complex<double>(0.04985267997082482, 0.11695877097229572), std::complex<double>(0.07501972401338014, 0.2035843047547987), std::complex<double>(0.22260727975599273, 0.7115840036562971), std::complex<double>(-0.12986226552953115, -0.501624128804808), std::complex<double>(-0.038884931705485806, -0.18847809181727201), std::complex<double>(-0.018105633856735154, -0.11695527949453918), std::complex<double>(-0.00886289585527625, -0.08514156662327775), std::complex<double>(-0.003616290846790898, -0.06708263373320575), std::complex<double>(-0.0002209935405095322, -0.05539594375048054), std::complex<double>(0.0021660007223392496, -0.04717985560737581), std::complex<double>(0.0039434667449540755, -0.04106177742827346), std::complex<double>(0.00532452486262397, -0.03630814420756144), std::complex<double>(0.0064334384721145745, -0.032491238528119006), std::complex<double>(0.0073475690424927445, -0.029344780466853734), std::complex<double>(0.008117611810080338, -0.026694275875816628), std::complex<double>(0.00877818805564715, -0.02442055752496475), std::complex<double>(0.009353761170349457, -0.02243942186963452), std::complex<double>(0.009862120099712813, -0.020689638957714866), std::complex<double>(0.010316522464134645, -0.01912557576048259), std::complex<double>(0.01072706293464418, -0.017712486192352488), std::complex<double>(0.011101575222496936, -0.01642340644232357), std::complex<double>(0.011446243350711179, -0.015237050963551399), std::complex<double>(0.011766026147149658, -0.014136351358580332), std::complex<double>(0.012064958525021863, -0.013107419365047342), std::complex<double>(0.012346369575348123, -0.012138796176499237), std::complex<double>(0.012613043336235343, -0.011220899070920063), std::complex<double>(0.01286733934945463, -0.010345606452262575), std::complex<double>(0.013111284568411995, -0.009505941501140772), std::complex<double>(0.013346644590514252, -0.008695826991419216), std::complex<double>(0.013574979817067007, -0.007909891986575945) } );
expected.push_back( { std::complex<double>(0.007694095772696858, 0.004102842405415429), std::complex<double>(0.007233793521780263, 0.00433374667776444), std::complex<double>(0.006801790241938655, 0.004550455161778238), std::complex<double>(0.00639358610465265, 0.004755225134340053), std::complex<double>(0.006005389857075124, 0.004949958425122961), std::complex<double>(0.005633964127554237, 0.0051362790169427845), std::complex<double>(0.005276506406089674, 0.00531559275026891), std::complex<double>(0.004930555926319557, 0.005489134034591082), std::complex<double>(0.004593919507692769, 0.005658003048667559), std::complex<double>(0.004264611330944682, 0.005823195951329397), std::complex<double>(0.0039408029284834405, 0.005985629968113226), std::complex<double>(0.003620780570265583, 0.006146164768046185), std::complex<double>(0.0033029078409875677, 0.006305621236285522), std::complex<double>(0.0029855916166766127, 0.006464798541487272), std::complex<double>(0.002667249909260636, 0.006624490266137422), std::complex<double>(0.0023462801874704784, 0.006785500297934637), std::complex<double>(0.0020210268176799173, 0.006948659162639612), std::complex<double>(0.0016897462030436082, 0.0071148415115502425), std::complex<double>(0.0013505680260474868, 0.0072849855636380285), std::complex<double>(0.0010014506982063372, 0.007460115453593961), std::complex<double>(0.0006401286547338843, 0.007641367670731387), std::complex<double>(0.00026404844283494505, 0.007830023119408384), std::complex<double>(-0.00012971045219589518, 0.008027546835525777), std::complex<double>(-0.0005445355622086635, 0.008235638127690393), std::complex<double>(-0.0009844098387317497, 0.008456294988575948), std::complex<double>(-0.0014540793572733021, 0.008691898221468788), std::complex<double>(-0.0019592759872314298, 0.00894532313955569), std::complex<double>(-0.002507018080550582, 0.009220090402243086), std::complex<double>(-0.0031060238261987425, 0.009520573368720978), std::complex<double>(-0.0037672905451849744, 0.009852288693319871), std::complex<double>(-0.004504923938165533, 0.010222312306126144), std::complex<double>(-0.005337353565570268, 0.010639889141813437), std::complex<double>(-0.006289162803698164, 0.01111735111187351), std::complex<double>(-0.007393929757212282, 0.011671542209156553), std::complex<double>(-0.008698797537397654, 0.012326111124897935), std::complex<double>(-0.010272141559441216, 0.013115357442599358), std::complex<double>(-0.012217094925778584, 0.014091016459937615), std::complex<double>(-0.014696916607553233, 0.015334984786936946), std::complex<double>(-0.017986368543364183, 0.016985092958587595), std::complex<double>(-0.02258662491880755, 0.019292748089270596), std::complex<double>(-0.029519166805105808, 0.022770362062698855), std::complex<double>(-0.04123796714387352, 0.028648936542061184), std::complex<double>(-0.0654969167652428, 0.040818103864470386), std::complex<double>(-0.14645264100433097, 0.08142842580125878), std::complex<double>(0.8651576602113913, -0.4260319223467539), std::complex<double>(0.1141964188360731, -0.049322578307840044), std::complex<double>(0.062355606362570024, -0.023317350094500165), std::complex<double>(0.04338300458546432, -0.013800006220568447), std::complex<double>(0.033506733932706034, -0.008845711332674824), std::complex<double>(0.027425598990948145, -0.005795193904203903), std::complex<double>(0.02328738517549909, -0.003719316047903733), std::complex<double>(0.020276307136231953, -0.002208850300103517), std::complex<double>(0.01797700428937623, -0.0010554367556180615), std::complex<double>(0.01615567921764992, -0.0001417941662945392), std::complex<double>(0.01467063747174552, 0.0006031565330852838), std::complex<double>(0.013430975614909638, 0.001225015797171784), std::complex<double>(0.012375673175734285, 0.0017543937034080975), std::complex<double>(0.011462225417535696, 0.0022126121664193445), std::complex<double>(0.01066009637057661, 0.002614989134053262), std::complex<double>(0.009946764595801306, 0.002972822175430136), std::complex<double>(0.009305237697341345, 0.0032946352914567075), std::complex<double>(0.008722435958674103, 0.0035869897414364587), std::complex<double>(0.008188109792453435, 0.003855027089423975) } );
expected.push_back( { std::complex<double>(0.008107366038144666, 0.020807807356682653), std::complex<double>(0.007487521659286392, 0.022468660305339234), std::complex<double>(0.006785933778354495, 0.024348542321722885), std::complex<double>(0.0059810084770855415, 0.02650531361085756), std::complex<double>(0.005043068343213787, 0.02901849383823641), std::complex<double>(0.003930143978578147, 0.03200053864766229), std::complex<double>(0.0025808346522562973, 0.035615969310092095), std::complex<double>(0.0009015434055273905, 0.0401155758466681), std::complex<double>(-0.0012578675988856084, 0.045901647732372625), std::complex<double>(-0.004154440928843917, 0.05366292220725275), std::complex<double>(-0.008267983877320256, 0.06468502738137274), std::complex<double>(-0.014609295477563707, 0.08167636654452763), std::complex<double>(-0.025735957150929956, 0.1114898963257282), std::complex<double>(-0.0505449970339172, 0.17796491561793712), std::complex<double>(-0.15592229747233202, 0.46031998105548266), std::complex<double>(0.2838250370772816, -0.7179687671489408), std::complex<double>(0.08902892190763874, -0.19601888214644628), std::complex<double>(0.05742226730786844, -0.11132987426095584), std::complex<double>(0.04443163510376675, -0.0765218957798013), std::complex<double>(0.03732440999956131, -0.057478316175572475), std::complex<double>(0.03282346612027887, -0.045418182747613396), std::complex<double>(0.029704217421743753, -0.03706025683068166), std::complex<double>(0.02740519242896718, -0.03090009378249128), std::complex<double>(0.025632676512488323, -0.02615069476102527), std::complex<double>(0.02421807814927559, -0.022360324237668917), std::complex<double>(0.023057692086021327, -0.019251107343140776), std::complex<double>(0.022084203910271855, -0.016642677288250536), std::complex<double>(0.021251997640798034, -0.014412807527905361), std::complex<double>(0.020529048388900444, -0.012475688409489753), std::complex<double>(0.019892195926007033, -0.010769262850214796), std::complex<double>(0.01932426096906339, -0.009247499517272937), std::complex<double>(0.018812216950869945, -0.007875494145504537), std::complex<double>(0.018345992264928494, -0.006626260191321337), std::complex<double>(0.017917662889686745, -0.005478565495483705), std::complex<double>(0.017520894364019025, -0.004415437074437624), std::complex<double>(0.017150547415347415, -0.0034231044136878437), std::complex<double>(0.016802393584465853, -0.002490237493663385), std::complex<double>(0.016472906348311098, -0.001607387109961173), std::complex<double>(0.016159105023166663, -0.0007665666170568318), std::complex<double>(0.015858436159373684, 3.9065870750873904e-05), std::complex<double>(0.015568681928231812, 0.0008154529536876787), std::complex<double>(0.015287888150909364, 0.001567830790663112), std::complex<double>(0.01501430672531629, 0.002300883364648319), std::complex<double>(0.014746348634735538, 0.0030188683944946623), std::complex<double>(0.0144825446998609, 0.003725722498600886), std::complex<double>(0.014221511907690273, 0.004425151415526741), std::complex<double>(0.013961923609162477, 0.005120709858505537), std::complex<double>(0.013702482181679836, 0.005815874765271456), std::complex<double>(0.013441892940373347, 0.00651411520201381), std::complex<double>(0.013178838174947867, 0.0072189619308318095), std::complex<double>(0.01291195019825882, 0.007934079625144419), std::complex<double>(0.01263978221939527, 0.008663344914370869), std::complex<double>(0.012360775689289238, 0.009410933880282893), std::complex<double>(0.012073222491899852, 0.01018142336452692), std::complex<double>(0.011775219934797219, 0.010979911569866538), std::complex<double>(0.011464615876480318, 0.011812165089804314), std::complex<double>(0.011138940429898868, 0.01268480190673312), std::complex<double>(0.010795319372475352, 0.013605523407003965), std::complex<double>(0.010430362467079112, 0.014583413621276135), std::complex<double>(0.01004001702847455, 0.015629331588452863), std::complex<double>(0.009619372722964295, 0.016756434388711477), std::complex<double>(0.00916239687831382, 0.01798088637204251), std::complex<double>(0.008661568995010058, 0.019322838473441725) } );
EXPECT_EQ(freqs.size(), expected.size());
run_tests(freqs, expected, window_size, fs);
}
TEST(TestFFT, ZerodBFSEven)
{
constexpr std::size_t window_size = 16;
constexpr double fs = 16.0;
std::vector<ComplexWindow> expected;
std::vector<double> freqs; /* exactly match borders */
ComplexWindow zeros(window_size); /* all zeros */
for (auto& v : zeros) { v = std::complex<double>(0.0, 0.0); }
for (std::size_t i = 1; i < 8; i++) {
freqs.push_back((double)i);
auto copy = zeros;
copy[7+i] = std::complex<double>(1.0, 0.0);
expected.push_back(copy);
}
run_tests(freqs, expected, window_size, fs);
}
TEST(TestFFT, ZerodBFSOdd)
{
constexpr std::size_t window_size = 15;
constexpr double fs = 15.0;
std::vector<ComplexWindow> expected;
std::vector<double> freqs; /* exactly match borders */
ComplexWindow zeros(window_size); /* all zeros */
for (auto& v : zeros) { v = std::complex<double>(0.0, 0.0); }
for (std::size_t i = 1; i < 8; i++) {
freqs.push_back((double)i);
auto copy = zeros;
copy[7+i] = std::complex<double>(1.0, 0.0);
expected.push_back(copy);
}
run_tests(freqs, expected, window_size, fs);
}
TEST(TestFFT, GetMagnitude)
{
constexpr double epsilon = 1e-9;
EXPECT_EQ(FFT::GetMagnitude({}, false).size(), 0); /* empty output, no error */
for (auto window_size : std::vector<std::size_t> { 63, 64 }) {
ComplexWindow input(window_size);
for (std::size_t j = 0; j < window_size; j++) {
double ang = 2.0 * (double)M_PI * (double) j;
input[j] = std::exp(std::complex<double>(0.0, ang)); /* e^jWt */
}
{ /* no aliasing, magnitude is 1.0 everywhere */
auto out = FFT::GetMagnitude(input, false);
EXPECT_EQ(out.size(), window_size);
for (std::size_t j = 0; j < window_size; j++) {
EXPECT_LE(std::abs(out[j] - 1.0), epsilon);
}
}
{ /* aliasing, magnitude is 1.0 everywhere */
auto out = FFT::GetMagnitude(input, true);
EXPECT_EQ(out.size(), window_size);
for (std::size_t j = 0; j < window_size; j++) {
if (window_size % 2 == 0) {
if ((j == window_size / 2 - 1) || (j == window_size - 1)) {
EXPECT_LE(std::abs(out[j] - 1.0), epsilon);
} else {
EXPECT_LE(std::abs(out[j] - 2.0), epsilon);
}
} else {
if (j == window_size / 2) {
EXPECT_LE(std::abs(out[j] - 1.0), epsilon);
} else {
EXPECT_LE(std::abs(out[j] - 2.0), epsilon);
}
}
}
}
}
}
TEST(TestFFT, GetFrequencyLimits)
{
constexpr double epsilon = 1e-9;
EXPECT_THROW_MATCH(FFT::GetFrequencyLimits(-1e-9, 1),
std::runtime_error, "rate must be positive in order to compute frequency limits");
EXPECT_THROW_MATCH(FFT::GetFrequencyLimits(0.0, 1),
std::runtime_error, "rate must be positive in order to compute frequency limits");
EXPECT_THROW_MATCH(FFT::GetFrequencyLimits(1e-9, 0),
std::runtime_error, "FFT width must be positive in order to compute frequency limits");
struct test_t { double rate; std::size_t width; double ex_low; double ex_high; };
std::vector<struct test_t> tests {
{ 1.0, 63, 32.0 / 63.0 - 1.0, 31.0 / 63.0 },
{ 1.0, 64, 33.0 / 64.0 - 1.0, 32.0 / 64.0 },
{ 1.5, 63, 1.5 * (32.0 / 63.0 - 1.0), 1.5 * (31.0 / 63.0) },
{ 1.5, 64, 1.5 * (33.0 / 64.0 - 1.0), 1.5 * (32.0 / 64.0) },
};
for (auto& test : tests) {
auto out = FFT::GetFrequencyLimits(test.rate, test.width);
EXPECT_LE(std::abs(std::get<0>(out) - test.ex_low), epsilon);
EXPECT_LE(std::abs(std::get<1>(out) - test.ex_high), epsilon);
}
}
TEST(TestFFT, GetFrequencyIndex)
{
constexpr double epsilon = 1e-6;
struct test_t { double rate; std::size_t width; double f; double idx; };
std::vector<struct test_t> tests {
/* np.roll(np.fft.fftfreq(63), 31) * 20.0 */
{ 20.0, 63, 3.17460317, 41.0 },
{ 20.0, 63, 9.84126984, 62.0 },
{ 20.0, 63, -9.84126984, 0.0 },
{ 20.0, 63, -8.0, 5.79999999 },
{ 20.0, 63, 0.0, 31.0 },
/* np.roll(np.fft.fftfreq(64), 31) * .1 */
{ 0.1, 64, -0.0484375, 0.0 },
{ 0.1, 64, 0.05, 63.0 },
{ 0.1, 64, 0.0, 31.0 },
{ 0.1, 64, 0.0015625, 32.0 },
};
for (auto& test : tests) {
auto out = FFT::GetFrequencyIndex(test.rate, test.width, test.f);
EXPECT_LE(std::abs(out - test.idx), epsilon);
}
}
TEST(TestFFT, Crop)
{
EXPECT_THROW_MATCH(FFT::Crop({}, -1e-9, 0.0, 1.0),
std::runtime_error, "rate must be positive for cropping");
EXPECT_THROW_MATCH(FFT::Crop({}, 0.0, 0.0, 1.0),
std::runtime_error, "rate must be positive for cropping");
EXPECT_THROW_MATCH(FFT::Crop({}, 1e-9, 1.0, 0.0),
std::runtime_error, "cropping frequency bounds either not distinct or not in order");
EXPECT_THROW_MATCH(FFT::Crop({}, 1e-9, 1.0, 1.0),
std::runtime_error, "cropping frequency bounds either not distinct or not in order");
EXPECT_THROW_MATCH(FFT::Crop({1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}, 1.0, -0.5, 0.5),
std::runtime_error, "fmin outside of window");
EXPECT_THROW_MATCH(FFT::Crop({1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}, 1.0, -0.375, 0.6),
std::runtime_error, "fmax outside of window");
{
auto out = FFT::Crop({1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}, 1.0, -0.375, 0.5);
EXPECT_EQ(out.size(), 8);
for (auto v : out) { EXPECT_EQ(v, 1.0); }
}
{
auto out = FFT::Crop({1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}, 1.0, -0.275, 0.5);
EXPECT_EQ(out.size(), 7);
for (auto v : out) { EXPECT_EQ(v, 1.0); }
}
{
auto out = FFT::Crop({1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}, 1.0, -0.275, 0.4);
EXPECT_EQ(out.size(), 6);
for (auto v : out) { EXPECT_EQ(v, 1.0); }
}
{
auto out = FFT::Crop({1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}, 1.0, 0.0, 0.1);
EXPECT_EQ(out.size(), 2);
for (auto v : out) { EXPECT_EQ(v, 1.0); }
}
{
auto out = FFT::Crop({1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0}, 1.0, 0.0, 0.05);
EXPECT_EQ(out.size(), 1);
for (auto v : out) { EXPECT_EQ(v, 1.0); }
}
}
TEST(TestFFT, Resample)
{
constexpr double epsilon = 1e-2;
EXPECT_THROW_MATCH(FFT::Resample({}, -1e-9, 8, -0.375, 0.5),
std::runtime_error, "rate must be positive for resampling");
EXPECT_THROW_MATCH(FFT::Resample({}, 0.0, 8, -0.375, 0.5),
std::runtime_error, "rate must be positive for resampling");
EXPECT_THROW_MATCH(FFT::Resample({}, 1.0, 8, 0.0, 0.0),
std::runtime_error, "resampling frequency bounds either not distinct or not in order");
EXPECT_THROW_MATCH(FFT::Resample({}, 1.0, 8, 1.0, 0.0),
std::runtime_error, "resampling frequency bounds either not distinct or not in order");
EXPECT_THROW_MATCH(FFT::Resample({}, 1.0, 0, 0.0, 0.1),
std::runtime_error, "resampling requires positive width");
{
RealWindow input { 0.0, 0.066, 0.133, 0.2, 0.266, 0.333, 0.4, 0.466, 0.533, 0.6, 0.666, 0.733, 0.8, 0.866, 0.933, 1. };
auto out = FFT::Resample(input, 1.0, 4, -0.4375, 0.5);
EXPECT_EQ(out.size(), 4);
EXPECT_LE(std::abs(out[0] - 0.0521), epsilon);
EXPECT_LE(std::abs(out[1] - 0.3355), epsilon);
EXPECT_LE(std::abs(out[2] - 0.6689), epsilon);
EXPECT_LE(std::abs(out[3] - 0.9504), epsilon);
}
{
RealWindow input { 0.0, 0.066, 0.133, 0.2, 0.266, 0.333, 0.4, 0.466, 0.533, 0.6, 0.666, 0.733, 0.8, 0.866, 0.933, 1. };
auto out = FFT::Resample(input, 1.0, 4, 0.0, 0.5);
EXPECT_EQ(out.size(), 4);
EXPECT_LE(std::abs(out[0] - 0.4685), epsilon);
EXPECT_LE(std::abs(out[1] - 0.6434), epsilon);
EXPECT_LE(std::abs(out[2] - 0.8225), epsilon);
EXPECT_LE(std::abs(out[3] - 0.9502), epsilon);
}
{
RealWindow input { 0.0, 0.066, 0.133, 0.2, 0.266, 0.333, 0.4, 0.466, 0.533, 0.6, 0.666, 0.733, 0.8, 0.866, 0.933, 1. };
auto out = FFT::Resample(input, 1.0, 4, 0.0, 0.01);
EXPECT_EQ(out.size(), 4);
EXPECT_LE(std::abs(out[0] - 0.4685), epsilon);
EXPECT_LE(std::abs(out[1] - 0.4718), epsilon);
EXPECT_LE(std::abs(out[2] - 0.4751), epsilon);
EXPECT_LE(std::abs(out[3] - 0.4784), epsilon);
}
{
RealWindow input { 0.0, 0.066, 0.133, 0.2, 0.266, 0.333, 0.4, 0.466, 0.533, 0.6, 0.666, 0.733, 0.8, 0.866, 0.933, 1. };
auto out = FFT::Resample(input, 1.0, 4, -2, -1);
EXPECT_EQ(out.size(), 4);
for (auto v : out) { EXPECT_EQ(v, 0.0); }
}
{
RealWindow input { 0.0, 0.066, 0.133, 0.2, 0.266, 0.333, 0.4, 0.466, 0.533, 0.6, 0.666, 0.733, 0.8, 0.866, 0.933, 1. };
auto out = FFT::Resample(input, 1.0, 4, -1, 0);
EXPECT_EQ(out.size(), 4);
EXPECT_LE(std::abs(out[0]), epsilon);
EXPECT_LE(std::abs(out[1]), epsilon);
EXPECT_LE(std::abs(out[2] - 0.1177), epsilon);
EXPECT_LE(std::abs(out[3] - 0.4685), epsilon);
}
{
RealWindow input { 0.0, 0.066, 0.133, 0.2, 0.266, 0.333, 0.4, 0.466, 0.533, 0.6, 0.666, 0.733, 0.8, 0.866, 0.933, 1. };
auto out = FFT::Resample(input, 1.0, 4, 0.0, 1.0);
EXPECT_EQ(out.size(), 4);
EXPECT_LE(std::abs(out[0] - 0.4685), epsilon);
EXPECT_LE(std::abs(out[1] - 0.8225), epsilon);
EXPECT_LE(std::abs(out[2] - 1.0), epsilon);
EXPECT_LE(std::abs(out[3] - 0.0), epsilon);
}
{
RealWindow input { 0.0, 0.066, 0.133, 0.2, 0.266, 0.333, 0.4, 0.466, 0.533, 0.6, 0.666, 0.733, 0.8, 0.866, 0.933, 1. };
auto out = FFT::Resample(input, 1.0, 4, 1, 2);
EXPECT_EQ(out.size(), 4);
for (auto v : out) { EXPECT_EQ(v, 0.0); }
}
}
|