1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.hipparchus.transform;
23
24 import java.io.Serializable;
25
26 import org.hipparchus.analysis.FunctionUtils;
27 import org.hipparchus.analysis.UnivariateFunction;
28 import org.hipparchus.complex.Complex;
29 import org.hipparchus.exception.MathIllegalArgumentException;
30 import org.hipparchus.exception.MathRuntimeException;
31 import org.hipparchus.util.ArithmeticUtils;
32 import org.hipparchus.util.FastMath;
33 import org.hipparchus.util.MathArrays;
34 import org.hipparchus.util.MathUtils;
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 public class FastFourierTransformer implements Serializable {
56
57
58 private static final long serialVersionUID = 20120210L;
59
60
61
62
63
64
65 private static final double[] W_SUB_N_R =
66 { 0x1.0p0, -0x1.0p0, 0x1.1a62633145c07p-54, 0x1.6a09e667f3bcdp-1
67 , 0x1.d906bcf328d46p-1, 0x1.f6297cff75cbp-1, 0x1.fd88da3d12526p-1, 0x1.ff621e3796d7ep-1
68 , 0x1.ffd886084cd0dp-1, 0x1.fff62169b92dbp-1, 0x1.fffd8858e8a92p-1, 0x1.ffff621621d02p-1
69 , 0x1.ffffd88586ee6p-1, 0x1.fffff62161a34p-1, 0x1.fffffd8858675p-1, 0x1.ffffff621619cp-1
70 , 0x1.ffffffd885867p-1, 0x1.fffffff62161ap-1, 0x1.fffffffd88586p-1, 0x1.ffffffff62162p-1
71 , 0x1.ffffffffd8858p-1, 0x1.fffffffff6216p-1, 0x1.fffffffffd886p-1, 0x1.ffffffffff621p-1
72 , 0x1.ffffffffffd88p-1, 0x1.fffffffffff62p-1, 0x1.fffffffffffd9p-1, 0x1.ffffffffffff6p-1
73 , 0x1.ffffffffffffep-1, 0x1.fffffffffffffp-1, 0x1.0p0, 0x1.0p0
74 , 0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0
75 , 0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0
76 , 0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0
77 , 0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0
78 , 0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0
79 , 0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0
80 , 0x1.0p0, 0x1.0p0, 0x1.0p0, 0x1.0p0
81 , 0x1.0p0, 0x1.0p0, 0x1.0p0 };
82
83
84
85
86
87
88 private static final double[] W_SUB_N_I =
89 { 0x1.1a62633145c07p-52, -0x1.1a62633145c07p-53, -0x1.0p0, -0x1.6a09e667f3bccp-1
90 , -0x1.87de2a6aea963p-2, -0x1.8f8b83c69a60ap-3, -0x1.917a6bc29b42cp-4, -0x1.91f65f10dd814p-5
91 , -0x1.92155f7a3667ep-6, -0x1.921d1fcdec784p-7, -0x1.921f0fe670071p-8, -0x1.921f8becca4bap-9
92 , -0x1.921faaee6472dp-10, -0x1.921fb2aecb36p-11, -0x1.921fb49ee4ea6p-12, -0x1.921fb51aeb57bp-13
93 , -0x1.921fb539ecf31p-14, -0x1.921fb541ad59ep-15, -0x1.921fb5439d73ap-16, -0x1.921fb544197ap-17
94 , -0x1.921fb544387bap-18, -0x1.921fb544403c1p-19, -0x1.921fb544422c2p-20, -0x1.921fb54442a83p-21
95 , -0x1.921fb54442c73p-22, -0x1.921fb54442cefp-23, -0x1.921fb54442d0ep-24, -0x1.921fb54442d15p-25
96 , -0x1.921fb54442d17p-26, -0x1.921fb54442d18p-27, -0x1.921fb54442d18p-28, -0x1.921fb54442d18p-29
97 , -0x1.921fb54442d18p-30, -0x1.921fb54442d18p-31, -0x1.921fb54442d18p-32, -0x1.921fb54442d18p-33
98 , -0x1.921fb54442d18p-34, -0x1.921fb54442d18p-35, -0x1.921fb54442d18p-36, -0x1.921fb54442d18p-37
99 , -0x1.921fb54442d18p-38, -0x1.921fb54442d18p-39, -0x1.921fb54442d18p-40, -0x1.921fb54442d18p-41
100 , -0x1.921fb54442d18p-42, -0x1.921fb54442d18p-43, -0x1.921fb54442d18p-44, -0x1.921fb54442d18p-45
101 , -0x1.921fb54442d18p-46, -0x1.921fb54442d18p-47, -0x1.921fb54442d18p-48, -0x1.921fb54442d18p-49
102 , -0x1.921fb54442d18p-50, -0x1.921fb54442d18p-51, -0x1.921fb54442d18p-52, -0x1.921fb54442d18p-53
103 , -0x1.921fb54442d18p-54, -0x1.921fb54442d18p-55, -0x1.921fb54442d18p-56, -0x1.921fb54442d18p-57
104 , -0x1.921fb54442d18p-58, -0x1.921fb54442d18p-59, -0x1.921fb54442d18p-60 };
105
106
107 private final DftNormalization normalization;
108
109
110
111
112
113
114
115
116 public FastFourierTransformer(final DftNormalization normalization) {
117 this.normalization = normalization;
118 }
119
120
121
122
123
124
125
126
127
128
129
130 private static void bitReversalShuffle2(double[] a, double[] b) {
131 final int n = a.length;
132 assert b.length == n;
133 final int halfOfN = n >> 1;
134
135 int j = 0;
136 for (int i = 0; i < n; i++) {
137 if (i < j) {
138
139 double temp = a[i];
140 a[i] = a[j];
141 a[j] = temp;
142
143 temp = b[i];
144 b[i] = b[j];
145 b[j] = temp;
146 }
147
148 int k = halfOfN;
149 while (k <= j && k > 0) {
150 j -= k;
151 k >>= 1;
152 }
153 j += k;
154 }
155 }
156
157
158
159
160
161
162
163
164 private static void normalizeTransformedData(final double[][] dataRI,
165 final DftNormalization normalization, final TransformType type) {
166
167 final double[] dataR = dataRI[0];
168 final double[] dataI = dataRI[1];
169 final int n = dataR.length;
170 assert dataI.length == n;
171
172 switch (normalization) {
173 case STANDARD:
174 if (type == TransformType.INVERSE) {
175 final double scaleFactor = 1.0 / n;
176 for (int i = 0; i < n; i++) {
177 dataR[i] *= scaleFactor;
178 dataI[i] *= scaleFactor;
179 }
180 }
181 break;
182 case UNITARY:
183 final double scaleFactor = 1.0 / FastMath.sqrt(n);
184 for (int i = 0; i < n; i++) {
185 dataR[i] *= scaleFactor;
186 dataI[i] *= scaleFactor;
187 }
188 break;
189 default:
190
191
192
193
194 throw MathRuntimeException.createInternalError();
195 }
196 }
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214 public static void transformInPlace(final double[][] dataRI,
215 final DftNormalization normalization, final TransformType type) {
216
217 MathUtils.checkDimension(dataRI.length, 2);
218 final double[] dataR = dataRI[0];
219 final double[] dataI = dataRI[1];
220 MathArrays.checkEqualLength(dataR, dataI);
221
222 final int n = dataR.length;
223 if (!ArithmeticUtils.isPowerOfTwo(n)) {
224 throw new MathIllegalArgumentException(LocalizedFFTFormats.NOT_POWER_OF_TWO_CONSIDER_PADDING,
225 Integer.valueOf(n));
226 }
227
228 if (n == 1) {
229 return;
230 } else if (n == 2) {
231 final double srcR0 = dataR[0];
232 final double srcI0 = dataI[0];
233 final double srcR1 = dataR[1];
234 final double srcI1 = dataI[1];
235
236
237 dataR[0] = srcR0 + srcR1;
238 dataI[0] = srcI0 + srcI1;
239
240 dataR[1] = srcR0 - srcR1;
241 dataI[1] = srcI0 - srcI1;
242
243 normalizeTransformedData(dataRI, normalization, type);
244 return;
245 }
246
247 bitReversalShuffle2(dataR, dataI);
248
249
250 if (type == TransformType.INVERSE) {
251 for (int i0 = 0; i0 < n; i0 += 4) {
252 final int i1 = i0 + 1;
253 final int i2 = i0 + 2;
254 final int i3 = i0 + 3;
255
256 final double srcR0 = dataR[i0];
257 final double srcI0 = dataI[i0];
258 final double srcR1 = dataR[i2];
259 final double srcI1 = dataI[i2];
260 final double srcR2 = dataR[i1];
261 final double srcI2 = dataI[i1];
262 final double srcR3 = dataR[i3];
263 final double srcI3 = dataI[i3];
264
265
266
267 dataR[i0] = srcR0 + srcR1 + srcR2 + srcR3;
268 dataI[i0] = srcI0 + srcI1 + srcI2 + srcI3;
269
270 dataR[i1] = srcR0 - srcR2 + (srcI3 - srcI1);
271 dataI[i1] = srcI0 - srcI2 + (srcR1 - srcR3);
272
273 dataR[i2] = srcR0 - srcR1 + srcR2 - srcR3;
274 dataI[i2] = srcI0 - srcI1 + srcI2 - srcI3;
275
276 dataR[i3] = srcR0 - srcR2 + (srcI1 - srcI3);
277 dataI[i3] = srcI0 - srcI2 + (srcR3 - srcR1);
278 }
279 } else {
280 for (int i0 = 0; i0 < n; i0 += 4) {
281 final int i1 = i0 + 1;
282 final int i2 = i0 + 2;
283 final int i3 = i0 + 3;
284
285 final double srcR0 = dataR[i0];
286 final double srcI0 = dataI[i0];
287 final double srcR1 = dataR[i2];
288 final double srcI1 = dataI[i2];
289 final double srcR2 = dataR[i1];
290 final double srcI2 = dataI[i1];
291 final double srcR3 = dataR[i3];
292 final double srcI3 = dataI[i3];
293
294
295
296 dataR[i0] = srcR0 + srcR1 + srcR2 + srcR3;
297 dataI[i0] = srcI0 + srcI1 + srcI2 + srcI3;
298
299 dataR[i1] = srcR0 - srcR2 + (srcI1 - srcI3);
300 dataI[i1] = srcI0 - srcI2 + (srcR3 - srcR1);
301
302 dataR[i2] = srcR0 - srcR1 + srcR2 - srcR3;
303 dataI[i2] = srcI0 - srcI1 + srcI2 - srcI3;
304
305 dataR[i3] = srcR0 - srcR2 + (srcI3 - srcI1);
306 dataI[i3] = srcI0 - srcI2 + (srcR1 - srcR3);
307 }
308 }
309
310 int lastN0 = 4;
311 int lastLogN0 = 2;
312 while (lastN0 < n) {
313 int n0 = lastN0 << 1;
314 int logN0 = lastLogN0 + 1;
315 double wSubN0R = W_SUB_N_R[logN0];
316 double wSubN0I = W_SUB_N_I[logN0];
317 if (type == TransformType.INVERSE) {
318 wSubN0I = -wSubN0I;
319 }
320
321
322 for (int destEvenStartIndex = 0; destEvenStartIndex < n; destEvenStartIndex += n0) {
323 int destOddStartIndex = destEvenStartIndex + lastN0;
324
325 double wSubN0ToRR = 1;
326 double wSubN0ToRI = 0;
327
328 for (int r = 0; r < lastN0; r++) {
329 double grR = dataR[destEvenStartIndex + r];
330 double grI = dataI[destEvenStartIndex + r];
331 double hrR = dataR[destOddStartIndex + r];
332 double hrI = dataI[destOddStartIndex + r];
333
334
335 dataR[destEvenStartIndex + r] = grR + wSubN0ToRR * hrR - wSubN0ToRI * hrI;
336 dataI[destEvenStartIndex + r] = grI + wSubN0ToRR * hrI + wSubN0ToRI * hrR;
337
338 dataR[destOddStartIndex + r] = grR - (wSubN0ToRR * hrR - wSubN0ToRI * hrI);
339 dataI[destOddStartIndex + r] = grI - (wSubN0ToRR * hrI + wSubN0ToRI * hrR);
340
341
342 double nextWsubN0ToRR = wSubN0ToRR * wSubN0R - wSubN0ToRI * wSubN0I;
343 double nextWsubN0ToRI = wSubN0ToRR * wSubN0I + wSubN0ToRI * wSubN0R;
344 wSubN0ToRR = nextWsubN0ToRR;
345 wSubN0ToRI = nextWsubN0ToRI;
346 }
347 }
348
349 lastN0 = n0;
350 lastLogN0 = logN0;
351 }
352
353 normalizeTransformedData(dataRI, normalization, type);
354 }
355
356
357
358
359
360
361
362
363
364 public Complex[] transform(final double[] f, final TransformType type) {
365 final double[][] dataRI = { f.clone(), new double[f.length] };
366 transformInPlace(dataRI, normalization, type);
367 return TransformUtils.createComplexArray(dataRI);
368 }
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387 public Complex[] transform(final UnivariateFunction f,
388 final double min, final double max, final int n,
389 final TransformType type) {
390
391 final double[] data = FunctionUtils.sample(f, min, max, n);
392 return transform(data, type);
393 }
394
395
396
397
398
399
400
401
402
403 public Complex[] transform(final Complex[] f, final TransformType type) {
404 final double[][] dataRI = TransformUtils.createRealImaginaryArray(f);
405
406 transformInPlace(dataRI, normalization, type);
407
408 return TransformUtils.createComplexArray(dataRI);
409 }
410
411 }