alglib4 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +47 -0
- data/ext/alglib/alglib.cpp +537 -0
- data/ext/alglib/alglib_array_converters.cpp +86 -0
- data/ext/alglib/alglib_array_converters.h +15 -0
- data/ext/alglib/alglib_utils.cpp +10 -0
- data/ext/alglib/alglib_utils.h +6 -0
- data/ext/alglib/alglibinternal.cpp +21749 -0
- data/ext/alglib/alglibinternal.h +2168 -0
- data/ext/alglib/alglibmisc.cpp +9106 -0
- data/ext/alglib/alglibmisc.h +2114 -0
- data/ext/alglib/ap.cpp +20094 -0
- data/ext/alglib/ap.h +7244 -0
- data/ext/alglib/dataanalysis.cpp +52588 -0
- data/ext/alglib/dataanalysis.h +10601 -0
- data/ext/alglib/diffequations.cpp +1342 -0
- data/ext/alglib/diffequations.h +282 -0
- data/ext/alglib/extconf.rb +5 -0
- data/ext/alglib/fasttransforms.cpp +4696 -0
- data/ext/alglib/fasttransforms.h +1018 -0
- data/ext/alglib/integration.cpp +4249 -0
- data/ext/alglib/integration.h +869 -0
- data/ext/alglib/interpolation.cpp +74502 -0
- data/ext/alglib/interpolation.h +12264 -0
- data/ext/alglib/kernels_avx2.cpp +2171 -0
- data/ext/alglib/kernels_avx2.h +201 -0
- data/ext/alglib/kernels_fma.cpp +1065 -0
- data/ext/alglib/kernels_fma.h +137 -0
- data/ext/alglib/kernels_sse2.cpp +735 -0
- data/ext/alglib/kernels_sse2.h +100 -0
- data/ext/alglib/linalg.cpp +65182 -0
- data/ext/alglib/linalg.h +9927 -0
- data/ext/alglib/optimization.cpp +135331 -0
- data/ext/alglib/optimization.h +19235 -0
- data/ext/alglib/solvers.cpp +20488 -0
- data/ext/alglib/solvers.h +4781 -0
- data/ext/alglib/specialfunctions.cpp +10672 -0
- data/ext/alglib/specialfunctions.h +2305 -0
- data/ext/alglib/statistics.cpp +19791 -0
- data/ext/alglib/statistics.h +1359 -0
- data/ext/alglib/stdafx.h +2 -0
- data/gpl2.txt +339 -0
- data/gpl3.txt +674 -0
- data/lib/alglib/version.rb +3 -0
- data/lib/alglib.rb +4 -0
- metadata +101 -0
@@ -0,0 +1,4696 @@
|
|
1
|
+
/*************************************************************************
|
2
|
+
ALGLIB 4.04.0 (source code generated 2024-12-21)
|
3
|
+
Copyright (c) Sergey Bochkanov (ALGLIB project).
|
4
|
+
|
5
|
+
>>> SOURCE LICENSE >>>
|
6
|
+
This program is free software; you can redistribute it and/or modify
|
7
|
+
it under the terms of the GNU General Public License as published by
|
8
|
+
the Free Software Foundation (www.fsf.org); either version 2 of the
|
9
|
+
License, or (at your option) any later version.
|
10
|
+
|
11
|
+
This program is distributed in the hope that it will be useful,
|
12
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
GNU General Public License for more details.
|
15
|
+
|
16
|
+
A copy of the GNU General Public License is available at
|
17
|
+
http://www.fsf.org/licensing/licenses
|
18
|
+
>>> END OF LICENSE >>>
|
19
|
+
*************************************************************************/
|
20
|
+
#ifdef _MSC_VER
|
21
|
+
#define _CRT_SECURE_NO_WARNINGS
|
22
|
+
#endif
|
23
|
+
#include "stdafx.h"
|
24
|
+
#include "fasttransforms.h"
|
25
|
+
|
26
|
+
// disable some irrelevant warnings
|
27
|
+
#if (AE_COMPILER==AE_MSVC) && !defined(AE_ALL_WARNINGS)
|
28
|
+
#pragma warning(disable:4100)
|
29
|
+
#pragma warning(disable:4127)
|
30
|
+
#pragma warning(disable:4611)
|
31
|
+
#pragma warning(disable:4702)
|
32
|
+
#pragma warning(disable:4996)
|
33
|
+
#endif
|
34
|
+
|
35
|
+
/////////////////////////////////////////////////////////////////////////
|
36
|
+
//
|
37
|
+
// THIS SECTION CONTAINS IMPLEMENTATION OF C++ INTERFACE
|
38
|
+
//
|
39
|
+
/////////////////////////////////////////////////////////////////////////
|
40
|
+
namespace alglib
|
41
|
+
{
|
42
|
+
|
43
|
+
|
44
|
+
#if defined(AE_COMPILE_FFT) || !defined(AE_PARTIAL_BUILD)
|
45
|
+
/*************************************************************************
|
46
|
+
1-dimensional complex FFT.
|
47
|
+
|
48
|
+
Array size N may be arbitrary number (composite or prime). Composite N's
|
49
|
+
are handled with cache-oblivious variation of a Cooley-Tukey algorithm.
|
50
|
+
Small prime-factors are transformed using hard coded codelets (similar to
|
51
|
+
FFTW codelets, but without low-level optimization), large prime-factors
|
52
|
+
are handled with Bluestein's algorithm.
|
53
|
+
|
54
|
+
Fastests transforms are for smooth N's (prime factors are 2, 3, 5 only),
|
55
|
+
most fast for powers of 2. When N have prime factors larger than these,
|
56
|
+
but orders of magnitude smaller than N, computations will be about 4 times
|
57
|
+
slower than for nearby highly composite N's. When N itself is prime, speed
|
58
|
+
will be 6 times lower.
|
59
|
+
|
60
|
+
Algorithm has O(N*logN) complexity for any N (composite or prime).
|
61
|
+
|
62
|
+
INPUT PARAMETERS
|
63
|
+
A - array[0..N-1] - complex function to be transformed
|
64
|
+
N - problem size
|
65
|
+
|
66
|
+
OUTPUT PARAMETERS
|
67
|
+
A - DFT of a input array, array[0..N-1]
|
68
|
+
A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
|
69
|
+
|
70
|
+
|
71
|
+
-- ALGLIB --
|
72
|
+
Copyright 29.05.2009 by Bochkanov Sergey
|
73
|
+
*************************************************************************/
|
74
|
+
void fftc1d(complex_1d_array &a, const ae_int_t n, const xparams _xparams)
|
75
|
+
{
|
76
|
+
jmp_buf _break_jump;
|
77
|
+
alglib_impl::ae_state _alglib_env_state;
|
78
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
79
|
+
if( setjmp(_break_jump) )
|
80
|
+
{
|
81
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
82
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
83
|
+
#else
|
84
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
85
|
+
return;
|
86
|
+
#endif
|
87
|
+
}
|
88
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
89
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
90
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
91
|
+
alglib_impl::fftc1d(a.c_ptr(), n, &_alglib_env_state);
|
92
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
93
|
+
return;
|
94
|
+
}
|
95
|
+
|
96
|
+
/*************************************************************************
|
97
|
+
1-dimensional complex FFT.
|
98
|
+
|
99
|
+
Array size N may be arbitrary number (composite or prime). Composite N's
|
100
|
+
are handled with cache-oblivious variation of a Cooley-Tukey algorithm.
|
101
|
+
Small prime-factors are transformed using hard coded codelets (similar to
|
102
|
+
FFTW codelets, but without low-level optimization), large prime-factors
|
103
|
+
are handled with Bluestein's algorithm.
|
104
|
+
|
105
|
+
Fastests transforms are for smooth N's (prime factors are 2, 3, 5 only),
|
106
|
+
most fast for powers of 2. When N have prime factors larger than these,
|
107
|
+
but orders of magnitude smaller than N, computations will be about 4 times
|
108
|
+
slower than for nearby highly composite N's. When N itself is prime, speed
|
109
|
+
will be 6 times lower.
|
110
|
+
|
111
|
+
Algorithm has O(N*logN) complexity for any N (composite or prime).
|
112
|
+
|
113
|
+
INPUT PARAMETERS
|
114
|
+
A - array[0..N-1] - complex function to be transformed
|
115
|
+
N - problem size
|
116
|
+
|
117
|
+
OUTPUT PARAMETERS
|
118
|
+
A - DFT of a input array, array[0..N-1]
|
119
|
+
A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
|
120
|
+
|
121
|
+
|
122
|
+
-- ALGLIB --
|
123
|
+
Copyright 29.05.2009 by Bochkanov Sergey
|
124
|
+
*************************************************************************/
|
125
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
126
|
+
void fftc1d(complex_1d_array &a, const xparams _xparams)
|
127
|
+
{
|
128
|
+
jmp_buf _break_jump;
|
129
|
+
alglib_impl::ae_state _alglib_env_state;
|
130
|
+
ae_int_t n;
|
131
|
+
|
132
|
+
n = a.length();
|
133
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
134
|
+
if( setjmp(_break_jump) )
|
135
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
136
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
137
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
138
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
139
|
+
alglib_impl::fftc1d(a.c_ptr(), n, &_alglib_env_state);
|
140
|
+
|
141
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
142
|
+
return;
|
143
|
+
}
|
144
|
+
#endif
|
145
|
+
|
146
|
+
/*************************************************************************
|
147
|
+
1-dimensional complex inverse FFT.
|
148
|
+
|
149
|
+
Array size N may be arbitrary number (composite or prime). Algorithm has
|
150
|
+
O(N*logN) complexity for any N (composite or prime).
|
151
|
+
|
152
|
+
See FFTC1D() description for more information about algorithm performance.
|
153
|
+
|
154
|
+
INPUT PARAMETERS
|
155
|
+
A - array[0..N-1] - complex array to be transformed
|
156
|
+
N - problem size
|
157
|
+
|
158
|
+
OUTPUT PARAMETERS
|
159
|
+
A - inverse DFT of a input array, array[0..N-1]
|
160
|
+
A_out[j] = SUM(A_in[k]/N*exp(+2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
|
161
|
+
|
162
|
+
|
163
|
+
-- ALGLIB --
|
164
|
+
Copyright 29.05.2009 by Bochkanov Sergey
|
165
|
+
*************************************************************************/
|
166
|
+
void fftc1dinv(complex_1d_array &a, const ae_int_t n, const xparams _xparams)
|
167
|
+
{
|
168
|
+
jmp_buf _break_jump;
|
169
|
+
alglib_impl::ae_state _alglib_env_state;
|
170
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
171
|
+
if( setjmp(_break_jump) )
|
172
|
+
{
|
173
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
174
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
175
|
+
#else
|
176
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
177
|
+
return;
|
178
|
+
#endif
|
179
|
+
}
|
180
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
181
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
182
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
183
|
+
alglib_impl::fftc1dinv(a.c_ptr(), n, &_alglib_env_state);
|
184
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
185
|
+
return;
|
186
|
+
}
|
187
|
+
|
188
|
+
/*************************************************************************
|
189
|
+
1-dimensional complex inverse FFT.
|
190
|
+
|
191
|
+
Array size N may be arbitrary number (composite or prime). Algorithm has
|
192
|
+
O(N*logN) complexity for any N (composite or prime).
|
193
|
+
|
194
|
+
See FFTC1D() description for more information about algorithm performance.
|
195
|
+
|
196
|
+
INPUT PARAMETERS
|
197
|
+
A - array[0..N-1] - complex array to be transformed
|
198
|
+
N - problem size
|
199
|
+
|
200
|
+
OUTPUT PARAMETERS
|
201
|
+
A - inverse DFT of a input array, array[0..N-1]
|
202
|
+
A_out[j] = SUM(A_in[k]/N*exp(+2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
|
203
|
+
|
204
|
+
|
205
|
+
-- ALGLIB --
|
206
|
+
Copyright 29.05.2009 by Bochkanov Sergey
|
207
|
+
*************************************************************************/
|
208
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
209
|
+
void fftc1dinv(complex_1d_array &a, const xparams _xparams)
|
210
|
+
{
|
211
|
+
jmp_buf _break_jump;
|
212
|
+
alglib_impl::ae_state _alglib_env_state;
|
213
|
+
ae_int_t n;
|
214
|
+
|
215
|
+
n = a.length();
|
216
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
217
|
+
if( setjmp(_break_jump) )
|
218
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
219
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
220
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
221
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
222
|
+
alglib_impl::fftc1dinv(a.c_ptr(), n, &_alglib_env_state);
|
223
|
+
|
224
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
225
|
+
return;
|
226
|
+
}
|
227
|
+
#endif
|
228
|
+
|
229
|
+
/*************************************************************************
|
230
|
+
1-dimensional real FFT.
|
231
|
+
|
232
|
+
Algorithm has O(N*logN) complexity for any N (composite or prime).
|
233
|
+
|
234
|
+
INPUT PARAMETERS
|
235
|
+
A - array[0..N-1] - real function to be transformed
|
236
|
+
N - problem size
|
237
|
+
|
238
|
+
OUTPUT PARAMETERS
|
239
|
+
F - DFT of a input array, array[0..N-1]
|
240
|
+
F[j] = SUM(A[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
|
241
|
+
|
242
|
+
NOTE: there is a buffered version of this function, FFTR1DBuf(), which
|
243
|
+
reuses memory previously allocated for A as much as possible.
|
244
|
+
|
245
|
+
NOTE:
|
246
|
+
F[] satisfies symmetry property F[k] = conj(F[N-k]), so just one half
|
247
|
+
of array is usually needed. But for convinience subroutine returns full
|
248
|
+
complex array (with frequencies above N/2), so its result may be used by
|
249
|
+
other FFT-related subroutines.
|
250
|
+
|
251
|
+
|
252
|
+
-- ALGLIB --
|
253
|
+
Copyright 01.06.2009 by Bochkanov Sergey
|
254
|
+
*************************************************************************/
|
255
|
+
void fftr1d(const real_1d_array &a, const ae_int_t n, complex_1d_array &f, const xparams _xparams)
|
256
|
+
{
|
257
|
+
jmp_buf _break_jump;
|
258
|
+
alglib_impl::ae_state _alglib_env_state;
|
259
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
260
|
+
if( setjmp(_break_jump) )
|
261
|
+
{
|
262
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
263
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
264
|
+
#else
|
265
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
266
|
+
return;
|
267
|
+
#endif
|
268
|
+
}
|
269
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
270
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
271
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
272
|
+
alglib_impl::fftr1d(a.c_ptr(), n, f.c_ptr(), &_alglib_env_state);
|
273
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
274
|
+
return;
|
275
|
+
}
|
276
|
+
|
277
|
+
/*************************************************************************
|
278
|
+
1-dimensional real FFT.
|
279
|
+
|
280
|
+
Algorithm has O(N*logN) complexity for any N (composite or prime).
|
281
|
+
|
282
|
+
INPUT PARAMETERS
|
283
|
+
A - array[0..N-1] - real function to be transformed
|
284
|
+
N - problem size
|
285
|
+
|
286
|
+
OUTPUT PARAMETERS
|
287
|
+
F - DFT of a input array, array[0..N-1]
|
288
|
+
F[j] = SUM(A[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
|
289
|
+
|
290
|
+
NOTE: there is a buffered version of this function, FFTR1DBuf(), which
|
291
|
+
reuses memory previously allocated for A as much as possible.
|
292
|
+
|
293
|
+
NOTE:
|
294
|
+
F[] satisfies symmetry property F[k] = conj(F[N-k]), so just one half
|
295
|
+
of array is usually needed. But for convinience subroutine returns full
|
296
|
+
complex array (with frequencies above N/2), so its result may be used by
|
297
|
+
other FFT-related subroutines.
|
298
|
+
|
299
|
+
|
300
|
+
-- ALGLIB --
|
301
|
+
Copyright 01.06.2009 by Bochkanov Sergey
|
302
|
+
*************************************************************************/
|
303
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
304
|
+
void fftr1d(const real_1d_array &a, complex_1d_array &f, const xparams _xparams)
|
305
|
+
{
|
306
|
+
jmp_buf _break_jump;
|
307
|
+
alglib_impl::ae_state _alglib_env_state;
|
308
|
+
ae_int_t n;
|
309
|
+
|
310
|
+
n = a.length();
|
311
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
312
|
+
if( setjmp(_break_jump) )
|
313
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
314
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
315
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
316
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
317
|
+
alglib_impl::fftr1d(a.c_ptr(), n, f.c_ptr(), &_alglib_env_state);
|
318
|
+
|
319
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
320
|
+
return;
|
321
|
+
}
|
322
|
+
#endif
|
323
|
+
|
324
|
+
/*************************************************************************
|
325
|
+
1-dimensional real FFT, a buffered function which does not reallocate F[]
|
326
|
+
if its length is enough to store the result (i.e. it reuses previously
|
327
|
+
allocated memory as much as possible).
|
328
|
+
|
329
|
+
-- ALGLIB --
|
330
|
+
Copyright 01.06.2009 by Bochkanov Sergey
|
331
|
+
*************************************************************************/
|
332
|
+
void fftr1dbuf(const real_1d_array &a, const ae_int_t n, complex_1d_array &f, const xparams _xparams)
|
333
|
+
{
|
334
|
+
jmp_buf _break_jump;
|
335
|
+
alglib_impl::ae_state _alglib_env_state;
|
336
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
337
|
+
if( setjmp(_break_jump) )
|
338
|
+
{
|
339
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
340
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
341
|
+
#else
|
342
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
343
|
+
return;
|
344
|
+
#endif
|
345
|
+
}
|
346
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
347
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
348
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
349
|
+
alglib_impl::fftr1dbuf(a.c_ptr(), n, f.c_ptr(), &_alglib_env_state);
|
350
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
351
|
+
return;
|
352
|
+
}
|
353
|
+
|
354
|
+
/*************************************************************************
|
355
|
+
1-dimensional real FFT, a buffered function which does not reallocate F[]
|
356
|
+
if its length is enough to store the result (i.e. it reuses previously
|
357
|
+
allocated memory as much as possible).
|
358
|
+
|
359
|
+
-- ALGLIB --
|
360
|
+
Copyright 01.06.2009 by Bochkanov Sergey
|
361
|
+
*************************************************************************/
|
362
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
363
|
+
void fftr1dbuf(const real_1d_array &a, complex_1d_array &f, const xparams _xparams)
|
364
|
+
{
|
365
|
+
jmp_buf _break_jump;
|
366
|
+
alglib_impl::ae_state _alglib_env_state;
|
367
|
+
ae_int_t n;
|
368
|
+
|
369
|
+
n = a.length();
|
370
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
371
|
+
if( setjmp(_break_jump) )
|
372
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
373
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
374
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
375
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
376
|
+
alglib_impl::fftr1dbuf(a.c_ptr(), n, f.c_ptr(), &_alglib_env_state);
|
377
|
+
|
378
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
379
|
+
return;
|
380
|
+
}
|
381
|
+
#endif
|
382
|
+
|
383
|
+
/*************************************************************************
|
384
|
+
1-dimensional real inverse FFT.
|
385
|
+
|
386
|
+
Algorithm has O(N*logN) complexity for any N (composite or prime).
|
387
|
+
|
388
|
+
INPUT PARAMETERS
|
389
|
+
F - array[0..floor(N/2)] - frequencies from forward real FFT
|
390
|
+
N - problem size
|
391
|
+
|
392
|
+
OUTPUT PARAMETERS
|
393
|
+
A - inverse DFT of a input array, array[0..N-1]
|
394
|
+
|
395
|
+
NOTE: there is a buffered version of this function, FFTR1DInvBuf(), which
|
396
|
+
reuses memory previously allocated for A as much as possible.
|
397
|
+
|
398
|
+
NOTE:
|
399
|
+
F[] should satisfy symmetry property F[k] = conj(F[N-k]), so just one
|
400
|
+
half of frequencies array is needed - elements from 0 to floor(N/2). F[0]
|
401
|
+
is ALWAYS real. If N is even F[floor(N/2)] is real too. If N is odd, then
|
402
|
+
F[floor(N/2)] has no special properties.
|
403
|
+
|
404
|
+
Relying on properties noted above, FFTR1DInv subroutine uses only elements
|
405
|
+
from 0th to floor(N/2)-th. It ignores imaginary part of F[0], and in case
|
406
|
+
N is even it ignores imaginary part of F[floor(N/2)] too.
|
407
|
+
|
408
|
+
When you call this function using full arguments list - "FFTR1DInv(F,N,A)"
|
409
|
+
- you can pass either either frequencies array with N elements or reduced
|
410
|
+
array with roughly N/2 elements - subroutine will successfully transform
|
411
|
+
both.
|
412
|
+
|
413
|
+
If you call this function using reduced arguments list - "FFTR1DInv(F,A)"
|
414
|
+
- you must pass FULL array with N elements (although higher N/2 are still
|
415
|
+
not used) because array size is used to automatically determine FFT length
|
416
|
+
|
417
|
+
-- ALGLIB --
|
418
|
+
Copyright 01.06.2009 by Bochkanov Sergey
|
419
|
+
*************************************************************************/
|
420
|
+
void fftr1dinv(const complex_1d_array &f, const ae_int_t n, real_1d_array &a, const xparams _xparams)
|
421
|
+
{
|
422
|
+
jmp_buf _break_jump;
|
423
|
+
alglib_impl::ae_state _alglib_env_state;
|
424
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
425
|
+
if( setjmp(_break_jump) )
|
426
|
+
{
|
427
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
428
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
429
|
+
#else
|
430
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
431
|
+
return;
|
432
|
+
#endif
|
433
|
+
}
|
434
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
435
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
436
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
437
|
+
alglib_impl::fftr1dinv(f.c_ptr(), n, a.c_ptr(), &_alglib_env_state);
|
438
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
439
|
+
return;
|
440
|
+
}
|
441
|
+
|
442
|
+
/*************************************************************************
|
443
|
+
1-dimensional real inverse FFT.
|
444
|
+
|
445
|
+
Algorithm has O(N*logN) complexity for any N (composite or prime).
|
446
|
+
|
447
|
+
INPUT PARAMETERS
|
448
|
+
F - array[0..floor(N/2)] - frequencies from forward real FFT
|
449
|
+
N - problem size
|
450
|
+
|
451
|
+
OUTPUT PARAMETERS
|
452
|
+
A - inverse DFT of a input array, array[0..N-1]
|
453
|
+
|
454
|
+
NOTE: there is a buffered version of this function, FFTR1DInvBuf(), which
|
455
|
+
reuses memory previously allocated for A as much as possible.
|
456
|
+
|
457
|
+
NOTE:
|
458
|
+
F[] should satisfy symmetry property F[k] = conj(F[N-k]), so just one
|
459
|
+
half of frequencies array is needed - elements from 0 to floor(N/2). F[0]
|
460
|
+
is ALWAYS real. If N is even F[floor(N/2)] is real too. If N is odd, then
|
461
|
+
F[floor(N/2)] has no special properties.
|
462
|
+
|
463
|
+
Relying on properties noted above, FFTR1DInv subroutine uses only elements
|
464
|
+
from 0th to floor(N/2)-th. It ignores imaginary part of F[0], and in case
|
465
|
+
N is even it ignores imaginary part of F[floor(N/2)] too.
|
466
|
+
|
467
|
+
When you call this function using full arguments list - "FFTR1DInv(F,N,A)"
|
468
|
+
- you can pass either either frequencies array with N elements or reduced
|
469
|
+
array with roughly N/2 elements - subroutine will successfully transform
|
470
|
+
both.
|
471
|
+
|
472
|
+
If you call this function using reduced arguments list - "FFTR1DInv(F,A)"
|
473
|
+
- you must pass FULL array with N elements (although higher N/2 are still
|
474
|
+
not used) because array size is used to automatically determine FFT length
|
475
|
+
|
476
|
+
-- ALGLIB --
|
477
|
+
Copyright 01.06.2009 by Bochkanov Sergey
|
478
|
+
*************************************************************************/
|
479
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
480
|
+
void fftr1dinv(const complex_1d_array &f, real_1d_array &a, const xparams _xparams)
|
481
|
+
{
|
482
|
+
jmp_buf _break_jump;
|
483
|
+
alglib_impl::ae_state _alglib_env_state;
|
484
|
+
ae_int_t n;
|
485
|
+
|
486
|
+
n = f.length();
|
487
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
488
|
+
if( setjmp(_break_jump) )
|
489
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
490
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
491
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
492
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
493
|
+
alglib_impl::fftr1dinv(f.c_ptr(), n, a.c_ptr(), &_alglib_env_state);
|
494
|
+
|
495
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
496
|
+
return;
|
497
|
+
}
|
498
|
+
#endif
|
499
|
+
|
500
|
+
/*************************************************************************
|
501
|
+
1-dimensional real inverse FFT, buffered version, which does not reallocate
|
502
|
+
A[] if its length is enough to store the result (i.e. it reuses previously
|
503
|
+
allocated memory as much as possible).
|
504
|
+
|
505
|
+
-- ALGLIB --
|
506
|
+
Copyright 01.06.2009 by Bochkanov Sergey
|
507
|
+
*************************************************************************/
|
508
|
+
void fftr1dinvbuf(const complex_1d_array &f, const ae_int_t n, real_1d_array &a, const xparams _xparams)
|
509
|
+
{
|
510
|
+
jmp_buf _break_jump;
|
511
|
+
alglib_impl::ae_state _alglib_env_state;
|
512
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
513
|
+
if( setjmp(_break_jump) )
|
514
|
+
{
|
515
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
516
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
517
|
+
#else
|
518
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
519
|
+
return;
|
520
|
+
#endif
|
521
|
+
}
|
522
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
523
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
524
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
525
|
+
alglib_impl::fftr1dinvbuf(f.c_ptr(), n, a.c_ptr(), &_alglib_env_state);
|
526
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
527
|
+
return;
|
528
|
+
}
|
529
|
+
|
530
|
+
/*************************************************************************
|
531
|
+
1-dimensional real inverse FFT, buffered version, which does not reallocate
|
532
|
+
A[] if its length is enough to store the result (i.e. it reuses previously
|
533
|
+
allocated memory as much as possible).
|
534
|
+
|
535
|
+
-- ALGLIB --
|
536
|
+
Copyright 01.06.2009 by Bochkanov Sergey
|
537
|
+
*************************************************************************/
|
538
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
539
|
+
void fftr1dinvbuf(const complex_1d_array &f, real_1d_array &a, const xparams _xparams)
|
540
|
+
{
|
541
|
+
jmp_buf _break_jump;
|
542
|
+
alglib_impl::ae_state _alglib_env_state;
|
543
|
+
ae_int_t n;
|
544
|
+
|
545
|
+
n = f.length();
|
546
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
547
|
+
if( setjmp(_break_jump) )
|
548
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
549
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
550
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
551
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
552
|
+
alglib_impl::fftr1dinvbuf(f.c_ptr(), n, a.c_ptr(), &_alglib_env_state);
|
553
|
+
|
554
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
555
|
+
return;
|
556
|
+
}
|
557
|
+
#endif
|
558
|
+
#endif
|
559
|
+
|
560
|
+
#if defined(AE_COMPILE_FHT) || !defined(AE_PARTIAL_BUILD)
|
561
|
+
/*************************************************************************
|
562
|
+
1-dimensional Fast Hartley Transform.
|
563
|
+
|
564
|
+
Algorithm has O(N*logN) complexity for any N (composite or prime).
|
565
|
+
|
566
|
+
INPUT PARAMETERS
|
567
|
+
A - array[0..N-1] - real function to be transformed
|
568
|
+
N - problem size
|
569
|
+
|
570
|
+
OUTPUT PARAMETERS
|
571
|
+
A - FHT of a input array, array[0..N-1],
|
572
|
+
A_out[k] = sum(A_in[j]*(cos(2*pi*j*k/N)+sin(2*pi*j*k/N)), j=0..N-1)
|
573
|
+
|
574
|
+
|
575
|
+
-- ALGLIB --
|
576
|
+
Copyright 04.06.2009 by Bochkanov Sergey
|
577
|
+
*************************************************************************/
|
578
|
+
void fhtr1d(real_1d_array &a, const ae_int_t n, const xparams _xparams)
|
579
|
+
{
|
580
|
+
jmp_buf _break_jump;
|
581
|
+
alglib_impl::ae_state _alglib_env_state;
|
582
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
583
|
+
if( setjmp(_break_jump) )
|
584
|
+
{
|
585
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
586
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
587
|
+
#else
|
588
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
589
|
+
return;
|
590
|
+
#endif
|
591
|
+
}
|
592
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
593
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
594
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
595
|
+
alglib_impl::fhtr1d(a.c_ptr(), n, &_alglib_env_state);
|
596
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
597
|
+
return;
|
598
|
+
}
|
599
|
+
|
600
|
+
/*************************************************************************
|
601
|
+
1-dimensional inverse FHT.
|
602
|
+
|
603
|
+
Algorithm has O(N*logN) complexity for any N (composite or prime).
|
604
|
+
|
605
|
+
INPUT PARAMETERS
|
606
|
+
A - array[0..N-1] - complex array to be transformed
|
607
|
+
N - problem size
|
608
|
+
|
609
|
+
OUTPUT PARAMETERS
|
610
|
+
A - inverse FHT of a input array, array[0..N-1]
|
611
|
+
|
612
|
+
|
613
|
+
-- ALGLIB --
|
614
|
+
Copyright 29.05.2009 by Bochkanov Sergey
|
615
|
+
*************************************************************************/
|
616
|
+
void fhtr1dinv(real_1d_array &a, const ae_int_t n, const xparams _xparams)
|
617
|
+
{
|
618
|
+
jmp_buf _break_jump;
|
619
|
+
alglib_impl::ae_state _alglib_env_state;
|
620
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
621
|
+
if( setjmp(_break_jump) )
|
622
|
+
{
|
623
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
624
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
625
|
+
#else
|
626
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
627
|
+
return;
|
628
|
+
#endif
|
629
|
+
}
|
630
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
631
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
632
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
633
|
+
alglib_impl::fhtr1dinv(a.c_ptr(), n, &_alglib_env_state);
|
634
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
635
|
+
return;
|
636
|
+
}
|
637
|
+
#endif
|
638
|
+
|
639
|
+
#if defined(AE_COMPILE_CONV) || !defined(AE_PARTIAL_BUILD)
|
640
|
+
/*************************************************************************
|
641
|
+
1-dimensional complex convolution.
|
642
|
+
|
643
|
+
For given A/B returns conv(A,B) (non-circular). Subroutine can automatically
|
644
|
+
choose between three implementations: straightforward O(M*N) formula for
|
645
|
+
very small N (or M), overlap-add algorithm for cases where max(M,N) is
|
646
|
+
significantly larger than min(M,N), but O(M*N) algorithm is too slow, and
|
647
|
+
general FFT-based formula for cases where two previous algorithms are too
|
648
|
+
slow.
|
649
|
+
|
650
|
+
Algorithm has max(M,N)*log(max(M,N)) complexity for any M/N.
|
651
|
+
|
652
|
+
INPUT PARAMETERS
|
653
|
+
A - array[M] - complex function to be transformed
|
654
|
+
M - problem size
|
655
|
+
B - array[N] - complex function to be transformed
|
656
|
+
N - problem size
|
657
|
+
|
658
|
+
OUTPUT PARAMETERS
|
659
|
+
R - convolution: A*B. array[N+M-1]
|
660
|
+
|
661
|
+
NOTE:
|
662
|
+
It is assumed that A is zero at T<0, B is zero too. If one or both
|
663
|
+
functions have non-zero values at negative T's, you can still use this
|
664
|
+
subroutine - just shift its result correspondingly.
|
665
|
+
|
666
|
+
NOTE: there is a buffered version of this function, ConvC1DBuf(), which
|
667
|
+
can reuse space previously allocated in its output parameter R.
|
668
|
+
|
669
|
+
-- ALGLIB --
|
670
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
671
|
+
*************************************************************************/
|
672
|
+
void convc1d(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams)
|
673
|
+
{
|
674
|
+
jmp_buf _break_jump;
|
675
|
+
alglib_impl::ae_state _alglib_env_state;
|
676
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
677
|
+
if( setjmp(_break_jump) )
|
678
|
+
{
|
679
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
680
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
681
|
+
#else
|
682
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
683
|
+
return;
|
684
|
+
#endif
|
685
|
+
}
|
686
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
687
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
688
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
689
|
+
alglib_impl::convc1d(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
|
690
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
691
|
+
return;
|
692
|
+
}
|
693
|
+
|
694
|
+
/*************************************************************************
|
695
|
+
1-dimensional complex convolution, buffered version of ConvC1DBuf(), which
|
696
|
+
does not reallocate R[] if its length is enough to store the result (i.e.
|
697
|
+
it reuses previously allocated memory as much as possible).
|
698
|
+
|
699
|
+
-- ALGLIB --
|
700
|
+
Copyright 30.11.2023 by Bochkanov Sergey
|
701
|
+
*************************************************************************/
|
702
|
+
void convc1dbuf(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams)
|
703
|
+
{
|
704
|
+
jmp_buf _break_jump;
|
705
|
+
alglib_impl::ae_state _alglib_env_state;
|
706
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
707
|
+
if( setjmp(_break_jump) )
|
708
|
+
{
|
709
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
710
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
711
|
+
#else
|
712
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
713
|
+
return;
|
714
|
+
#endif
|
715
|
+
}
|
716
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
717
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
718
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
719
|
+
alglib_impl::convc1dbuf(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
|
720
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
721
|
+
return;
|
722
|
+
}
|
723
|
+
|
724
|
+
/*************************************************************************
|
725
|
+
1-dimensional complex non-circular deconvolution (inverse of ConvC1D()).
|
726
|
+
|
727
|
+
Algorithm has M*log(M)) complexity for any M (composite or prime).
|
728
|
+
|
729
|
+
INPUT PARAMETERS
|
730
|
+
A - array[0..M-1] - convolved signal, A = conv(R, B)
|
731
|
+
M - convolved signal length
|
732
|
+
B - array[0..N-1] - response
|
733
|
+
N - response length, N<=M
|
734
|
+
|
735
|
+
OUTPUT PARAMETERS
|
736
|
+
R - deconvolved signal. array[0..M-N].
|
737
|
+
|
738
|
+
NOTE:
|
739
|
+
deconvolution is unstable process and may result in division by zero
|
740
|
+
(if your response function is degenerate, i.e. has zero Fourier coefficient).
|
741
|
+
|
742
|
+
NOTE:
|
743
|
+
It is assumed that A is zero at T<0, B is zero too. If one or both
|
744
|
+
functions have non-zero values at negative T's, you can still use this
|
745
|
+
subroutine - just shift its result correspondingly.
|
746
|
+
|
747
|
+
NOTE: there is a buffered version of this function, ConvC1DInvBuf(),
|
748
|
+
which can reuse space previously allocated in its output parameter R
|
749
|
+
|
750
|
+
-- ALGLIB --
|
751
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
752
|
+
*************************************************************************/
|
753
|
+
void convc1dinv(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams)
|
754
|
+
{
|
755
|
+
jmp_buf _break_jump;
|
756
|
+
alglib_impl::ae_state _alglib_env_state;
|
757
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
758
|
+
if( setjmp(_break_jump) )
|
759
|
+
{
|
760
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
761
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
762
|
+
#else
|
763
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
764
|
+
return;
|
765
|
+
#endif
|
766
|
+
}
|
767
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
768
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
769
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
770
|
+
alglib_impl::convc1dinv(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
|
771
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
772
|
+
return;
|
773
|
+
}
|
774
|
+
|
775
|
+
/*************************************************************************
|
776
|
+
1-dimensional complex non-circular deconvolution (inverse of ConvC1D()).
|
777
|
+
|
778
|
+
A buffered version, which does not reallocate R[] if its length is enough
|
779
|
+
to store the result (i.e. it reuses previously allocated memory as much as
|
780
|
+
possible).
|
781
|
+
|
782
|
+
-- ALGLIB --
|
783
|
+
Copyright 30.11.2023 by Bochkanov Sergey
|
784
|
+
*************************************************************************/
|
785
|
+
void convc1dinvbuf(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams)
|
786
|
+
{
|
787
|
+
jmp_buf _break_jump;
|
788
|
+
alglib_impl::ae_state _alglib_env_state;
|
789
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
790
|
+
if( setjmp(_break_jump) )
|
791
|
+
{
|
792
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
793
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
794
|
+
#else
|
795
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
796
|
+
return;
|
797
|
+
#endif
|
798
|
+
}
|
799
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
800
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
801
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
802
|
+
alglib_impl::convc1dinvbuf(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
|
803
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
804
|
+
return;
|
805
|
+
}
|
806
|
+
|
807
|
+
/*************************************************************************
|
808
|
+
1-dimensional circular complex convolution.
|
809
|
+
|
810
|
+
For given S/R returns conv(S,R) (circular). Algorithm has linearithmic
|
811
|
+
complexity for any M/N.
|
812
|
+
|
813
|
+
IMPORTANT: normal convolution is commutative, i.e. it is symmetric -
|
814
|
+
conv(A,B)=conv(B,A). Cyclic convolution IS NOT. One function - S - is a
|
815
|
+
signal, periodic function, and another - R - is a response, non-periodic
|
816
|
+
function with limited length.
|
817
|
+
|
818
|
+
INPUT PARAMETERS
|
819
|
+
S - array[M] - complex periodic signal
|
820
|
+
M - problem size
|
821
|
+
B - array[N] - complex non-periodic response
|
822
|
+
N - problem size
|
823
|
+
|
824
|
+
OUTPUT PARAMETERS
|
825
|
+
R - convolution: A*B. array[M].
|
826
|
+
|
827
|
+
NOTE:
|
828
|
+
It is assumed that B is zero at T<0. If it has non-zero values at
|
829
|
+
negative T's, you can still use this subroutine - just shift its result
|
830
|
+
correspondingly.
|
831
|
+
|
832
|
+
NOTE: there is a buffered version of this function, ConvC1DCircularBuf(),
|
833
|
+
which can reuse space previously allocated in its output parameter R.
|
834
|
+
|
835
|
+
-- ALGLIB --
|
836
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
837
|
+
*************************************************************************/
|
838
|
+
void convc1dcircular(const complex_1d_array &s, const ae_int_t m, const complex_1d_array &r, const ae_int_t n, complex_1d_array &c, const xparams _xparams)
|
839
|
+
{
|
840
|
+
jmp_buf _break_jump;
|
841
|
+
alglib_impl::ae_state _alglib_env_state;
|
842
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
843
|
+
if( setjmp(_break_jump) )
|
844
|
+
{
|
845
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
846
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
847
|
+
#else
|
848
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
849
|
+
return;
|
850
|
+
#endif
|
851
|
+
}
|
852
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
853
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
854
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
855
|
+
alglib_impl::convc1dcircular(s.c_ptr(), m, r.c_ptr(), n, c.c_ptr(), &_alglib_env_state);
|
856
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
857
|
+
return;
|
858
|
+
}
|
859
|
+
|
860
|
+
/*************************************************************************
|
861
|
+
1-dimensional circular complex convolution.
|
862
|
+
|
863
|
+
Buffered version of ConvC1DCircular(), which does not reallocate C[] if
|
864
|
+
its length is enough to store the result (i.e. it reuses previously
|
865
|
+
allocated memory as much as possible).
|
866
|
+
|
867
|
+
-- ALGLIB --
|
868
|
+
Copyright 30.11.2023 by Bochkanov Sergey
|
869
|
+
*************************************************************************/
|
870
|
+
void convc1dcircularbuf(const complex_1d_array &s, const ae_int_t m, const complex_1d_array &r, const ae_int_t n, complex_1d_array &c, const xparams _xparams)
|
871
|
+
{
|
872
|
+
jmp_buf _break_jump;
|
873
|
+
alglib_impl::ae_state _alglib_env_state;
|
874
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
875
|
+
if( setjmp(_break_jump) )
|
876
|
+
{
|
877
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
878
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
879
|
+
#else
|
880
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
881
|
+
return;
|
882
|
+
#endif
|
883
|
+
}
|
884
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
885
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
886
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
887
|
+
alglib_impl::convc1dcircularbuf(s.c_ptr(), m, r.c_ptr(), n, c.c_ptr(), &_alglib_env_state);
|
888
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
889
|
+
return;
|
890
|
+
}
|
891
|
+
|
892
|
+
/*************************************************************************
|
893
|
+
1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()).
|
894
|
+
|
895
|
+
Algorithm has M*log(M)) complexity for any M (composite or prime).
|
896
|
+
|
897
|
+
INPUT PARAMETERS
|
898
|
+
A - array[0..M-1] - convolved periodic signal, A = conv(R, B)
|
899
|
+
M - convolved signal length
|
900
|
+
B - array[0..N-1] - non-periodic response
|
901
|
+
N - response length
|
902
|
+
|
903
|
+
OUTPUT PARAMETERS
|
904
|
+
R - deconvolved signal. array[0..M-1].
|
905
|
+
|
906
|
+
NOTE:
|
907
|
+
deconvolution is unstable process and may result in division by zero
|
908
|
+
(if your response function is degenerate, i.e. has zero Fourier coefficient).
|
909
|
+
|
910
|
+
NOTE:
|
911
|
+
It is assumed that B is zero at T<0. If it has non-zero values at
|
912
|
+
negative T's, you can still use this subroutine - just shift its result
|
913
|
+
correspondingly.
|
914
|
+
|
915
|
+
NOTE: there is a buffered version of this function, ConvC1DCircularInvBuf(),
|
916
|
+
which can reuse space previously allocated in its output parameter R.
|
917
|
+
|
918
|
+
-- ALGLIB --
|
919
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
920
|
+
*************************************************************************/
|
921
|
+
void convc1dcircularinv(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams)
|
922
|
+
{
|
923
|
+
jmp_buf _break_jump;
|
924
|
+
alglib_impl::ae_state _alglib_env_state;
|
925
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
926
|
+
if( setjmp(_break_jump) )
|
927
|
+
{
|
928
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
929
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
930
|
+
#else
|
931
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
932
|
+
return;
|
933
|
+
#endif
|
934
|
+
}
|
935
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
936
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
937
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
938
|
+
alglib_impl::convc1dcircularinv(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
|
939
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
940
|
+
return;
|
941
|
+
}
|
942
|
+
|
943
|
+
/*************************************************************************
|
944
|
+
1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()).
|
945
|
+
|
946
|
+
Buffered version of ConvC1DCircularInv(), which does not reallocate R[] if
|
947
|
+
its length is enough to store the result (i.e. it reuses previously
|
948
|
+
allocated memory as much as possible).
|
949
|
+
|
950
|
+
-- ALGLIB --
|
951
|
+
Copyright 30.11.2023 by Bochkanov Sergey
|
952
|
+
*************************************************************************/
|
953
|
+
void convc1dcircularinvbuf(const complex_1d_array &a, const ae_int_t m, const complex_1d_array &b, const ae_int_t n, complex_1d_array &r, const xparams _xparams)
|
954
|
+
{
|
955
|
+
jmp_buf _break_jump;
|
956
|
+
alglib_impl::ae_state _alglib_env_state;
|
957
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
958
|
+
if( setjmp(_break_jump) )
|
959
|
+
{
|
960
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
961
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
962
|
+
#else
|
963
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
964
|
+
return;
|
965
|
+
#endif
|
966
|
+
}
|
967
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
968
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
969
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
970
|
+
alglib_impl::convc1dcircularinvbuf(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
|
971
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
972
|
+
return;
|
973
|
+
}
|
974
|
+
|
975
|
+
/*************************************************************************
|
976
|
+
1-dimensional real convolution.
|
977
|
+
|
978
|
+
Analogous to ConvC1D(), see ConvC1D() comments for more details.
|
979
|
+
|
980
|
+
INPUT PARAMETERS
|
981
|
+
A - array[0..M-1] - real function to be transformed
|
982
|
+
M - problem size
|
983
|
+
B - array[0..N-1] - real function to be transformed
|
984
|
+
N - problem size
|
985
|
+
|
986
|
+
OUTPUT PARAMETERS
|
987
|
+
R - convolution: A*B. array[0..N+M-2].
|
988
|
+
|
989
|
+
NOTE:
|
990
|
+
It is assumed that A is zero at T<0, B is zero too. If one or both
|
991
|
+
functions have non-zero values at negative T's, you can still use this
|
992
|
+
subroutine - just shift its result correspondingly.
|
993
|
+
|
994
|
+
NOTE: there is a buffered version of this function, ConvR1DBuf(),
|
995
|
+
which can reuse space previously allocated in its output parameter R.
|
996
|
+
|
997
|
+
|
998
|
+
-- ALGLIB --
|
999
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
1000
|
+
*************************************************************************/
|
1001
|
+
void convr1d(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r, const xparams _xparams)
|
1002
|
+
{
|
1003
|
+
jmp_buf _break_jump;
|
1004
|
+
alglib_impl::ae_state _alglib_env_state;
|
1005
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
1006
|
+
if( setjmp(_break_jump) )
|
1007
|
+
{
|
1008
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
1009
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
1010
|
+
#else
|
1011
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
1012
|
+
return;
|
1013
|
+
#endif
|
1014
|
+
}
|
1015
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
1016
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
1017
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
1018
|
+
alglib_impl::convr1d(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
|
1019
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
1020
|
+
return;
|
1021
|
+
}
|
1022
|
+
|
1023
|
+
/*************************************************************************
|
1024
|
+
1-dimensional real convolution.
|
1025
|
+
|
1026
|
+
Buffered version of ConvR1D(), which does not reallocate R[] if its length
|
1027
|
+
is enough to store the result (i.e. it reuses previously allocated memory
|
1028
|
+
as much as possible).
|
1029
|
+
|
1030
|
+
-- ALGLIB --
|
1031
|
+
Copyright 30.11.2023 by Bochkanov Sergey
|
1032
|
+
*************************************************************************/
|
1033
|
+
void convr1dbuf(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r, const xparams _xparams)
|
1034
|
+
{
|
1035
|
+
jmp_buf _break_jump;
|
1036
|
+
alglib_impl::ae_state _alglib_env_state;
|
1037
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
1038
|
+
if( setjmp(_break_jump) )
|
1039
|
+
{
|
1040
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
1041
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
1042
|
+
#else
|
1043
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
1044
|
+
return;
|
1045
|
+
#endif
|
1046
|
+
}
|
1047
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
1048
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
1049
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
1050
|
+
alglib_impl::convr1dbuf(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
|
1051
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
1052
|
+
return;
|
1053
|
+
}
|
1054
|
+
|
1055
|
+
/*************************************************************************
|
1056
|
+
1-dimensional real deconvolution (inverse of ConvC1D()).
|
1057
|
+
|
1058
|
+
Algorithm has M*log(M)) complexity for any M (composite or prime).
|
1059
|
+
|
1060
|
+
INPUT PARAMETERS
|
1061
|
+
A - array[0..M-1] - convolved signal, A = conv(R, B)
|
1062
|
+
M - convolved signal length
|
1063
|
+
B - array[0..N-1] - response
|
1064
|
+
N - response length, N<=M
|
1065
|
+
|
1066
|
+
OUTPUT PARAMETERS
|
1067
|
+
R - deconvolved signal. array[0..M-N].
|
1068
|
+
|
1069
|
+
NOTE:
|
1070
|
+
deconvolution is unstable process and may result in division by zero
|
1071
|
+
(if your response function is degenerate, i.e. has zero Fourier coefficient).
|
1072
|
+
|
1073
|
+
NOTE:
|
1074
|
+
It is assumed that A is zero at T<0, B is zero too. If one or both
|
1075
|
+
functions have non-zero values at negative T's, you can still use this
|
1076
|
+
subroutine - just shift its result correspondingly.
|
1077
|
+
|
1078
|
+
NOTE: there is a buffered version of this function, ConvR1DInvBuf(),
|
1079
|
+
which can reuse space previously allocated in its output parameter R.
|
1080
|
+
|
1081
|
+
-- ALGLIB --
|
1082
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
1083
|
+
*************************************************************************/
|
1084
|
+
void convr1dinv(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r, const xparams _xparams)
|
1085
|
+
{
|
1086
|
+
jmp_buf _break_jump;
|
1087
|
+
alglib_impl::ae_state _alglib_env_state;
|
1088
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
1089
|
+
if( setjmp(_break_jump) )
|
1090
|
+
{
|
1091
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
1092
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
1093
|
+
#else
|
1094
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
1095
|
+
return;
|
1096
|
+
#endif
|
1097
|
+
}
|
1098
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
1099
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
1100
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
1101
|
+
alglib_impl::convr1dinv(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
|
1102
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
1103
|
+
return;
|
1104
|
+
}
|
1105
|
+
|
1106
|
+
/*************************************************************************
|
1107
|
+
1-dimensional real deconvolution (inverse of ConvR1D()), buffered version,
|
1108
|
+
which does not reallocate R[] if its length is enough to store the result
|
1109
|
+
(i.e. it reuses previously allocated memory as much as possible).
|
1110
|
+
|
1111
|
+
|
1112
|
+
-- ALGLIB --
|
1113
|
+
Copyright 30.11.2023 by Bochkanov Sergey
|
1114
|
+
*************************************************************************/
|
1115
|
+
void convr1dinvbuf(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r, const xparams _xparams)
|
1116
|
+
{
|
1117
|
+
jmp_buf _break_jump;
|
1118
|
+
alglib_impl::ae_state _alglib_env_state;
|
1119
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
1120
|
+
if( setjmp(_break_jump) )
|
1121
|
+
{
|
1122
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
1123
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
1124
|
+
#else
|
1125
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
1126
|
+
return;
|
1127
|
+
#endif
|
1128
|
+
}
|
1129
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
1130
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
1131
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
1132
|
+
alglib_impl::convr1dinvbuf(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
|
1133
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
1134
|
+
return;
|
1135
|
+
}
|
1136
|
+
|
1137
|
+
/*************************************************************************
|
1138
|
+
1-dimensional circular real convolution.
|
1139
|
+
|
1140
|
+
Analogous to ConvC1DCircular(), see ConvC1DCircular() comments for more details.
|
1141
|
+
|
1142
|
+
INPUT PARAMETERS
|
1143
|
+
S - array[0..M-1] - real signal
|
1144
|
+
M - problem size
|
1145
|
+
B - array[0..N-1] - real response
|
1146
|
+
N - problem size
|
1147
|
+
|
1148
|
+
OUTPUT PARAMETERS
|
1149
|
+
R - convolution: A*B. array[0..M-1].
|
1150
|
+
|
1151
|
+
NOTE:
|
1152
|
+
It is assumed that B is zero at T<0. If it has non-zero values at
|
1153
|
+
negative T's, you can still use this subroutine - just shift its result
|
1154
|
+
correspondingly.
|
1155
|
+
|
1156
|
+
NOTE: there is a buffered version of this function, ConvR1DCurcularBuf(),
|
1157
|
+
which can reuse space previously allocated in its output parameter R.
|
1158
|
+
|
1159
|
+
-- ALGLIB --
|
1160
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
1161
|
+
*************************************************************************/
|
1162
|
+
void convr1dcircular(const real_1d_array &s, const ae_int_t m, const real_1d_array &r, const ae_int_t n, real_1d_array &c, const xparams _xparams)
|
1163
|
+
{
|
1164
|
+
jmp_buf _break_jump;
|
1165
|
+
alglib_impl::ae_state _alglib_env_state;
|
1166
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
1167
|
+
if( setjmp(_break_jump) )
|
1168
|
+
{
|
1169
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
1170
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
1171
|
+
#else
|
1172
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
1173
|
+
return;
|
1174
|
+
#endif
|
1175
|
+
}
|
1176
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
1177
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
1178
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
1179
|
+
alglib_impl::convr1dcircular(s.c_ptr(), m, r.c_ptr(), n, c.c_ptr(), &_alglib_env_state);
|
1180
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
1181
|
+
return;
|
1182
|
+
}
|
1183
|
+
|
1184
|
+
/*************************************************************************
|
1185
|
+
1-dimensional circular real convolution, buffered version, which does not
|
1186
|
+
reallocate C[] if its length is enough to store the result (i.e. it reuses
|
1187
|
+
previously allocated memory as much as possible).
|
1188
|
+
|
1189
|
+
-- ALGLIB --
|
1190
|
+
Copyright 30.11.2023 by Bochkanov Sergey
|
1191
|
+
*************************************************************************/
|
1192
|
+
void convr1dcircularbuf(const real_1d_array &s, const ae_int_t m, const real_1d_array &r, const ae_int_t n, real_1d_array &c, const xparams _xparams)
|
1193
|
+
{
|
1194
|
+
jmp_buf _break_jump;
|
1195
|
+
alglib_impl::ae_state _alglib_env_state;
|
1196
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
1197
|
+
if( setjmp(_break_jump) )
|
1198
|
+
{
|
1199
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
1200
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
1201
|
+
#else
|
1202
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
1203
|
+
return;
|
1204
|
+
#endif
|
1205
|
+
}
|
1206
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
1207
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
1208
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
1209
|
+
alglib_impl::convr1dcircularbuf(s.c_ptr(), m, r.c_ptr(), n, c.c_ptr(), &_alglib_env_state);
|
1210
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
1211
|
+
return;
|
1212
|
+
}
|
1213
|
+
|
1214
|
+
/*************************************************************************
|
1215
|
+
1-dimensional complex deconvolution (inverse of ConvC1D()).
|
1216
|
+
|
1217
|
+
Algorithm has M*log(M)) complexity for any M (composite or prime).
|
1218
|
+
|
1219
|
+
INPUT PARAMETERS
|
1220
|
+
A - array[0..M-1] - convolved signal, A = conv(R, B)
|
1221
|
+
M - convolved signal length
|
1222
|
+
B - array[0..N-1] - response
|
1223
|
+
N - response length
|
1224
|
+
|
1225
|
+
OUTPUT PARAMETERS
|
1226
|
+
R - deconvolved signal. array[0..M-N].
|
1227
|
+
|
1228
|
+
NOTE:
|
1229
|
+
deconvolution is unstable process and may result in division by zero
|
1230
|
+
(if your response function is degenerate, i.e. has zero Fourier coefficient).
|
1231
|
+
|
1232
|
+
NOTE:
|
1233
|
+
It is assumed that B is zero at T<0. If it has non-zero values at
|
1234
|
+
negative T's, you can still use this subroutine - just shift its result
|
1235
|
+
correspondingly.
|
1236
|
+
|
1237
|
+
-- ALGLIB --
|
1238
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
1239
|
+
*************************************************************************/
|
1240
|
+
void convr1dcircularinv(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r, const xparams _xparams)
|
1241
|
+
{
|
1242
|
+
jmp_buf _break_jump;
|
1243
|
+
alglib_impl::ae_state _alglib_env_state;
|
1244
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
1245
|
+
if( setjmp(_break_jump) )
|
1246
|
+
{
|
1247
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
1248
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
1249
|
+
#else
|
1250
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
1251
|
+
return;
|
1252
|
+
#endif
|
1253
|
+
}
|
1254
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
1255
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
1256
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
1257
|
+
alglib_impl::convr1dcircularinv(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
|
1258
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
1259
|
+
return;
|
1260
|
+
}
|
1261
|
+
|
1262
|
+
/*************************************************************************
|
1263
|
+
1-dimensional complex deconvolution, inverse of ConvR1DCircular().
|
1264
|
+
|
1265
|
+
Buffered version, which does not reallocate R[] if its length is enough to
|
1266
|
+
store the result (i.e. it reuses previously allocated memory as much as
|
1267
|
+
possible).
|
1268
|
+
|
1269
|
+
-- ALGLIB --
|
1270
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
1271
|
+
*************************************************************************/
|
1272
|
+
void convr1dcircularinvbuf(const real_1d_array &a, const ae_int_t m, const real_1d_array &b, const ae_int_t n, real_1d_array &r, const xparams _xparams)
|
1273
|
+
{
|
1274
|
+
jmp_buf _break_jump;
|
1275
|
+
alglib_impl::ae_state _alglib_env_state;
|
1276
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
1277
|
+
if( setjmp(_break_jump) )
|
1278
|
+
{
|
1279
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
1280
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
1281
|
+
#else
|
1282
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
1283
|
+
return;
|
1284
|
+
#endif
|
1285
|
+
}
|
1286
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
1287
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
1288
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
1289
|
+
alglib_impl::convr1dcircularinvbuf(a.c_ptr(), m, b.c_ptr(), n, r.c_ptr(), &_alglib_env_state);
|
1290
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
1291
|
+
return;
|
1292
|
+
}
|
1293
|
+
#endif
|
1294
|
+
|
1295
|
+
#if defined(AE_COMPILE_CORR) || !defined(AE_PARTIAL_BUILD)
|
1296
|
+
/*************************************************************************
|
1297
|
+
1-dimensional complex cross-correlation.
|
1298
|
+
|
1299
|
+
For given Pattern/Signal returns corr(Pattern,Signal) (non-circular).
|
1300
|
+
|
1301
|
+
Correlation is calculated using reduction to convolution. Algorithm with
|
1302
|
+
max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info
|
1303
|
+
about performance).
|
1304
|
+
|
1305
|
+
IMPORTANT:
|
1306
|
+
for historical reasons subroutine accepts its parameters in reversed
|
1307
|
+
order: CorrC1D(Signal, Pattern) = Pattern x Signal (using traditional
|
1308
|
+
definition of cross-correlation, denoting cross-correlation as "x").
|
1309
|
+
|
1310
|
+
INPUT PARAMETERS
|
1311
|
+
Signal - array[0..N-1] - complex function to be transformed,
|
1312
|
+
signal containing pattern
|
1313
|
+
N - problem size
|
1314
|
+
Pattern - array[0..M-1] - complex function to be transformed,
|
1315
|
+
pattern to 'search' within a signal
|
1316
|
+
M - problem size
|
1317
|
+
|
1318
|
+
OUTPUT PARAMETERS
|
1319
|
+
R - cross-correlation, array[0..N+M-2]:
|
1320
|
+
* positive lags are stored in R[0..N-1],
|
1321
|
+
R[i] = sum(conj(pattern[j])*signal[i+j]
|
1322
|
+
* negative lags are stored in R[N..N+M-2],
|
1323
|
+
R[N+M-1-i] = sum(conj(pattern[j])*signal[-i+j]
|
1324
|
+
|
1325
|
+
NOTE:
|
1326
|
+
It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero
|
1327
|
+
on [-K..M-1], you can still use this subroutine, just shift result by K.
|
1328
|
+
|
1329
|
+
NOTE: there is a buffered version of this function, CorrC1DBuf(), which
|
1330
|
+
can reuse space previously allocated in its output parameter R.
|
1331
|
+
|
1332
|
+
-- ALGLIB --
|
1333
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
1334
|
+
*************************************************************************/
|
1335
|
+
void corrc1d(const complex_1d_array &signal, const ae_int_t n, const complex_1d_array &pattern, const ae_int_t m, complex_1d_array &r, const xparams _xparams)
|
1336
|
+
{
|
1337
|
+
jmp_buf _break_jump;
|
1338
|
+
alglib_impl::ae_state _alglib_env_state;
|
1339
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
1340
|
+
if( setjmp(_break_jump) )
|
1341
|
+
{
|
1342
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
1343
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
1344
|
+
#else
|
1345
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
1346
|
+
return;
|
1347
|
+
#endif
|
1348
|
+
}
|
1349
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
1350
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
1351
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
1352
|
+
alglib_impl::corrc1d(signal.c_ptr(), n, pattern.c_ptr(), m, r.c_ptr(), &_alglib_env_state);
|
1353
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
1354
|
+
return;
|
1355
|
+
}
|
1356
|
+
|
1357
|
+
/*************************************************************************
|
1358
|
+
1-dimensional complex cross-correlation, a buffered version of CorrC1D()
|
1359
|
+
which does not reallocate R[] if its length is enough to store the result
|
1360
|
+
(i.e. it reuses previously allocated memory as much as possible).
|
1361
|
+
|
1362
|
+
-- ALGLIB --
|
1363
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
1364
|
+
*************************************************************************/
|
1365
|
+
void corrc1dbuf(const complex_1d_array &signal, const ae_int_t n, const complex_1d_array &pattern, const ae_int_t m, complex_1d_array &r, const xparams _xparams)
|
1366
|
+
{
|
1367
|
+
jmp_buf _break_jump;
|
1368
|
+
alglib_impl::ae_state _alglib_env_state;
|
1369
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
1370
|
+
if( setjmp(_break_jump) )
|
1371
|
+
{
|
1372
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
1373
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
1374
|
+
#else
|
1375
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
1376
|
+
return;
|
1377
|
+
#endif
|
1378
|
+
}
|
1379
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
1380
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
1381
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
1382
|
+
alglib_impl::corrc1dbuf(signal.c_ptr(), n, pattern.c_ptr(), m, r.c_ptr(), &_alglib_env_state);
|
1383
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
1384
|
+
return;
|
1385
|
+
}
|
1386
|
+
|
1387
|
+
/*************************************************************************
|
1388
|
+
1-dimensional circular complex cross-correlation.
|
1389
|
+
|
1390
|
+
For given Pattern/Signal returns corr(Pattern,Signal) (circular).
|
1391
|
+
Algorithm has linearithmic complexity for any M/N.
|
1392
|
+
|
1393
|
+
IMPORTANT:
|
1394
|
+
for historical reasons subroutine accepts its parameters in reversed
|
1395
|
+
order: CorrC1DCircular(Signal, Pattern) = Pattern x Signal (using
|
1396
|
+
traditional definition of cross-correlation, denoting cross-correlation
|
1397
|
+
as "x").
|
1398
|
+
|
1399
|
+
INPUT PARAMETERS
|
1400
|
+
Signal - array[0..N-1] - complex function to be transformed,
|
1401
|
+
periodic signal containing pattern
|
1402
|
+
N - problem size
|
1403
|
+
Pattern - array[0..M-1] - complex function to be transformed,
|
1404
|
+
non-periodic pattern to 'search' within a signal
|
1405
|
+
M - problem size
|
1406
|
+
|
1407
|
+
OUTPUT PARAMETERS
|
1408
|
+
R - convolution: A*B. array[0..M-1].
|
1409
|
+
|
1410
|
+
NOTE: there is a buffered version of this function, CorrC1DCircular(),
|
1411
|
+
which can reuse space previously allocated in its output parameter R.
|
1412
|
+
|
1413
|
+
-- ALGLIB --
|
1414
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
1415
|
+
*************************************************************************/
|
1416
|
+
void corrc1dcircular(const complex_1d_array &signal, const ae_int_t m, const complex_1d_array &pattern, const ae_int_t n, complex_1d_array &c, const xparams _xparams)
|
1417
|
+
{
|
1418
|
+
jmp_buf _break_jump;
|
1419
|
+
alglib_impl::ae_state _alglib_env_state;
|
1420
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
1421
|
+
if( setjmp(_break_jump) )
|
1422
|
+
{
|
1423
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
1424
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
1425
|
+
#else
|
1426
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
1427
|
+
return;
|
1428
|
+
#endif
|
1429
|
+
}
|
1430
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
1431
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
1432
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
1433
|
+
alglib_impl::corrc1dcircular(signal.c_ptr(), m, pattern.c_ptr(), n, c.c_ptr(), &_alglib_env_state);
|
1434
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
1435
|
+
return;
|
1436
|
+
}
|
1437
|
+
|
1438
|
+
/*************************************************************************
|
1439
|
+
1-dimensional circular complex cross-correlation.
|
1440
|
+
|
1441
|
+
A buffered function which does not reallocate C[] if its length is enough
|
1442
|
+
to store the result (i.e. it reuses previously allocated memory as much as
|
1443
|
+
possible).
|
1444
|
+
|
1445
|
+
-- ALGLIB --
|
1446
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
1447
|
+
*************************************************************************/
|
1448
|
+
void corrc1dcircularbuf(const complex_1d_array &signal, const ae_int_t m, const complex_1d_array &pattern, const ae_int_t n, complex_1d_array &c, const xparams _xparams)
|
1449
|
+
{
|
1450
|
+
jmp_buf _break_jump;
|
1451
|
+
alglib_impl::ae_state _alglib_env_state;
|
1452
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
1453
|
+
if( setjmp(_break_jump) )
|
1454
|
+
{
|
1455
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
1456
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
1457
|
+
#else
|
1458
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
1459
|
+
return;
|
1460
|
+
#endif
|
1461
|
+
}
|
1462
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
1463
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
1464
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
1465
|
+
alglib_impl::corrc1dcircularbuf(signal.c_ptr(), m, pattern.c_ptr(), n, c.c_ptr(), &_alglib_env_state);
|
1466
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
1467
|
+
return;
|
1468
|
+
}
|
1469
|
+
|
1470
|
+
/*************************************************************************
|
1471
|
+
1-dimensional real cross-correlation.
|
1472
|
+
|
1473
|
+
For given Pattern/Signal returns corr(Pattern,Signal) (non-circular).
|
1474
|
+
|
1475
|
+
Correlation is calculated using reduction to convolution. Algorithm with
|
1476
|
+
max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info
|
1477
|
+
about performance).
|
1478
|
+
|
1479
|
+
IMPORTANT:
|
1480
|
+
for historical reasons subroutine accepts its parameters in reversed
|
1481
|
+
order: CorrR1D(Signal, Pattern) = Pattern x Signal (using traditional
|
1482
|
+
definition of cross-correlation, denoting cross-correlation as "x").
|
1483
|
+
|
1484
|
+
INPUT PARAMETERS
|
1485
|
+
Signal - array[0..N-1] - real function to be transformed,
|
1486
|
+
signal containing pattern
|
1487
|
+
N - problem size
|
1488
|
+
Pattern - array[0..M-1] - real function to be transformed,
|
1489
|
+
pattern to 'search' withing signal
|
1490
|
+
M - problem size
|
1491
|
+
|
1492
|
+
OUTPUT PARAMETERS
|
1493
|
+
R - cross-correlation, array[0..N+M-2]:
|
1494
|
+
* positive lags are stored in R[0..N-1],
|
1495
|
+
R[i] = sum(pattern[j]*signal[i+j]
|
1496
|
+
* negative lags are stored in R[N..N+M-2],
|
1497
|
+
R[N+M-1-i] = sum(pattern[j]*signal[-i+j]
|
1498
|
+
|
1499
|
+
NOTE:
|
1500
|
+
It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero
|
1501
|
+
on [-K..M-1], you can still use this subroutine, just shift result by K.
|
1502
|
+
|
1503
|
+
NOTE: there is a buffered version of this function, CorrR1DBuf(), which
|
1504
|
+
can reuse space previously allocated in its output parameter R.
|
1505
|
+
|
1506
|
+
-- ALGLIB --
|
1507
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
1508
|
+
*************************************************************************/
|
1509
|
+
void corrr1d(const real_1d_array &signal, const ae_int_t n, const real_1d_array &pattern, const ae_int_t m, real_1d_array &r, const xparams _xparams)
|
1510
|
+
{
|
1511
|
+
jmp_buf _break_jump;
|
1512
|
+
alglib_impl::ae_state _alglib_env_state;
|
1513
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
1514
|
+
if( setjmp(_break_jump) )
|
1515
|
+
{
|
1516
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
1517
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
1518
|
+
#else
|
1519
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
1520
|
+
return;
|
1521
|
+
#endif
|
1522
|
+
}
|
1523
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
1524
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
1525
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
1526
|
+
alglib_impl::corrr1d(signal.c_ptr(), n, pattern.c_ptr(), m, r.c_ptr(), &_alglib_env_state);
|
1527
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
1528
|
+
return;
|
1529
|
+
}
|
1530
|
+
|
1531
|
+
/*************************************************************************
|
1532
|
+
1-dimensional real cross-correlation, buffered function, which does not
|
1533
|
+
reallocate R[] if its length is enough to store the result (i.e. it reuses
|
1534
|
+
previously allocated memory as much as possible).
|
1535
|
+
|
1536
|
+
-- ALGLIB --
|
1537
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
1538
|
+
*************************************************************************/
|
1539
|
+
void corrr1dbuf(const real_1d_array &signal, const ae_int_t n, const real_1d_array &pattern, const ae_int_t m, real_1d_array &r, const xparams _xparams)
|
1540
|
+
{
|
1541
|
+
jmp_buf _break_jump;
|
1542
|
+
alglib_impl::ae_state _alglib_env_state;
|
1543
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
1544
|
+
if( setjmp(_break_jump) )
|
1545
|
+
{
|
1546
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
1547
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
1548
|
+
#else
|
1549
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
1550
|
+
return;
|
1551
|
+
#endif
|
1552
|
+
}
|
1553
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
1554
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
1555
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
1556
|
+
alglib_impl::corrr1dbuf(signal.c_ptr(), n, pattern.c_ptr(), m, r.c_ptr(), &_alglib_env_state);
|
1557
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
1558
|
+
return;
|
1559
|
+
}
|
1560
|
+
|
1561
|
+
/*************************************************************************
|
1562
|
+
1-dimensional circular real cross-correlation.
|
1563
|
+
|
1564
|
+
For given Pattern/Signal returns corr(Pattern,Signal) (circular).
|
1565
|
+
Algorithm has linearithmic complexity for any M/N.
|
1566
|
+
|
1567
|
+
IMPORTANT:
|
1568
|
+
for historical reasons subroutine accepts its parameters in reversed
|
1569
|
+
order: CorrR1DCircular(Signal, Pattern) = Pattern x Signal (using
|
1570
|
+
traditional definition of cross-correlation, denoting cross-correlation
|
1571
|
+
as "x").
|
1572
|
+
|
1573
|
+
INPUT PARAMETERS
|
1574
|
+
Signal - array[0..N-1] - real function to be transformed,
|
1575
|
+
periodic signal containing pattern
|
1576
|
+
N - problem size
|
1577
|
+
Pattern - array[0..M-1] - real function to be transformed,
|
1578
|
+
non-periodic pattern to search withing signal
|
1579
|
+
M - problem size
|
1580
|
+
|
1581
|
+
OUTPUT PARAMETERS
|
1582
|
+
R - convolution: A*B. array[0..M-1].
|
1583
|
+
|
1584
|
+
NOTE: there is a buffered version of this function, CorrR1DCircularBuf(),
|
1585
|
+
which can reuse space previously allocated in its output parameter C.
|
1586
|
+
|
1587
|
+
-- ALGLIB --
|
1588
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
1589
|
+
*************************************************************************/
|
1590
|
+
void corrr1dcircular(const real_1d_array &signal, const ae_int_t m, const real_1d_array &pattern, const ae_int_t n, real_1d_array &c, const xparams _xparams)
|
1591
|
+
{
|
1592
|
+
jmp_buf _break_jump;
|
1593
|
+
alglib_impl::ae_state _alglib_env_state;
|
1594
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
1595
|
+
if( setjmp(_break_jump) )
|
1596
|
+
{
|
1597
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
1598
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
1599
|
+
#else
|
1600
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
1601
|
+
return;
|
1602
|
+
#endif
|
1603
|
+
}
|
1604
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
1605
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
1606
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
1607
|
+
alglib_impl::corrr1dcircular(signal.c_ptr(), m, pattern.c_ptr(), n, c.c_ptr(), &_alglib_env_state);
|
1608
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
1609
|
+
return;
|
1610
|
+
}
|
1611
|
+
|
1612
|
+
/*************************************************************************
|
1613
|
+
1-dimensional circular real cross-correlation, buffered version , which
|
1614
|
+
does not reallocate C[] if its length is enough to store the result (i.e.
|
1615
|
+
it reuses previously allocated memory as much as possible).
|
1616
|
+
|
1617
|
+
-- ALGLIB --
|
1618
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
1619
|
+
*************************************************************************/
|
1620
|
+
void corrr1dcircularbuf(const real_1d_array &signal, const ae_int_t m, const real_1d_array &pattern, const ae_int_t n, real_1d_array &c, const xparams _xparams)
|
1621
|
+
{
|
1622
|
+
jmp_buf _break_jump;
|
1623
|
+
alglib_impl::ae_state _alglib_env_state;
|
1624
|
+
alglib_impl::ae_state_init(&_alglib_env_state);
|
1625
|
+
if( setjmp(_break_jump) )
|
1626
|
+
{
|
1627
|
+
#if !defined(AE_NO_EXCEPTIONS)
|
1628
|
+
_ALGLIB_CPP_EXCEPTION(_alglib_env_state.error_msg);
|
1629
|
+
#else
|
1630
|
+
_ALGLIB_SET_ERROR_FLAG(_alglib_env_state.error_msg);
|
1631
|
+
return;
|
1632
|
+
#endif
|
1633
|
+
}
|
1634
|
+
ae_state_set_break_jump(&_alglib_env_state, &_break_jump);
|
1635
|
+
if( _xparams.flags!=(alglib_impl::ae_uint64_t)0x0 )
|
1636
|
+
ae_state_set_flags(&_alglib_env_state, _xparams.flags);
|
1637
|
+
alglib_impl::corrr1dcircularbuf(signal.c_ptr(), m, pattern.c_ptr(), n, c.c_ptr(), &_alglib_env_state);
|
1638
|
+
alglib_impl::ae_state_clear(&_alglib_env_state);
|
1639
|
+
return;
|
1640
|
+
}
|
1641
|
+
#endif
|
1642
|
+
}
|
1643
|
+
|
1644
|
+
/////////////////////////////////////////////////////////////////////////
|
1645
|
+
//
|
1646
|
+
// THIS SECTION CONTAINS IMPLEMENTATION OF COMPUTATIONAL CORE
|
1647
|
+
//
|
1648
|
+
/////////////////////////////////////////////////////////////////////////
|
1649
|
+
namespace alglib_impl
|
1650
|
+
{
|
1651
|
+
#if defined(AE_COMPILE_FFT) || !defined(AE_PARTIAL_BUILD)
|
1652
|
+
|
1653
|
+
|
1654
|
+
#endif
|
1655
|
+
#if defined(AE_COMPILE_FHT) || !defined(AE_PARTIAL_BUILD)
|
1656
|
+
|
1657
|
+
|
1658
|
+
#endif
|
1659
|
+
#if defined(AE_COMPILE_CONV) || !defined(AE_PARTIAL_BUILD)
|
1660
|
+
|
1661
|
+
|
1662
|
+
#endif
|
1663
|
+
#if defined(AE_COMPILE_CORR) || !defined(AE_PARTIAL_BUILD)
|
1664
|
+
|
1665
|
+
|
1666
|
+
#endif
|
1667
|
+
|
1668
|
+
#if defined(AE_COMPILE_FFT) || !defined(AE_PARTIAL_BUILD)
|
1669
|
+
|
1670
|
+
|
1671
|
+
/*************************************************************************
|
1672
|
+
1-dimensional complex FFT.
|
1673
|
+
|
1674
|
+
Array size N may be arbitrary number (composite or prime). Composite N's
|
1675
|
+
are handled with cache-oblivious variation of a Cooley-Tukey algorithm.
|
1676
|
+
Small prime-factors are transformed using hard coded codelets (similar to
|
1677
|
+
FFTW codelets, but without low-level optimization), large prime-factors
|
1678
|
+
are handled with Bluestein's algorithm.
|
1679
|
+
|
1680
|
+
Fastests transforms are for smooth N's (prime factors are 2, 3, 5 only),
|
1681
|
+
most fast for powers of 2. When N have prime factors larger than these,
|
1682
|
+
but orders of magnitude smaller than N, computations will be about 4 times
|
1683
|
+
slower than for nearby highly composite N's. When N itself is prime, speed
|
1684
|
+
will be 6 times lower.
|
1685
|
+
|
1686
|
+
Algorithm has O(N*logN) complexity for any N (composite or prime).
|
1687
|
+
|
1688
|
+
INPUT PARAMETERS
|
1689
|
+
A - array[0..N-1] - complex function to be transformed
|
1690
|
+
N - problem size
|
1691
|
+
|
1692
|
+
OUTPUT PARAMETERS
|
1693
|
+
A - DFT of a input array, array[0..N-1]
|
1694
|
+
A_out[j] = SUM(A_in[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
|
1695
|
+
|
1696
|
+
|
1697
|
+
-- ALGLIB --
|
1698
|
+
Copyright 29.05.2009 by Bochkanov Sergey
|
1699
|
+
*************************************************************************/
|
1700
|
+
void fftc1d(/* Complex */ ae_vector* a, ae_int_t n, ae_state *_state)
|
1701
|
+
{
|
1702
|
+
ae_frame _frame_block;
|
1703
|
+
fasttransformplan plan;
|
1704
|
+
ae_int_t i;
|
1705
|
+
ae_vector buf;
|
1706
|
+
|
1707
|
+
ae_frame_make(_state, &_frame_block);
|
1708
|
+
memset(&plan, 0, sizeof(plan));
|
1709
|
+
memset(&buf, 0, sizeof(buf));
|
1710
|
+
_fasttransformplan_init(&plan, _state, ae_true);
|
1711
|
+
ae_vector_init(&buf, 0, DT_REAL, _state, ae_true);
|
1712
|
+
|
1713
|
+
ae_assert(n>0, "FFTC1D: incorrect N!", _state);
|
1714
|
+
ae_assert(a->cnt>=n, "FFTC1D: Length(A)<N!", _state);
|
1715
|
+
ae_assert(isfinitecvector(a, n, _state), "FFTC1D: A contains infinite or NAN values!", _state);
|
1716
|
+
|
1717
|
+
/*
|
1718
|
+
* Special case: N=1, FFT is just identity transform.
|
1719
|
+
* After this block we assume that N is strictly greater than 1.
|
1720
|
+
*/
|
1721
|
+
if( n==1 )
|
1722
|
+
{
|
1723
|
+
ae_frame_leave(_state);
|
1724
|
+
return;
|
1725
|
+
}
|
1726
|
+
|
1727
|
+
/*
|
1728
|
+
* convert input array to the more convenient format
|
1729
|
+
*/
|
1730
|
+
ae_vector_set_length(&buf, 2*n, _state);
|
1731
|
+
for(i=0; i<=n-1; i++)
|
1732
|
+
{
|
1733
|
+
buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x;
|
1734
|
+
buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y;
|
1735
|
+
}
|
1736
|
+
|
1737
|
+
/*
|
1738
|
+
* Generate plan and execute it.
|
1739
|
+
*
|
1740
|
+
* Plan is a combination of a successive factorizations of N and
|
1741
|
+
* precomputed data. It is much like a FFTW plan, but is not stored
|
1742
|
+
* between subroutine calls and is much simpler.
|
1743
|
+
*/
|
1744
|
+
ftcomplexfftplan(n, 1, &plan, _state);
|
1745
|
+
ftapplyplan(&plan, &buf, 0, 1, _state);
|
1746
|
+
|
1747
|
+
/*
|
1748
|
+
* result
|
1749
|
+
*/
|
1750
|
+
for(i=0; i<=n-1; i++)
|
1751
|
+
{
|
1752
|
+
a->ptr.p_complex[i].x = buf.ptr.p_double[2*i+0];
|
1753
|
+
a->ptr.p_complex[i].y = buf.ptr.p_double[2*i+1];
|
1754
|
+
}
|
1755
|
+
ae_frame_leave(_state);
|
1756
|
+
}
|
1757
|
+
|
1758
|
+
|
1759
|
+
/*************************************************************************
|
1760
|
+
1-dimensional complex inverse FFT.
|
1761
|
+
|
1762
|
+
Array size N may be arbitrary number (composite or prime). Algorithm has
|
1763
|
+
O(N*logN) complexity for any N (composite or prime).
|
1764
|
+
|
1765
|
+
See FFTC1D() description for more information about algorithm performance.
|
1766
|
+
|
1767
|
+
INPUT PARAMETERS
|
1768
|
+
A - array[0..N-1] - complex array to be transformed
|
1769
|
+
N - problem size
|
1770
|
+
|
1771
|
+
OUTPUT PARAMETERS
|
1772
|
+
A - inverse DFT of a input array, array[0..N-1]
|
1773
|
+
A_out[j] = SUM(A_in[k]/N*exp(+2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
|
1774
|
+
|
1775
|
+
|
1776
|
+
-- ALGLIB --
|
1777
|
+
Copyright 29.05.2009 by Bochkanov Sergey
|
1778
|
+
*************************************************************************/
|
1779
|
+
void fftc1dinv(/* Complex */ ae_vector* a, ae_int_t n, ae_state *_state)
|
1780
|
+
{
|
1781
|
+
ae_int_t i;
|
1782
|
+
|
1783
|
+
|
1784
|
+
ae_assert(n>0, "FFTC1DInv: incorrect N!", _state);
|
1785
|
+
ae_assert(a->cnt>=n, "FFTC1DInv: Length(A)<N!", _state);
|
1786
|
+
ae_assert(isfinitecvector(a, n, _state), "FFTC1DInv: A contains infinite or NAN values!", _state);
|
1787
|
+
|
1788
|
+
/*
|
1789
|
+
* Inverse DFT can be expressed in terms of the DFT as
|
1790
|
+
*
|
1791
|
+
* invfft(x) = fft(x')'/N
|
1792
|
+
*
|
1793
|
+
* here x' means conj(x).
|
1794
|
+
*/
|
1795
|
+
for(i=0; i<=n-1; i++)
|
1796
|
+
{
|
1797
|
+
a->ptr.p_complex[i].y = -a->ptr.p_complex[i].y;
|
1798
|
+
}
|
1799
|
+
fftc1d(a, n, _state);
|
1800
|
+
for(i=0; i<=n-1; i++)
|
1801
|
+
{
|
1802
|
+
a->ptr.p_complex[i].x = a->ptr.p_complex[i].x/(double)n;
|
1803
|
+
a->ptr.p_complex[i].y = -a->ptr.p_complex[i].y/(double)n;
|
1804
|
+
}
|
1805
|
+
}
|
1806
|
+
|
1807
|
+
|
1808
|
+
/*************************************************************************
|
1809
|
+
1-dimensional real FFT.
|
1810
|
+
|
1811
|
+
Algorithm has O(N*logN) complexity for any N (composite or prime).
|
1812
|
+
|
1813
|
+
INPUT PARAMETERS
|
1814
|
+
A - array[0..N-1] - real function to be transformed
|
1815
|
+
N - problem size
|
1816
|
+
|
1817
|
+
OUTPUT PARAMETERS
|
1818
|
+
F - DFT of a input array, array[0..N-1]
|
1819
|
+
F[j] = SUM(A[k]*exp(-2*pi*sqrt(-1)*j*k/N), k = 0..N-1)
|
1820
|
+
|
1821
|
+
NOTE: there is a buffered version of this function, FFTR1DBuf(), which
|
1822
|
+
reuses memory previously allocated for A as much as possible.
|
1823
|
+
|
1824
|
+
NOTE:
|
1825
|
+
F[] satisfies symmetry property F[k] = conj(F[N-k]), so just one half
|
1826
|
+
of array is usually needed. But for convinience subroutine returns full
|
1827
|
+
complex array (with frequencies above N/2), so its result may be used by
|
1828
|
+
other FFT-related subroutines.
|
1829
|
+
|
1830
|
+
|
1831
|
+
-- ALGLIB --
|
1832
|
+
Copyright 01.06.2009 by Bochkanov Sergey
|
1833
|
+
*************************************************************************/
|
1834
|
+
void fftr1d(/* Real */ const ae_vector* a,
|
1835
|
+
ae_int_t n,
|
1836
|
+
/* Complex */ ae_vector* f,
|
1837
|
+
ae_state *_state)
|
1838
|
+
{
|
1839
|
+
|
1840
|
+
ae_vector_clear(f);
|
1841
|
+
|
1842
|
+
ae_assert(n>0, "FFTR1D: incorrect N!", _state);
|
1843
|
+
ae_assert(a->cnt>=n, "FFTR1D: Length(A)<N!", _state);
|
1844
|
+
ae_assert(isfinitevector(a, n, _state), "FFTR1D: A contains infinite or NAN values!", _state);
|
1845
|
+
fftr1dbuf(a, n, f, _state);
|
1846
|
+
}
|
1847
|
+
|
1848
|
+
|
1849
|
+
/*************************************************************************
|
1850
|
+
1-dimensional real FFT, a buffered function which does not reallocate F[]
|
1851
|
+
if its length is enough to store the result (i.e. it reuses previously
|
1852
|
+
allocated memory as much as possible).
|
1853
|
+
|
1854
|
+
-- ALGLIB --
|
1855
|
+
Copyright 01.06.2009 by Bochkanov Sergey
|
1856
|
+
*************************************************************************/
|
1857
|
+
void fftr1dbuf(/* Real */ const ae_vector* a,
|
1858
|
+
ae_int_t n,
|
1859
|
+
/* Complex */ ae_vector* f,
|
1860
|
+
ae_state *_state)
|
1861
|
+
{
|
1862
|
+
ae_frame _frame_block;
|
1863
|
+
ae_int_t i;
|
1864
|
+
ae_int_t n2;
|
1865
|
+
ae_int_t idx;
|
1866
|
+
ae_complex hn;
|
1867
|
+
ae_complex hmnc;
|
1868
|
+
ae_complex v;
|
1869
|
+
ae_vector buf;
|
1870
|
+
fasttransformplan plan;
|
1871
|
+
|
1872
|
+
ae_frame_make(_state, &_frame_block);
|
1873
|
+
memset(&buf, 0, sizeof(buf));
|
1874
|
+
memset(&plan, 0, sizeof(plan));
|
1875
|
+
ae_vector_init(&buf, 0, DT_REAL, _state, ae_true);
|
1876
|
+
_fasttransformplan_init(&plan, _state, ae_true);
|
1877
|
+
|
1878
|
+
ae_assert(n>0, "FFTR1DBuf: incorrect N!", _state);
|
1879
|
+
ae_assert(a->cnt>=n, "FFTR1DBuf: Length(A)<N!", _state);
|
1880
|
+
ae_assert(isfinitevector(a, n, _state), "FFTR1DBuf: A contains infinite or NAN values!", _state);
|
1881
|
+
|
1882
|
+
/*
|
1883
|
+
* Special cases:
|
1884
|
+
* * N=1, FFT is just identity transform.
|
1885
|
+
* * N=2, FFT is simple too
|
1886
|
+
*
|
1887
|
+
* After this block we assume that N is strictly greater than 2
|
1888
|
+
*/
|
1889
|
+
if( n==1 )
|
1890
|
+
{
|
1891
|
+
callocv(1, f, _state);
|
1892
|
+
f->ptr.p_complex[0] = ae_complex_from_d(a->ptr.p_double[0]);
|
1893
|
+
ae_frame_leave(_state);
|
1894
|
+
return;
|
1895
|
+
}
|
1896
|
+
if( n==2 )
|
1897
|
+
{
|
1898
|
+
callocv(2, f, _state);
|
1899
|
+
f->ptr.p_complex[0].x = a->ptr.p_double[0]+a->ptr.p_double[1];
|
1900
|
+
f->ptr.p_complex[0].y = (double)(0);
|
1901
|
+
f->ptr.p_complex[1].x = a->ptr.p_double[0]-a->ptr.p_double[1];
|
1902
|
+
f->ptr.p_complex[1].y = (double)(0);
|
1903
|
+
ae_frame_leave(_state);
|
1904
|
+
return;
|
1905
|
+
}
|
1906
|
+
|
1907
|
+
/*
|
1908
|
+
* Choose between odd-size and even-size FFTs
|
1909
|
+
*/
|
1910
|
+
if( n%2==0 )
|
1911
|
+
{
|
1912
|
+
|
1913
|
+
/*
|
1914
|
+
* even-size real FFT, use reduction to the complex task
|
1915
|
+
*/
|
1916
|
+
n2 = n/2;
|
1917
|
+
ae_vector_set_length(&buf, n, _state);
|
1918
|
+
ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,n-1));
|
1919
|
+
ftcomplexfftplan(n2, 1, &plan, _state);
|
1920
|
+
ftapplyplan(&plan, &buf, 0, 1, _state);
|
1921
|
+
callocv(n, f, _state);
|
1922
|
+
for(i=0; i<=n2; i++)
|
1923
|
+
{
|
1924
|
+
idx = 2*(i%n2);
|
1925
|
+
hn.x = buf.ptr.p_double[idx+0];
|
1926
|
+
hn.y = buf.ptr.p_double[idx+1];
|
1927
|
+
idx = 2*((n2-i)%n2);
|
1928
|
+
hmnc.x = buf.ptr.p_double[idx+0];
|
1929
|
+
hmnc.y = -buf.ptr.p_double[idx+1];
|
1930
|
+
v.x = -ae_sin(-(double)2*ae_pi*(double)i/(double)n, _state);
|
1931
|
+
v.y = ae_cos(-(double)2*ae_pi*(double)i/(double)n, _state);
|
1932
|
+
f->ptr.p_complex[i] = ae_c_sub(ae_c_add(hn,hmnc),ae_c_mul(v,ae_c_sub(hn,hmnc)));
|
1933
|
+
f->ptr.p_complex[i].x = 0.5*f->ptr.p_complex[i].x;
|
1934
|
+
f->ptr.p_complex[i].y = 0.5*f->ptr.p_complex[i].y;
|
1935
|
+
}
|
1936
|
+
for(i=n2+1; i<=n-1; i++)
|
1937
|
+
{
|
1938
|
+
f->ptr.p_complex[i] = ae_c_conj(f->ptr.p_complex[n-i], _state);
|
1939
|
+
}
|
1940
|
+
}
|
1941
|
+
else
|
1942
|
+
{
|
1943
|
+
|
1944
|
+
/*
|
1945
|
+
* use complex FFT
|
1946
|
+
*/
|
1947
|
+
callocv(n, f, _state);
|
1948
|
+
for(i=0; i<=n-1; i++)
|
1949
|
+
{
|
1950
|
+
f->ptr.p_complex[i] = ae_complex_from_d(a->ptr.p_double[i]);
|
1951
|
+
}
|
1952
|
+
fftc1d(f, n, _state);
|
1953
|
+
}
|
1954
|
+
ae_frame_leave(_state);
|
1955
|
+
}
|
1956
|
+
|
1957
|
+
|
1958
|
+
/*************************************************************************
|
1959
|
+
1-dimensional real inverse FFT.
|
1960
|
+
|
1961
|
+
Algorithm has O(N*logN) complexity for any N (composite or prime).
|
1962
|
+
|
1963
|
+
INPUT PARAMETERS
|
1964
|
+
F - array[0..floor(N/2)] - frequencies from forward real FFT
|
1965
|
+
N - problem size
|
1966
|
+
|
1967
|
+
OUTPUT PARAMETERS
|
1968
|
+
A - inverse DFT of a input array, array[0..N-1]
|
1969
|
+
|
1970
|
+
NOTE: there is a buffered version of this function, FFTR1DInvBuf(), which
|
1971
|
+
reuses memory previously allocated for A as much as possible.
|
1972
|
+
|
1973
|
+
NOTE:
|
1974
|
+
F[] should satisfy symmetry property F[k] = conj(F[N-k]), so just one
|
1975
|
+
half of frequencies array is needed - elements from 0 to floor(N/2). F[0]
|
1976
|
+
is ALWAYS real. If N is even F[floor(N/2)] is real too. If N is odd, then
|
1977
|
+
F[floor(N/2)] has no special properties.
|
1978
|
+
|
1979
|
+
Relying on properties noted above, FFTR1DInv subroutine uses only elements
|
1980
|
+
from 0th to floor(N/2)-th. It ignores imaginary part of F[0], and in case
|
1981
|
+
N is even it ignores imaginary part of F[floor(N/2)] too.
|
1982
|
+
|
1983
|
+
When you call this function using full arguments list - "FFTR1DInv(F,N,A)"
|
1984
|
+
- you can pass either either frequencies array with N elements or reduced
|
1985
|
+
array with roughly N/2 elements - subroutine will successfully transform
|
1986
|
+
both.
|
1987
|
+
|
1988
|
+
If you call this function using reduced arguments list - "FFTR1DInv(F,A)"
|
1989
|
+
- you must pass FULL array with N elements (although higher N/2 are still
|
1990
|
+
not used) because array size is used to automatically determine FFT length
|
1991
|
+
|
1992
|
+
-- ALGLIB --
|
1993
|
+
Copyright 01.06.2009 by Bochkanov Sergey
|
1994
|
+
*************************************************************************/
|
1995
|
+
void fftr1dinv(/* Complex */ const ae_vector* f,
|
1996
|
+
ae_int_t n,
|
1997
|
+
/* Real */ ae_vector* a,
|
1998
|
+
ae_state *_state)
|
1999
|
+
{
|
2000
|
+
ae_frame _frame_block;
|
2001
|
+
ae_int_t i;
|
2002
|
+
ae_vector h;
|
2003
|
+
ae_vector fh;
|
2004
|
+
|
2005
|
+
ae_frame_make(_state, &_frame_block);
|
2006
|
+
memset(&h, 0, sizeof(h));
|
2007
|
+
memset(&fh, 0, sizeof(fh));
|
2008
|
+
ae_vector_clear(a);
|
2009
|
+
ae_vector_init(&h, 0, DT_REAL, _state, ae_true);
|
2010
|
+
ae_vector_init(&fh, 0, DT_COMPLEX, _state, ae_true);
|
2011
|
+
|
2012
|
+
ae_assert(n>0, "FFTR1DInv: incorrect N!", _state);
|
2013
|
+
ae_assert(f->cnt>=ae_ifloor((double)n/(double)2, _state)+1, "FFTR1DInv: Length(F)<Floor(N/2)+1!", _state);
|
2014
|
+
ae_assert(ae_isfinite(f->ptr.p_complex[0].x, _state), "FFTR1DInv: F contains infinite or NAN values!", _state);
|
2015
|
+
for(i=1; i<=ae_ifloor((double)n/(double)2, _state)-1; i++)
|
2016
|
+
{
|
2017
|
+
ae_assert(ae_isfinite(f->ptr.p_complex[i].x, _state)&&ae_isfinite(f->ptr.p_complex[i].y, _state), "FFTR1DInv: F contains infinite or NAN values!", _state);
|
2018
|
+
}
|
2019
|
+
ae_assert(ae_isfinite(f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].x, _state), "FFTR1DInv: F contains infinite or NAN values!", _state);
|
2020
|
+
if( n%2!=0 )
|
2021
|
+
{
|
2022
|
+
ae_assert(ae_isfinite(f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].y, _state), "FFTR1DInv: F contains infinite or NAN values!", _state);
|
2023
|
+
}
|
2024
|
+
fftr1dinvbuf(f, n, a, _state);
|
2025
|
+
ae_frame_leave(_state);
|
2026
|
+
}
|
2027
|
+
|
2028
|
+
|
2029
|
+
/*************************************************************************
|
2030
|
+
1-dimensional real inverse FFT, buffered version, which does not reallocate
|
2031
|
+
A[] if its length is enough to store the result (i.e. it reuses previously
|
2032
|
+
allocated memory as much as possible).
|
2033
|
+
|
2034
|
+
-- ALGLIB --
|
2035
|
+
Copyright 01.06.2009 by Bochkanov Sergey
|
2036
|
+
*************************************************************************/
|
2037
|
+
void fftr1dinvbuf(/* Complex */ const ae_vector* f,
|
2038
|
+
ae_int_t n,
|
2039
|
+
/* Real */ ae_vector* a,
|
2040
|
+
ae_state *_state)
|
2041
|
+
{
|
2042
|
+
ae_frame _frame_block;
|
2043
|
+
ae_int_t i;
|
2044
|
+
ae_vector h;
|
2045
|
+
ae_vector fh;
|
2046
|
+
|
2047
|
+
ae_frame_make(_state, &_frame_block);
|
2048
|
+
memset(&h, 0, sizeof(h));
|
2049
|
+
memset(&fh, 0, sizeof(fh));
|
2050
|
+
ae_vector_init(&h, 0, DT_REAL, _state, ae_true);
|
2051
|
+
ae_vector_init(&fh, 0, DT_COMPLEX, _state, ae_true);
|
2052
|
+
|
2053
|
+
ae_assert(n>0, "FFTR1DInvBuf: incorrect N!", _state);
|
2054
|
+
ae_assert(f->cnt>=ae_ifloor((double)n/(double)2, _state)+1, "FFTR1DInvBuf: Length(F)<Floor(N/2)+1!", _state);
|
2055
|
+
ae_assert(ae_isfinite(f->ptr.p_complex[0].x, _state), "FFTR1DInvBuf: F contains infinite or NAN values!", _state);
|
2056
|
+
for(i=1; i<=ae_ifloor((double)n/(double)2, _state)-1; i++)
|
2057
|
+
{
|
2058
|
+
ae_assert(ae_isfinite(f->ptr.p_complex[i].x, _state)&&ae_isfinite(f->ptr.p_complex[i].y, _state), "FFTR1DInvBuf: F contains infinite or NAN values!", _state);
|
2059
|
+
}
|
2060
|
+
ae_assert(ae_isfinite(f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].x, _state), "FFTR1DInvBuf: F contains infinite or NAN values!", _state);
|
2061
|
+
if( n%2!=0 )
|
2062
|
+
{
|
2063
|
+
ae_assert(ae_isfinite(f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].y, _state), "FFTR1DInvBuf: F contains infinite or NAN values!", _state);
|
2064
|
+
}
|
2065
|
+
|
2066
|
+
/*
|
2067
|
+
* Special case: N=1, FFT is just identity transform.
|
2068
|
+
* After this block we assume that N is strictly greater than 1.
|
2069
|
+
*/
|
2070
|
+
if( n==1 )
|
2071
|
+
{
|
2072
|
+
rallocv(1, a, _state);
|
2073
|
+
a->ptr.p_double[0] = f->ptr.p_complex[0].x;
|
2074
|
+
ae_frame_leave(_state);
|
2075
|
+
return;
|
2076
|
+
}
|
2077
|
+
|
2078
|
+
/*
|
2079
|
+
* inverse real FFT is reduced to the inverse real FHT,
|
2080
|
+
* which is reduced to the forward real FHT,
|
2081
|
+
* which is reduced to the forward real FFT.
|
2082
|
+
*
|
2083
|
+
* Don't worry, it is really compact and efficient reduction :)
|
2084
|
+
*/
|
2085
|
+
ae_vector_set_length(&h, n, _state);
|
2086
|
+
rallocv(n, a, _state);
|
2087
|
+
h.ptr.p_double[0] = f->ptr.p_complex[0].x;
|
2088
|
+
for(i=1; i<=ae_ifloor((double)n/(double)2, _state)-1; i++)
|
2089
|
+
{
|
2090
|
+
h.ptr.p_double[i] = f->ptr.p_complex[i].x-f->ptr.p_complex[i].y;
|
2091
|
+
h.ptr.p_double[n-i] = f->ptr.p_complex[i].x+f->ptr.p_complex[i].y;
|
2092
|
+
}
|
2093
|
+
if( n%2==0 )
|
2094
|
+
{
|
2095
|
+
h.ptr.p_double[ae_ifloor((double)n/(double)2, _state)] = f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].x;
|
2096
|
+
}
|
2097
|
+
else
|
2098
|
+
{
|
2099
|
+
h.ptr.p_double[ae_ifloor((double)n/(double)2, _state)] = f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].x-f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].y;
|
2100
|
+
h.ptr.p_double[ae_ifloor((double)n/(double)2, _state)+1] = f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].x+f->ptr.p_complex[ae_ifloor((double)n/(double)2, _state)].y;
|
2101
|
+
}
|
2102
|
+
fftr1d(&h, n, &fh, _state);
|
2103
|
+
for(i=0; i<=n-1; i++)
|
2104
|
+
{
|
2105
|
+
a->ptr.p_double[i] = (fh.ptr.p_complex[i].x-fh.ptr.p_complex[i].y)/(double)n;
|
2106
|
+
}
|
2107
|
+
ae_frame_leave(_state);
|
2108
|
+
}
|
2109
|
+
|
2110
|
+
|
2111
|
+
/*************************************************************************
|
2112
|
+
Internal subroutine. Never call it directly!
|
2113
|
+
|
2114
|
+
|
2115
|
+
-- ALGLIB --
|
2116
|
+
Copyright 01.06.2009 by Bochkanov Sergey
|
2117
|
+
*************************************************************************/
|
2118
|
+
void fftr1dinternaleven(/* Real */ ae_vector* a,
|
2119
|
+
ae_int_t n,
|
2120
|
+
/* Real */ ae_vector* buf,
|
2121
|
+
fasttransformplan* plan,
|
2122
|
+
ae_state *_state)
|
2123
|
+
{
|
2124
|
+
double x;
|
2125
|
+
double y;
|
2126
|
+
ae_int_t i;
|
2127
|
+
ae_int_t n2;
|
2128
|
+
ae_int_t idx;
|
2129
|
+
ae_complex hn;
|
2130
|
+
ae_complex hmnc;
|
2131
|
+
ae_complex v;
|
2132
|
+
|
2133
|
+
|
2134
|
+
ae_assert(n>0&&n%2==0, "FFTR1DEvenInplace: incorrect N!", _state);
|
2135
|
+
|
2136
|
+
/*
|
2137
|
+
* Special cases:
|
2138
|
+
* * N=2
|
2139
|
+
*
|
2140
|
+
* After this block we assume that N is strictly greater than 2
|
2141
|
+
*/
|
2142
|
+
if( n==2 )
|
2143
|
+
{
|
2144
|
+
x = a->ptr.p_double[0]+a->ptr.p_double[1];
|
2145
|
+
y = a->ptr.p_double[0]-a->ptr.p_double[1];
|
2146
|
+
a->ptr.p_double[0] = x;
|
2147
|
+
a->ptr.p_double[1] = y;
|
2148
|
+
return;
|
2149
|
+
}
|
2150
|
+
|
2151
|
+
/*
|
2152
|
+
* even-size real FFT, use reduction to the complex task
|
2153
|
+
*/
|
2154
|
+
n2 = n/2;
|
2155
|
+
ae_v_move(&buf->ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,n-1));
|
2156
|
+
ftapplyplan(plan, buf, 0, 1, _state);
|
2157
|
+
a->ptr.p_double[0] = buf->ptr.p_double[0]+buf->ptr.p_double[1];
|
2158
|
+
for(i=1; i<=n2-1; i++)
|
2159
|
+
{
|
2160
|
+
idx = 2*(i%n2);
|
2161
|
+
hn.x = buf->ptr.p_double[idx+0];
|
2162
|
+
hn.y = buf->ptr.p_double[idx+1];
|
2163
|
+
idx = 2*(n2-i);
|
2164
|
+
hmnc.x = buf->ptr.p_double[idx+0];
|
2165
|
+
hmnc.y = -buf->ptr.p_double[idx+1];
|
2166
|
+
v.x = -ae_sin(-(double)2*ae_pi*(double)i/(double)n, _state);
|
2167
|
+
v.y = ae_cos(-(double)2*ae_pi*(double)i/(double)n, _state);
|
2168
|
+
v = ae_c_sub(ae_c_add(hn,hmnc),ae_c_mul(v,ae_c_sub(hn,hmnc)));
|
2169
|
+
a->ptr.p_double[2*i+0] = 0.5*v.x;
|
2170
|
+
a->ptr.p_double[2*i+1] = 0.5*v.y;
|
2171
|
+
}
|
2172
|
+
a->ptr.p_double[1] = buf->ptr.p_double[0]-buf->ptr.p_double[1];
|
2173
|
+
}
|
2174
|
+
|
2175
|
+
|
2176
|
+
/*************************************************************************
|
2177
|
+
Internal subroutine. Never call it directly!
|
2178
|
+
|
2179
|
+
|
2180
|
+
-- ALGLIB --
|
2181
|
+
Copyright 01.06.2009 by Bochkanov Sergey
|
2182
|
+
*************************************************************************/
|
2183
|
+
void fftr1dinvinternaleven(/* Real */ ae_vector* a,
|
2184
|
+
ae_int_t n,
|
2185
|
+
/* Real */ ae_vector* buf,
|
2186
|
+
fasttransformplan* plan,
|
2187
|
+
ae_state *_state)
|
2188
|
+
{
|
2189
|
+
double x;
|
2190
|
+
double y;
|
2191
|
+
double t;
|
2192
|
+
ae_int_t i;
|
2193
|
+
ae_int_t n2;
|
2194
|
+
|
2195
|
+
|
2196
|
+
ae_assert(n>0&&n%2==0, "FFTR1DInvInternalEven: incorrect N!", _state);
|
2197
|
+
|
2198
|
+
/*
|
2199
|
+
* Special cases:
|
2200
|
+
* * N=2
|
2201
|
+
*
|
2202
|
+
* After this block we assume that N is strictly greater than 2
|
2203
|
+
*/
|
2204
|
+
if( n==2 )
|
2205
|
+
{
|
2206
|
+
x = 0.5*(a->ptr.p_double[0]+a->ptr.p_double[1]);
|
2207
|
+
y = 0.5*(a->ptr.p_double[0]-a->ptr.p_double[1]);
|
2208
|
+
a->ptr.p_double[0] = x;
|
2209
|
+
a->ptr.p_double[1] = y;
|
2210
|
+
return;
|
2211
|
+
}
|
2212
|
+
|
2213
|
+
/*
|
2214
|
+
* inverse real FFT is reduced to the inverse real FHT,
|
2215
|
+
* which is reduced to the forward real FHT,
|
2216
|
+
* which is reduced to the forward real FFT.
|
2217
|
+
*
|
2218
|
+
* Don't worry, it is really compact and efficient reduction :)
|
2219
|
+
*/
|
2220
|
+
n2 = n/2;
|
2221
|
+
buf->ptr.p_double[0] = a->ptr.p_double[0];
|
2222
|
+
for(i=1; i<=n2-1; i++)
|
2223
|
+
{
|
2224
|
+
x = a->ptr.p_double[2*i+0];
|
2225
|
+
y = a->ptr.p_double[2*i+1];
|
2226
|
+
buf->ptr.p_double[i] = x-y;
|
2227
|
+
buf->ptr.p_double[n-i] = x+y;
|
2228
|
+
}
|
2229
|
+
buf->ptr.p_double[n2] = a->ptr.p_double[1];
|
2230
|
+
fftr1dinternaleven(buf, n, a, plan, _state);
|
2231
|
+
a->ptr.p_double[0] = buf->ptr.p_double[0]/(double)n;
|
2232
|
+
t = (double)1/(double)n;
|
2233
|
+
for(i=1; i<=n2-1; i++)
|
2234
|
+
{
|
2235
|
+
x = buf->ptr.p_double[2*i+0];
|
2236
|
+
y = buf->ptr.p_double[2*i+1];
|
2237
|
+
a->ptr.p_double[i] = t*(x-y);
|
2238
|
+
a->ptr.p_double[n-i] = t*(x+y);
|
2239
|
+
}
|
2240
|
+
a->ptr.p_double[n2] = buf->ptr.p_double[1]/(double)n;
|
2241
|
+
}
|
2242
|
+
|
2243
|
+
|
2244
|
+
#endif
|
2245
|
+
#if defined(AE_COMPILE_FHT) || !defined(AE_PARTIAL_BUILD)
|
2246
|
+
|
2247
|
+
|
2248
|
+
/*************************************************************************
|
2249
|
+
1-dimensional Fast Hartley Transform.
|
2250
|
+
|
2251
|
+
Algorithm has O(N*logN) complexity for any N (composite or prime).
|
2252
|
+
|
2253
|
+
INPUT PARAMETERS
|
2254
|
+
A - array[0..N-1] - real function to be transformed
|
2255
|
+
N - problem size
|
2256
|
+
|
2257
|
+
OUTPUT PARAMETERS
|
2258
|
+
A - FHT of a input array, array[0..N-1],
|
2259
|
+
A_out[k] = sum(A_in[j]*(cos(2*pi*j*k/N)+sin(2*pi*j*k/N)), j=0..N-1)
|
2260
|
+
|
2261
|
+
|
2262
|
+
-- ALGLIB --
|
2263
|
+
Copyright 04.06.2009 by Bochkanov Sergey
|
2264
|
+
*************************************************************************/
|
2265
|
+
void fhtr1d(/* Real */ ae_vector* a, ae_int_t n, ae_state *_state)
|
2266
|
+
{
|
2267
|
+
ae_frame _frame_block;
|
2268
|
+
ae_int_t i;
|
2269
|
+
ae_vector fa;
|
2270
|
+
|
2271
|
+
ae_frame_make(_state, &_frame_block);
|
2272
|
+
memset(&fa, 0, sizeof(fa));
|
2273
|
+
ae_vector_init(&fa, 0, DT_COMPLEX, _state, ae_true);
|
2274
|
+
|
2275
|
+
ae_assert(n>0, "FHTR1D: incorrect N!", _state);
|
2276
|
+
|
2277
|
+
/*
|
2278
|
+
* Special case: N=1, FHT is just identity transform.
|
2279
|
+
* After this block we assume that N is strictly greater than 1.
|
2280
|
+
*/
|
2281
|
+
if( n==1 )
|
2282
|
+
{
|
2283
|
+
ae_frame_leave(_state);
|
2284
|
+
return;
|
2285
|
+
}
|
2286
|
+
|
2287
|
+
/*
|
2288
|
+
* Reduce FHt to real FFT
|
2289
|
+
*/
|
2290
|
+
fftr1d(a, n, &fa, _state);
|
2291
|
+
for(i=0; i<=n-1; i++)
|
2292
|
+
{
|
2293
|
+
a->ptr.p_double[i] = fa.ptr.p_complex[i].x-fa.ptr.p_complex[i].y;
|
2294
|
+
}
|
2295
|
+
ae_frame_leave(_state);
|
2296
|
+
}
|
2297
|
+
|
2298
|
+
|
2299
|
+
/*************************************************************************
|
2300
|
+
1-dimensional inverse FHT.
|
2301
|
+
|
2302
|
+
Algorithm has O(N*logN) complexity for any N (composite or prime).
|
2303
|
+
|
2304
|
+
INPUT PARAMETERS
|
2305
|
+
A - array[0..N-1] - complex array to be transformed
|
2306
|
+
N - problem size
|
2307
|
+
|
2308
|
+
OUTPUT PARAMETERS
|
2309
|
+
A - inverse FHT of a input array, array[0..N-1]
|
2310
|
+
|
2311
|
+
|
2312
|
+
-- ALGLIB --
|
2313
|
+
Copyright 29.05.2009 by Bochkanov Sergey
|
2314
|
+
*************************************************************************/
|
2315
|
+
void fhtr1dinv(/* Real */ ae_vector* a, ae_int_t n, ae_state *_state)
|
2316
|
+
{
|
2317
|
+
ae_int_t i;
|
2318
|
+
|
2319
|
+
|
2320
|
+
ae_assert(n>0, "FHTR1DInv: incorrect N!", _state);
|
2321
|
+
|
2322
|
+
/*
|
2323
|
+
* Special case: N=1, iFHT is just identity transform.
|
2324
|
+
* After this block we assume that N is strictly greater than 1.
|
2325
|
+
*/
|
2326
|
+
if( n==1 )
|
2327
|
+
{
|
2328
|
+
return;
|
2329
|
+
}
|
2330
|
+
|
2331
|
+
/*
|
2332
|
+
* Inverse FHT can be expressed in terms of the FHT as
|
2333
|
+
*
|
2334
|
+
* invfht(x) = fht(x)/N
|
2335
|
+
*/
|
2336
|
+
fhtr1d(a, n, _state);
|
2337
|
+
for(i=0; i<=n-1; i++)
|
2338
|
+
{
|
2339
|
+
a->ptr.p_double[i] = a->ptr.p_double[i]/(double)n;
|
2340
|
+
}
|
2341
|
+
}
|
2342
|
+
|
2343
|
+
|
2344
|
+
#endif
|
2345
|
+
#if defined(AE_COMPILE_CONV) || !defined(AE_PARTIAL_BUILD)
|
2346
|
+
|
2347
|
+
|
2348
|
+
/*************************************************************************
|
2349
|
+
1-dimensional complex convolution.
|
2350
|
+
|
2351
|
+
For given A/B returns conv(A,B) (non-circular). Subroutine can automatically
|
2352
|
+
choose between three implementations: straightforward O(M*N) formula for
|
2353
|
+
very small N (or M), overlap-add algorithm for cases where max(M,N) is
|
2354
|
+
significantly larger than min(M,N), but O(M*N) algorithm is too slow, and
|
2355
|
+
general FFT-based formula for cases where two previous algorithms are too
|
2356
|
+
slow.
|
2357
|
+
|
2358
|
+
Algorithm has max(M,N)*log(max(M,N)) complexity for any M/N.
|
2359
|
+
|
2360
|
+
INPUT PARAMETERS
|
2361
|
+
A - array[M] - complex function to be transformed
|
2362
|
+
M - problem size
|
2363
|
+
B - array[N] - complex function to be transformed
|
2364
|
+
N - problem size
|
2365
|
+
|
2366
|
+
OUTPUT PARAMETERS
|
2367
|
+
R - convolution: A*B. array[N+M-1]
|
2368
|
+
|
2369
|
+
NOTE:
|
2370
|
+
It is assumed that A is zero at T<0, B is zero too. If one or both
|
2371
|
+
functions have non-zero values at negative T's, you can still use this
|
2372
|
+
subroutine - just shift its result correspondingly.
|
2373
|
+
|
2374
|
+
NOTE: there is a buffered version of this function, ConvC1DBuf(), which
|
2375
|
+
can reuse space previously allocated in its output parameter R.
|
2376
|
+
|
2377
|
+
-- ALGLIB --
|
2378
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
2379
|
+
*************************************************************************/
|
2380
|
+
void convc1d(/* Complex */ const ae_vector* a,
|
2381
|
+
ae_int_t m,
|
2382
|
+
/* Complex */ const ae_vector* b,
|
2383
|
+
ae_int_t n,
|
2384
|
+
/* Complex */ ae_vector* r,
|
2385
|
+
ae_state *_state)
|
2386
|
+
{
|
2387
|
+
|
2388
|
+
ae_vector_clear(r);
|
2389
|
+
|
2390
|
+
ae_assert(n>0&&m>0, "ConvC1D: incorrect N or M!", _state);
|
2391
|
+
convc1dbuf(a, m, b, n, r, _state);
|
2392
|
+
}
|
2393
|
+
|
2394
|
+
|
2395
|
+
/*************************************************************************
|
2396
|
+
1-dimensional complex convolution, buffered version of ConvC1DBuf(), which
|
2397
|
+
does not reallocate R[] if its length is enough to store the result (i.e.
|
2398
|
+
it reuses previously allocated memory as much as possible).
|
2399
|
+
|
2400
|
+
-- ALGLIB --
|
2401
|
+
Copyright 30.11.2023 by Bochkanov Sergey
|
2402
|
+
*************************************************************************/
|
2403
|
+
void convc1dbuf(/* Complex */ const ae_vector* a,
|
2404
|
+
ae_int_t m,
|
2405
|
+
/* Complex */ const ae_vector* b,
|
2406
|
+
ae_int_t n,
|
2407
|
+
/* Complex */ ae_vector* r,
|
2408
|
+
ae_state *_state)
|
2409
|
+
{
|
2410
|
+
|
2411
|
+
|
2412
|
+
ae_assert(n>0&&m>0, "ConvC1DBuf: incorrect N or M!", _state);
|
2413
|
+
|
2414
|
+
/*
|
2415
|
+
* normalize task: make M>=N,
|
2416
|
+
* so A will be longer that B.
|
2417
|
+
*/
|
2418
|
+
if( m<n )
|
2419
|
+
{
|
2420
|
+
convc1dbuf(b, n, a, m, r, _state);
|
2421
|
+
return;
|
2422
|
+
}
|
2423
|
+
convc1dx(a, m, b, n, ae_false, -1, 0, r, _state);
|
2424
|
+
}
|
2425
|
+
|
2426
|
+
|
2427
|
+
/*************************************************************************
|
2428
|
+
1-dimensional complex non-circular deconvolution (inverse of ConvC1D()).
|
2429
|
+
|
2430
|
+
Algorithm has M*log(M)) complexity for any M (composite or prime).
|
2431
|
+
|
2432
|
+
INPUT PARAMETERS
|
2433
|
+
A - array[0..M-1] - convolved signal, A = conv(R, B)
|
2434
|
+
M - convolved signal length
|
2435
|
+
B - array[0..N-1] - response
|
2436
|
+
N - response length, N<=M
|
2437
|
+
|
2438
|
+
OUTPUT PARAMETERS
|
2439
|
+
R - deconvolved signal. array[0..M-N].
|
2440
|
+
|
2441
|
+
NOTE:
|
2442
|
+
deconvolution is unstable process and may result in division by zero
|
2443
|
+
(if your response function is degenerate, i.e. has zero Fourier coefficient).
|
2444
|
+
|
2445
|
+
NOTE:
|
2446
|
+
It is assumed that A is zero at T<0, B is zero too. If one or both
|
2447
|
+
functions have non-zero values at negative T's, you can still use this
|
2448
|
+
subroutine - just shift its result correspondingly.
|
2449
|
+
|
2450
|
+
NOTE: there is a buffered version of this function, ConvC1DInvBuf(),
|
2451
|
+
which can reuse space previously allocated in its output parameter R
|
2452
|
+
|
2453
|
+
-- ALGLIB --
|
2454
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
2455
|
+
*************************************************************************/
|
2456
|
+
void convc1dinv(/* Complex */ const ae_vector* a,
|
2457
|
+
ae_int_t m,
|
2458
|
+
/* Complex */ const ae_vector* b,
|
2459
|
+
ae_int_t n,
|
2460
|
+
/* Complex */ ae_vector* r,
|
2461
|
+
ae_state *_state)
|
2462
|
+
{
|
2463
|
+
|
2464
|
+
ae_vector_clear(r);
|
2465
|
+
|
2466
|
+
ae_assert((n>0&&m>0)&&n<=m, "ConvC1DInv: incorrect N or M!", _state);
|
2467
|
+
convc1dinvbuf(a, m, b, n, r, _state);
|
2468
|
+
}
|
2469
|
+
|
2470
|
+
|
2471
|
+
/*************************************************************************
|
2472
|
+
1-dimensional complex non-circular deconvolution (inverse of ConvC1D()).
|
2473
|
+
|
2474
|
+
A buffered version, which does not reallocate R[] if its length is enough
|
2475
|
+
to store the result (i.e. it reuses previously allocated memory as much as
|
2476
|
+
possible).
|
2477
|
+
|
2478
|
+
-- ALGLIB --
|
2479
|
+
Copyright 30.11.2023 by Bochkanov Sergey
|
2480
|
+
*************************************************************************/
|
2481
|
+
void convc1dinvbuf(/* Complex */ const ae_vector* a,
|
2482
|
+
ae_int_t m,
|
2483
|
+
/* Complex */ const ae_vector* b,
|
2484
|
+
ae_int_t n,
|
2485
|
+
/* Complex */ ae_vector* r,
|
2486
|
+
ae_state *_state)
|
2487
|
+
{
|
2488
|
+
ae_frame _frame_block;
|
2489
|
+
ae_int_t i;
|
2490
|
+
ae_int_t p;
|
2491
|
+
ae_vector buf;
|
2492
|
+
ae_vector buf2;
|
2493
|
+
fasttransformplan plan;
|
2494
|
+
ae_complex c1;
|
2495
|
+
ae_complex c2;
|
2496
|
+
ae_complex c3;
|
2497
|
+
double t;
|
2498
|
+
|
2499
|
+
ae_frame_make(_state, &_frame_block);
|
2500
|
+
memset(&buf, 0, sizeof(buf));
|
2501
|
+
memset(&buf2, 0, sizeof(buf2));
|
2502
|
+
memset(&plan, 0, sizeof(plan));
|
2503
|
+
ae_vector_init(&buf, 0, DT_REAL, _state, ae_true);
|
2504
|
+
ae_vector_init(&buf2, 0, DT_REAL, _state, ae_true);
|
2505
|
+
_fasttransformplan_init(&plan, _state, ae_true);
|
2506
|
+
|
2507
|
+
ae_assert((n>0&&m>0)&&n<=m, "ConvC1DInvBuf: incorrect N or M!", _state);
|
2508
|
+
p = ftbasefindsmooth(m, _state);
|
2509
|
+
ftcomplexfftplan(p, 1, &plan, _state);
|
2510
|
+
ae_vector_set_length(&buf, 2*p, _state);
|
2511
|
+
for(i=0; i<=m-1; i++)
|
2512
|
+
{
|
2513
|
+
buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x;
|
2514
|
+
buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y;
|
2515
|
+
}
|
2516
|
+
for(i=m; i<=p-1; i++)
|
2517
|
+
{
|
2518
|
+
buf.ptr.p_double[2*i+0] = (double)(0);
|
2519
|
+
buf.ptr.p_double[2*i+1] = (double)(0);
|
2520
|
+
}
|
2521
|
+
ae_vector_set_length(&buf2, 2*p, _state);
|
2522
|
+
for(i=0; i<=n-1; i++)
|
2523
|
+
{
|
2524
|
+
buf2.ptr.p_double[2*i+0] = b->ptr.p_complex[i].x;
|
2525
|
+
buf2.ptr.p_double[2*i+1] = b->ptr.p_complex[i].y;
|
2526
|
+
}
|
2527
|
+
for(i=n; i<=p-1; i++)
|
2528
|
+
{
|
2529
|
+
buf2.ptr.p_double[2*i+0] = (double)(0);
|
2530
|
+
buf2.ptr.p_double[2*i+1] = (double)(0);
|
2531
|
+
}
|
2532
|
+
ftapplyplan(&plan, &buf, 0, 1, _state);
|
2533
|
+
ftapplyplan(&plan, &buf2, 0, 1, _state);
|
2534
|
+
for(i=0; i<=p-1; i++)
|
2535
|
+
{
|
2536
|
+
c1.x = buf.ptr.p_double[2*i+0];
|
2537
|
+
c1.y = buf.ptr.p_double[2*i+1];
|
2538
|
+
c2.x = buf2.ptr.p_double[2*i+0];
|
2539
|
+
c2.y = buf2.ptr.p_double[2*i+1];
|
2540
|
+
c3 = ae_c_div(c1,c2);
|
2541
|
+
buf.ptr.p_double[2*i+0] = c3.x;
|
2542
|
+
buf.ptr.p_double[2*i+1] = -c3.y;
|
2543
|
+
}
|
2544
|
+
ftapplyplan(&plan, &buf, 0, 1, _state);
|
2545
|
+
t = (double)1/(double)p;
|
2546
|
+
callocv(m-n+1, r, _state);
|
2547
|
+
for(i=0; i<=m-n; i++)
|
2548
|
+
{
|
2549
|
+
r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0];
|
2550
|
+
r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1];
|
2551
|
+
}
|
2552
|
+
ae_frame_leave(_state);
|
2553
|
+
}
|
2554
|
+
|
2555
|
+
|
2556
|
+
/*************************************************************************
|
2557
|
+
1-dimensional circular complex convolution.
|
2558
|
+
|
2559
|
+
For given S/R returns conv(S,R) (circular). Algorithm has linearithmic
|
2560
|
+
complexity for any M/N.
|
2561
|
+
|
2562
|
+
IMPORTANT: normal convolution is commutative, i.e. it is symmetric -
|
2563
|
+
conv(A,B)=conv(B,A). Cyclic convolution IS NOT. One function - S - is a
|
2564
|
+
signal, periodic function, and another - R - is a response, non-periodic
|
2565
|
+
function with limited length.
|
2566
|
+
|
2567
|
+
INPUT PARAMETERS
|
2568
|
+
S - array[M] - complex periodic signal
|
2569
|
+
M - problem size
|
2570
|
+
B - array[N] - complex non-periodic response
|
2571
|
+
N - problem size
|
2572
|
+
|
2573
|
+
OUTPUT PARAMETERS
|
2574
|
+
R - convolution: A*B. array[M].
|
2575
|
+
|
2576
|
+
NOTE:
|
2577
|
+
It is assumed that B is zero at T<0. If it has non-zero values at
|
2578
|
+
negative T's, you can still use this subroutine - just shift its result
|
2579
|
+
correspondingly.
|
2580
|
+
|
2581
|
+
NOTE: there is a buffered version of this function, ConvC1DCircularBuf(),
|
2582
|
+
which can reuse space previously allocated in its output parameter R.
|
2583
|
+
|
2584
|
+
-- ALGLIB --
|
2585
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
2586
|
+
*************************************************************************/
|
2587
|
+
void convc1dcircular(/* Complex */ const ae_vector* s,
|
2588
|
+
ae_int_t m,
|
2589
|
+
/* Complex */ const ae_vector* r,
|
2590
|
+
ae_int_t n,
|
2591
|
+
/* Complex */ ae_vector* c,
|
2592
|
+
ae_state *_state)
|
2593
|
+
{
|
2594
|
+
|
2595
|
+
ae_vector_clear(c);
|
2596
|
+
|
2597
|
+
ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state);
|
2598
|
+
convc1dcircularbuf(s, m, r, n, c, _state);
|
2599
|
+
}
|
2600
|
+
|
2601
|
+
|
2602
|
+
/*************************************************************************
|
2603
|
+
1-dimensional circular complex convolution.
|
2604
|
+
|
2605
|
+
Buffered version of ConvC1DCircular(), which does not reallocate C[] if
|
2606
|
+
its length is enough to store the result (i.e. it reuses previously
|
2607
|
+
allocated memory as much as possible).
|
2608
|
+
|
2609
|
+
-- ALGLIB --
|
2610
|
+
Copyright 30.11.2023 by Bochkanov Sergey
|
2611
|
+
*************************************************************************/
|
2612
|
+
void convc1dcircularbuf(/* Complex */ const ae_vector* s,
|
2613
|
+
ae_int_t m,
|
2614
|
+
/* Complex */ const ae_vector* r,
|
2615
|
+
ae_int_t n,
|
2616
|
+
/* Complex */ ae_vector* c,
|
2617
|
+
ae_state *_state)
|
2618
|
+
{
|
2619
|
+
ae_frame _frame_block;
|
2620
|
+
ae_vector buf;
|
2621
|
+
ae_int_t i1;
|
2622
|
+
ae_int_t i2;
|
2623
|
+
ae_int_t j2;
|
2624
|
+
|
2625
|
+
ae_frame_make(_state, &_frame_block);
|
2626
|
+
memset(&buf, 0, sizeof(buf));
|
2627
|
+
ae_vector_init(&buf, 0, DT_COMPLEX, _state, ae_true);
|
2628
|
+
|
2629
|
+
ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state);
|
2630
|
+
|
2631
|
+
/*
|
2632
|
+
* normalize task: make M>=N,
|
2633
|
+
* so A will be longer (at least - not shorter) that B.
|
2634
|
+
*/
|
2635
|
+
if( m<n )
|
2636
|
+
{
|
2637
|
+
ae_vector_set_length(&buf, m, _state);
|
2638
|
+
for(i1=0; i1<=m-1; i1++)
|
2639
|
+
{
|
2640
|
+
buf.ptr.p_complex[i1] = ae_complex_from_i(0);
|
2641
|
+
}
|
2642
|
+
i1 = 0;
|
2643
|
+
while(i1<n)
|
2644
|
+
{
|
2645
|
+
i2 = ae_minint(i1+m-1, n-1, _state);
|
2646
|
+
j2 = i2-i1;
|
2647
|
+
ae_v_cadd(&buf.ptr.p_complex[0], 1, &r->ptr.p_complex[i1], 1, "N", ae_v_len(0,j2));
|
2648
|
+
i1 = i1+m;
|
2649
|
+
}
|
2650
|
+
convc1dcircularbuf(s, m, &buf, m, c, _state);
|
2651
|
+
ae_frame_leave(_state);
|
2652
|
+
return;
|
2653
|
+
}
|
2654
|
+
convc1dx(s, m, r, n, ae_true, -1, 0, c, _state);
|
2655
|
+
ae_frame_leave(_state);
|
2656
|
+
}
|
2657
|
+
|
2658
|
+
|
2659
|
+
/*************************************************************************
|
2660
|
+
1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()).
|
2661
|
+
|
2662
|
+
Algorithm has M*log(M)) complexity for any M (composite or prime).
|
2663
|
+
|
2664
|
+
INPUT PARAMETERS
|
2665
|
+
A - array[0..M-1] - convolved periodic signal, A = conv(R, B)
|
2666
|
+
M - convolved signal length
|
2667
|
+
B - array[0..N-1] - non-periodic response
|
2668
|
+
N - response length
|
2669
|
+
|
2670
|
+
OUTPUT PARAMETERS
|
2671
|
+
R - deconvolved signal. array[0..M-1].
|
2672
|
+
|
2673
|
+
NOTE:
|
2674
|
+
deconvolution is unstable process and may result in division by zero
|
2675
|
+
(if your response function is degenerate, i.e. has zero Fourier coefficient).
|
2676
|
+
|
2677
|
+
NOTE:
|
2678
|
+
It is assumed that B is zero at T<0. If it has non-zero values at
|
2679
|
+
negative T's, you can still use this subroutine - just shift its result
|
2680
|
+
correspondingly.
|
2681
|
+
|
2682
|
+
NOTE: there is a buffered version of this function, ConvC1DCircularInvBuf(),
|
2683
|
+
which can reuse space previously allocated in its output parameter R.
|
2684
|
+
|
2685
|
+
-- ALGLIB --
|
2686
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
2687
|
+
*************************************************************************/
|
2688
|
+
void convc1dcircularinv(/* Complex */ const ae_vector* a,
|
2689
|
+
ae_int_t m,
|
2690
|
+
/* Complex */ const ae_vector* b,
|
2691
|
+
ae_int_t n,
|
2692
|
+
/* Complex */ ae_vector* r,
|
2693
|
+
ae_state *_state)
|
2694
|
+
{
|
2695
|
+
|
2696
|
+
ae_vector_clear(r);
|
2697
|
+
|
2698
|
+
ae_assert(n>0&&m>0, "ConvC1DCircularInv: incorrect N or M!", _state);
|
2699
|
+
convc1dcircularinvbuf(a, m, b, n, r, _state);
|
2700
|
+
}
|
2701
|
+
|
2702
|
+
|
2703
|
+
/*************************************************************************
|
2704
|
+
1-dimensional circular complex deconvolution (inverse of ConvC1DCircular()).
|
2705
|
+
|
2706
|
+
Buffered version of ConvC1DCircularInv(), which does not reallocate R[] if
|
2707
|
+
its length is enough to store the result (i.e. it reuses previously
|
2708
|
+
allocated memory as much as possible).
|
2709
|
+
|
2710
|
+
-- ALGLIB --
|
2711
|
+
Copyright 30.11.2023 by Bochkanov Sergey
|
2712
|
+
*************************************************************************/
|
2713
|
+
void convc1dcircularinvbuf(/* Complex */ const ae_vector* a,
|
2714
|
+
ae_int_t m,
|
2715
|
+
/* Complex */ const ae_vector* b,
|
2716
|
+
ae_int_t n,
|
2717
|
+
/* Complex */ ae_vector* r,
|
2718
|
+
ae_state *_state)
|
2719
|
+
{
|
2720
|
+
ae_frame _frame_block;
|
2721
|
+
ae_int_t i;
|
2722
|
+
ae_int_t i1;
|
2723
|
+
ae_int_t i2;
|
2724
|
+
ae_int_t j2;
|
2725
|
+
ae_vector buf;
|
2726
|
+
ae_vector buf2;
|
2727
|
+
ae_vector cbuf;
|
2728
|
+
fasttransformplan plan;
|
2729
|
+
ae_complex c1;
|
2730
|
+
ae_complex c2;
|
2731
|
+
ae_complex c3;
|
2732
|
+
double t;
|
2733
|
+
|
2734
|
+
ae_frame_make(_state, &_frame_block);
|
2735
|
+
memset(&buf, 0, sizeof(buf));
|
2736
|
+
memset(&buf2, 0, sizeof(buf2));
|
2737
|
+
memset(&cbuf, 0, sizeof(cbuf));
|
2738
|
+
memset(&plan, 0, sizeof(plan));
|
2739
|
+
ae_vector_init(&buf, 0, DT_REAL, _state, ae_true);
|
2740
|
+
ae_vector_init(&buf2, 0, DT_REAL, _state, ae_true);
|
2741
|
+
ae_vector_init(&cbuf, 0, DT_COMPLEX, _state, ae_true);
|
2742
|
+
_fasttransformplan_init(&plan, _state, ae_true);
|
2743
|
+
|
2744
|
+
ae_assert(n>0&&m>0, "ConvC1DCircularInv: incorrect N or M!", _state);
|
2745
|
+
|
2746
|
+
/*
|
2747
|
+
* normalize task: make M>=N,
|
2748
|
+
* so A will be longer (at least - not shorter) that B.
|
2749
|
+
*/
|
2750
|
+
if( m<n )
|
2751
|
+
{
|
2752
|
+
ae_vector_set_length(&cbuf, m, _state);
|
2753
|
+
for(i=0; i<=m-1; i++)
|
2754
|
+
{
|
2755
|
+
cbuf.ptr.p_complex[i] = ae_complex_from_i(0);
|
2756
|
+
}
|
2757
|
+
i1 = 0;
|
2758
|
+
while(i1<n)
|
2759
|
+
{
|
2760
|
+
i2 = ae_minint(i1+m-1, n-1, _state);
|
2761
|
+
j2 = i2-i1;
|
2762
|
+
ae_v_cadd(&cbuf.ptr.p_complex[0], 1, &b->ptr.p_complex[i1], 1, "N", ae_v_len(0,j2));
|
2763
|
+
i1 = i1+m;
|
2764
|
+
}
|
2765
|
+
convc1dcircularinvbuf(a, m, &cbuf, m, r, _state);
|
2766
|
+
ae_frame_leave(_state);
|
2767
|
+
return;
|
2768
|
+
}
|
2769
|
+
|
2770
|
+
/*
|
2771
|
+
* Task is normalized
|
2772
|
+
*/
|
2773
|
+
ftcomplexfftplan(m, 1, &plan, _state);
|
2774
|
+
ae_vector_set_length(&buf, 2*m, _state);
|
2775
|
+
for(i=0; i<=m-1; i++)
|
2776
|
+
{
|
2777
|
+
buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x;
|
2778
|
+
buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y;
|
2779
|
+
}
|
2780
|
+
ae_vector_set_length(&buf2, 2*m, _state);
|
2781
|
+
for(i=0; i<=n-1; i++)
|
2782
|
+
{
|
2783
|
+
buf2.ptr.p_double[2*i+0] = b->ptr.p_complex[i].x;
|
2784
|
+
buf2.ptr.p_double[2*i+1] = b->ptr.p_complex[i].y;
|
2785
|
+
}
|
2786
|
+
for(i=n; i<=m-1; i++)
|
2787
|
+
{
|
2788
|
+
buf2.ptr.p_double[2*i+0] = (double)(0);
|
2789
|
+
buf2.ptr.p_double[2*i+1] = (double)(0);
|
2790
|
+
}
|
2791
|
+
ftapplyplan(&plan, &buf, 0, 1, _state);
|
2792
|
+
ftapplyplan(&plan, &buf2, 0, 1, _state);
|
2793
|
+
for(i=0; i<=m-1; i++)
|
2794
|
+
{
|
2795
|
+
c1.x = buf.ptr.p_double[2*i+0];
|
2796
|
+
c1.y = buf.ptr.p_double[2*i+1];
|
2797
|
+
c2.x = buf2.ptr.p_double[2*i+0];
|
2798
|
+
c2.y = buf2.ptr.p_double[2*i+1];
|
2799
|
+
c3 = ae_c_div(c1,c2);
|
2800
|
+
buf.ptr.p_double[2*i+0] = c3.x;
|
2801
|
+
buf.ptr.p_double[2*i+1] = -c3.y;
|
2802
|
+
}
|
2803
|
+
ftapplyplan(&plan, &buf, 0, 1, _state);
|
2804
|
+
t = (double)1/(double)m;
|
2805
|
+
callocv(m, r, _state);
|
2806
|
+
for(i=0; i<=m-1; i++)
|
2807
|
+
{
|
2808
|
+
r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0];
|
2809
|
+
r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1];
|
2810
|
+
}
|
2811
|
+
ae_frame_leave(_state);
|
2812
|
+
}
|
2813
|
+
|
2814
|
+
|
2815
|
+
/*************************************************************************
|
2816
|
+
1-dimensional real convolution.
|
2817
|
+
|
2818
|
+
Analogous to ConvC1D(), see ConvC1D() comments for more details.
|
2819
|
+
|
2820
|
+
INPUT PARAMETERS
|
2821
|
+
A - array[0..M-1] - real function to be transformed
|
2822
|
+
M - problem size
|
2823
|
+
B - array[0..N-1] - real function to be transformed
|
2824
|
+
N - problem size
|
2825
|
+
|
2826
|
+
OUTPUT PARAMETERS
|
2827
|
+
R - convolution: A*B. array[0..N+M-2].
|
2828
|
+
|
2829
|
+
NOTE:
|
2830
|
+
It is assumed that A is zero at T<0, B is zero too. If one or both
|
2831
|
+
functions have non-zero values at negative T's, you can still use this
|
2832
|
+
subroutine - just shift its result correspondingly.
|
2833
|
+
|
2834
|
+
NOTE: there is a buffered version of this function, ConvR1DBuf(),
|
2835
|
+
which can reuse space previously allocated in its output parameter R.
|
2836
|
+
|
2837
|
+
|
2838
|
+
-- ALGLIB --
|
2839
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
2840
|
+
*************************************************************************/
|
2841
|
+
void convr1d(/* Real */ const ae_vector* a,
|
2842
|
+
ae_int_t m,
|
2843
|
+
/* Real */ const ae_vector* b,
|
2844
|
+
ae_int_t n,
|
2845
|
+
/* Real */ ae_vector* r,
|
2846
|
+
ae_state *_state)
|
2847
|
+
{
|
2848
|
+
|
2849
|
+
ae_vector_clear(r);
|
2850
|
+
|
2851
|
+
ae_assert(n>0&&m>0, "ConvR1D: incorrect N or M!", _state);
|
2852
|
+
convr1dbuf(a, m, b, n, r, _state);
|
2853
|
+
}
|
2854
|
+
|
2855
|
+
|
2856
|
+
/*************************************************************************
|
2857
|
+
1-dimensional real convolution.
|
2858
|
+
|
2859
|
+
Buffered version of ConvR1D(), which does not reallocate R[] if its length
|
2860
|
+
is enough to store the result (i.e. it reuses previously allocated memory
|
2861
|
+
as much as possible).
|
2862
|
+
|
2863
|
+
-- ALGLIB --
|
2864
|
+
Copyright 30.11.2023 by Bochkanov Sergey
|
2865
|
+
*************************************************************************/
|
2866
|
+
void convr1dbuf(/* Real */ const ae_vector* a,
|
2867
|
+
ae_int_t m,
|
2868
|
+
/* Real */ const ae_vector* b,
|
2869
|
+
ae_int_t n,
|
2870
|
+
/* Real */ ae_vector* r,
|
2871
|
+
ae_state *_state)
|
2872
|
+
{
|
2873
|
+
|
2874
|
+
|
2875
|
+
ae_assert(n>0&&m>0, "ConvR1DBuf: incorrect N or M!", _state);
|
2876
|
+
|
2877
|
+
/*
|
2878
|
+
* normalize task: make M>=N,
|
2879
|
+
* so A will be longer that B.
|
2880
|
+
*/
|
2881
|
+
if( m<n )
|
2882
|
+
{
|
2883
|
+
convr1dbuf(b, n, a, m, r, _state);
|
2884
|
+
return;
|
2885
|
+
}
|
2886
|
+
convr1dx(a, m, b, n, ae_false, -1, 0, r, _state);
|
2887
|
+
}
|
2888
|
+
|
2889
|
+
|
2890
|
+
/*************************************************************************
|
2891
|
+
1-dimensional real deconvolution (inverse of ConvC1D()).
|
2892
|
+
|
2893
|
+
Algorithm has M*log(M)) complexity for any M (composite or prime).
|
2894
|
+
|
2895
|
+
INPUT PARAMETERS
|
2896
|
+
A - array[0..M-1] - convolved signal, A = conv(R, B)
|
2897
|
+
M - convolved signal length
|
2898
|
+
B - array[0..N-1] - response
|
2899
|
+
N - response length, N<=M
|
2900
|
+
|
2901
|
+
OUTPUT PARAMETERS
|
2902
|
+
R - deconvolved signal. array[0..M-N].
|
2903
|
+
|
2904
|
+
NOTE:
|
2905
|
+
deconvolution is unstable process and may result in division by zero
|
2906
|
+
(if your response function is degenerate, i.e. has zero Fourier coefficient).
|
2907
|
+
|
2908
|
+
NOTE:
|
2909
|
+
It is assumed that A is zero at T<0, B is zero too. If one or both
|
2910
|
+
functions have non-zero values at negative T's, you can still use this
|
2911
|
+
subroutine - just shift its result correspondingly.
|
2912
|
+
|
2913
|
+
NOTE: there is a buffered version of this function, ConvR1DInvBuf(),
|
2914
|
+
which can reuse space previously allocated in its output parameter R.
|
2915
|
+
|
2916
|
+
-- ALGLIB --
|
2917
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
2918
|
+
*************************************************************************/
|
2919
|
+
void convr1dinv(/* Real */ const ae_vector* a,
|
2920
|
+
ae_int_t m,
|
2921
|
+
/* Real */ const ae_vector* b,
|
2922
|
+
ae_int_t n,
|
2923
|
+
/* Real */ ae_vector* r,
|
2924
|
+
ae_state *_state)
|
2925
|
+
{
|
2926
|
+
|
2927
|
+
ae_vector_clear(r);
|
2928
|
+
|
2929
|
+
ae_assert((n>0&&m>0)&&n<=m, "ConvR1DInv: incorrect N or M!", _state);
|
2930
|
+
convr1dinvbuf(a, m, b, n, r, _state);
|
2931
|
+
}
|
2932
|
+
|
2933
|
+
|
2934
|
+
/*************************************************************************
|
2935
|
+
1-dimensional real deconvolution (inverse of ConvR1D()), buffered version,
|
2936
|
+
which does not reallocate R[] if its length is enough to store the result
|
2937
|
+
(i.e. it reuses previously allocated memory as much as possible).
|
2938
|
+
|
2939
|
+
|
2940
|
+
-- ALGLIB --
|
2941
|
+
Copyright 30.11.2023 by Bochkanov Sergey
|
2942
|
+
*************************************************************************/
|
2943
|
+
void convr1dinvbuf(/* Real */ const ae_vector* a,
|
2944
|
+
ae_int_t m,
|
2945
|
+
/* Real */ const ae_vector* b,
|
2946
|
+
ae_int_t n,
|
2947
|
+
/* Real */ ae_vector* r,
|
2948
|
+
ae_state *_state)
|
2949
|
+
{
|
2950
|
+
ae_frame _frame_block;
|
2951
|
+
ae_int_t i;
|
2952
|
+
ae_int_t p;
|
2953
|
+
ae_vector buf;
|
2954
|
+
ae_vector buf2;
|
2955
|
+
ae_vector buf3;
|
2956
|
+
fasttransformplan plan;
|
2957
|
+
ae_complex c1;
|
2958
|
+
ae_complex c2;
|
2959
|
+
ae_complex c3;
|
2960
|
+
|
2961
|
+
ae_frame_make(_state, &_frame_block);
|
2962
|
+
memset(&buf, 0, sizeof(buf));
|
2963
|
+
memset(&buf2, 0, sizeof(buf2));
|
2964
|
+
memset(&buf3, 0, sizeof(buf3));
|
2965
|
+
memset(&plan, 0, sizeof(plan));
|
2966
|
+
ae_vector_init(&buf, 0, DT_REAL, _state, ae_true);
|
2967
|
+
ae_vector_init(&buf2, 0, DT_REAL, _state, ae_true);
|
2968
|
+
ae_vector_init(&buf3, 0, DT_REAL, _state, ae_true);
|
2969
|
+
_fasttransformplan_init(&plan, _state, ae_true);
|
2970
|
+
|
2971
|
+
ae_assert((n>0&&m>0)&&n<=m, "ConvR1DInvBuf: incorrect N or M!", _state);
|
2972
|
+
p = ftbasefindsmootheven(m, _state);
|
2973
|
+
ae_vector_set_length(&buf, p, _state);
|
2974
|
+
ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1));
|
2975
|
+
for(i=m; i<=p-1; i++)
|
2976
|
+
{
|
2977
|
+
buf.ptr.p_double[i] = (double)(0);
|
2978
|
+
}
|
2979
|
+
ae_vector_set_length(&buf2, p, _state);
|
2980
|
+
ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1));
|
2981
|
+
for(i=n; i<=p-1; i++)
|
2982
|
+
{
|
2983
|
+
buf2.ptr.p_double[i] = (double)(0);
|
2984
|
+
}
|
2985
|
+
ae_vector_set_length(&buf3, p, _state);
|
2986
|
+
ftcomplexfftplan(p/2, 1, &plan, _state);
|
2987
|
+
fftr1dinternaleven(&buf, p, &buf3, &plan, _state);
|
2988
|
+
fftr1dinternaleven(&buf2, p, &buf3, &plan, _state);
|
2989
|
+
buf.ptr.p_double[0] = buf.ptr.p_double[0]/buf2.ptr.p_double[0];
|
2990
|
+
buf.ptr.p_double[1] = buf.ptr.p_double[1]/buf2.ptr.p_double[1];
|
2991
|
+
for(i=1; i<=p/2-1; i++)
|
2992
|
+
{
|
2993
|
+
c1.x = buf.ptr.p_double[2*i+0];
|
2994
|
+
c1.y = buf.ptr.p_double[2*i+1];
|
2995
|
+
c2.x = buf2.ptr.p_double[2*i+0];
|
2996
|
+
c2.y = buf2.ptr.p_double[2*i+1];
|
2997
|
+
c3 = ae_c_div(c1,c2);
|
2998
|
+
buf.ptr.p_double[2*i+0] = c3.x;
|
2999
|
+
buf.ptr.p_double[2*i+1] = c3.y;
|
3000
|
+
}
|
3001
|
+
fftr1dinvinternaleven(&buf, p, &buf3, &plan, _state);
|
3002
|
+
rallocv(m-n+1, r, _state);
|
3003
|
+
ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m-n));
|
3004
|
+
ae_frame_leave(_state);
|
3005
|
+
}
|
3006
|
+
|
3007
|
+
|
3008
|
+
/*************************************************************************
|
3009
|
+
1-dimensional circular real convolution.
|
3010
|
+
|
3011
|
+
Analogous to ConvC1DCircular(), see ConvC1DCircular() comments for more details.
|
3012
|
+
|
3013
|
+
INPUT PARAMETERS
|
3014
|
+
S - array[0..M-1] - real signal
|
3015
|
+
M - problem size
|
3016
|
+
B - array[0..N-1] - real response
|
3017
|
+
N - problem size
|
3018
|
+
|
3019
|
+
OUTPUT PARAMETERS
|
3020
|
+
R - convolution: A*B. array[0..M-1].
|
3021
|
+
|
3022
|
+
NOTE:
|
3023
|
+
It is assumed that B is zero at T<0. If it has non-zero values at
|
3024
|
+
negative T's, you can still use this subroutine - just shift its result
|
3025
|
+
correspondingly.
|
3026
|
+
|
3027
|
+
NOTE: there is a buffered version of this function, ConvR1DCurcularBuf(),
|
3028
|
+
which can reuse space previously allocated in its output parameter R.
|
3029
|
+
|
3030
|
+
-- ALGLIB --
|
3031
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
3032
|
+
*************************************************************************/
|
3033
|
+
void convr1dcircular(/* Real */ const ae_vector* s,
|
3034
|
+
ae_int_t m,
|
3035
|
+
/* Real */ const ae_vector* r,
|
3036
|
+
ae_int_t n,
|
3037
|
+
/* Real */ ae_vector* c,
|
3038
|
+
ae_state *_state)
|
3039
|
+
{
|
3040
|
+
|
3041
|
+
ae_vector_clear(c);
|
3042
|
+
|
3043
|
+
ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state);
|
3044
|
+
convr1dcircularbuf(s, m, r, n, c, _state);
|
3045
|
+
}
|
3046
|
+
|
3047
|
+
|
3048
|
+
/*************************************************************************
|
3049
|
+
1-dimensional circular real convolution, buffered version, which does not
|
3050
|
+
reallocate C[] if its length is enough to store the result (i.e. it reuses
|
3051
|
+
previously allocated memory as much as possible).
|
3052
|
+
|
3053
|
+
-- ALGLIB --
|
3054
|
+
Copyright 30.11.2023 by Bochkanov Sergey
|
3055
|
+
*************************************************************************/
|
3056
|
+
void convr1dcircularbuf(/* Real */ const ae_vector* s,
|
3057
|
+
ae_int_t m,
|
3058
|
+
/* Real */ const ae_vector* r,
|
3059
|
+
ae_int_t n,
|
3060
|
+
/* Real */ ae_vector* c,
|
3061
|
+
ae_state *_state)
|
3062
|
+
{
|
3063
|
+
ae_frame _frame_block;
|
3064
|
+
ae_vector buf;
|
3065
|
+
ae_int_t i1;
|
3066
|
+
ae_int_t i2;
|
3067
|
+
ae_int_t j2;
|
3068
|
+
|
3069
|
+
ae_frame_make(_state, &_frame_block);
|
3070
|
+
memset(&buf, 0, sizeof(buf));
|
3071
|
+
ae_vector_init(&buf, 0, DT_REAL, _state, ae_true);
|
3072
|
+
|
3073
|
+
ae_assert(n>0&&m>0, "ConvC1DCircularBuf: incorrect N or M!", _state);
|
3074
|
+
|
3075
|
+
/*
|
3076
|
+
* normalize task: make M>=N,
|
3077
|
+
* so A will be longer (at least - not shorter) that B.
|
3078
|
+
*/
|
3079
|
+
if( m<n )
|
3080
|
+
{
|
3081
|
+
ae_vector_set_length(&buf, m, _state);
|
3082
|
+
for(i1=0; i1<=m-1; i1++)
|
3083
|
+
{
|
3084
|
+
buf.ptr.p_double[i1] = (double)(0);
|
3085
|
+
}
|
3086
|
+
i1 = 0;
|
3087
|
+
while(i1<n)
|
3088
|
+
{
|
3089
|
+
i2 = ae_minint(i1+m-1, n-1, _state);
|
3090
|
+
j2 = i2-i1;
|
3091
|
+
ae_v_add(&buf.ptr.p_double[0], 1, &r->ptr.p_double[i1], 1, ae_v_len(0,j2));
|
3092
|
+
i1 = i1+m;
|
3093
|
+
}
|
3094
|
+
convr1dcircularbuf(s, m, &buf, m, c, _state);
|
3095
|
+
ae_frame_leave(_state);
|
3096
|
+
return;
|
3097
|
+
}
|
3098
|
+
|
3099
|
+
/*
|
3100
|
+
* reduce to usual convolution
|
3101
|
+
*/
|
3102
|
+
convr1dx(s, m, r, n, ae_true, -1, 0, c, _state);
|
3103
|
+
ae_frame_leave(_state);
|
3104
|
+
}
|
3105
|
+
|
3106
|
+
|
3107
|
+
/*************************************************************************
|
3108
|
+
1-dimensional complex deconvolution (inverse of ConvC1D()).
|
3109
|
+
|
3110
|
+
Algorithm has M*log(M)) complexity for any M (composite or prime).
|
3111
|
+
|
3112
|
+
INPUT PARAMETERS
|
3113
|
+
A - array[0..M-1] - convolved signal, A = conv(R, B)
|
3114
|
+
M - convolved signal length
|
3115
|
+
B - array[0..N-1] - response
|
3116
|
+
N - response length
|
3117
|
+
|
3118
|
+
OUTPUT PARAMETERS
|
3119
|
+
R - deconvolved signal. array[0..M-N].
|
3120
|
+
|
3121
|
+
NOTE:
|
3122
|
+
deconvolution is unstable process and may result in division by zero
|
3123
|
+
(if your response function is degenerate, i.e. has zero Fourier coefficient).
|
3124
|
+
|
3125
|
+
NOTE:
|
3126
|
+
It is assumed that B is zero at T<0. If it has non-zero values at
|
3127
|
+
negative T's, you can still use this subroutine - just shift its result
|
3128
|
+
correspondingly.
|
3129
|
+
|
3130
|
+
-- ALGLIB --
|
3131
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
3132
|
+
*************************************************************************/
|
3133
|
+
void convr1dcircularinv(/* Real */ const ae_vector* a,
|
3134
|
+
ae_int_t m,
|
3135
|
+
/* Real */ const ae_vector* b,
|
3136
|
+
ae_int_t n,
|
3137
|
+
/* Real */ ae_vector* r,
|
3138
|
+
ae_state *_state)
|
3139
|
+
{
|
3140
|
+
|
3141
|
+
ae_vector_clear(r);
|
3142
|
+
|
3143
|
+
ae_assert(n>0&&m>0, "ConvR1DCircularInv: incorrect N or M!", _state);
|
3144
|
+
convr1dcircularinvbuf(a, m, b, n, r, _state);
|
3145
|
+
}
|
3146
|
+
|
3147
|
+
|
3148
|
+
/*************************************************************************
|
3149
|
+
1-dimensional complex deconvolution, inverse of ConvR1DCircular().
|
3150
|
+
|
3151
|
+
Buffered version, which does not reallocate R[] if its length is enough to
|
3152
|
+
store the result (i.e. it reuses previously allocated memory as much as
|
3153
|
+
possible).
|
3154
|
+
|
3155
|
+
-- ALGLIB --
|
3156
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
3157
|
+
*************************************************************************/
|
3158
|
+
void convr1dcircularinvbuf(/* Real */ const ae_vector* a,
|
3159
|
+
ae_int_t m,
|
3160
|
+
/* Real */ const ae_vector* b,
|
3161
|
+
ae_int_t n,
|
3162
|
+
/* Real */ ae_vector* r,
|
3163
|
+
ae_state *_state)
|
3164
|
+
{
|
3165
|
+
ae_frame _frame_block;
|
3166
|
+
ae_int_t i;
|
3167
|
+
ae_int_t i1;
|
3168
|
+
ae_int_t i2;
|
3169
|
+
ae_int_t j2;
|
3170
|
+
ae_vector buf;
|
3171
|
+
ae_vector buf2;
|
3172
|
+
ae_vector buf3;
|
3173
|
+
ae_vector cbuf;
|
3174
|
+
ae_vector cbuf2;
|
3175
|
+
fasttransformplan plan;
|
3176
|
+
ae_complex c1;
|
3177
|
+
ae_complex c2;
|
3178
|
+
ae_complex c3;
|
3179
|
+
|
3180
|
+
ae_frame_make(_state, &_frame_block);
|
3181
|
+
memset(&buf, 0, sizeof(buf));
|
3182
|
+
memset(&buf2, 0, sizeof(buf2));
|
3183
|
+
memset(&buf3, 0, sizeof(buf3));
|
3184
|
+
memset(&cbuf, 0, sizeof(cbuf));
|
3185
|
+
memset(&cbuf2, 0, sizeof(cbuf2));
|
3186
|
+
memset(&plan, 0, sizeof(plan));
|
3187
|
+
ae_vector_init(&buf, 0, DT_REAL, _state, ae_true);
|
3188
|
+
ae_vector_init(&buf2, 0, DT_REAL, _state, ae_true);
|
3189
|
+
ae_vector_init(&buf3, 0, DT_REAL, _state, ae_true);
|
3190
|
+
ae_vector_init(&cbuf, 0, DT_COMPLEX, _state, ae_true);
|
3191
|
+
ae_vector_init(&cbuf2, 0, DT_COMPLEX, _state, ae_true);
|
3192
|
+
_fasttransformplan_init(&plan, _state, ae_true);
|
3193
|
+
|
3194
|
+
ae_assert(n>0&&m>0, "ConvR1DCircularInv: incorrect N or M!", _state);
|
3195
|
+
|
3196
|
+
/*
|
3197
|
+
* normalize task: make M>=N,
|
3198
|
+
* so A will be longer (at least - not shorter) that B.
|
3199
|
+
*/
|
3200
|
+
if( m<n )
|
3201
|
+
{
|
3202
|
+
ae_vector_set_length(&buf, m, _state);
|
3203
|
+
for(i=0; i<=m-1; i++)
|
3204
|
+
{
|
3205
|
+
buf.ptr.p_double[i] = (double)(0);
|
3206
|
+
}
|
3207
|
+
i1 = 0;
|
3208
|
+
while(i1<n)
|
3209
|
+
{
|
3210
|
+
i2 = ae_minint(i1+m-1, n-1, _state);
|
3211
|
+
j2 = i2-i1;
|
3212
|
+
ae_v_add(&buf.ptr.p_double[0], 1, &b->ptr.p_double[i1], 1, ae_v_len(0,j2));
|
3213
|
+
i1 = i1+m;
|
3214
|
+
}
|
3215
|
+
convr1dcircularinvbuf(a, m, &buf, m, r, _state);
|
3216
|
+
ae_frame_leave(_state);
|
3217
|
+
return;
|
3218
|
+
}
|
3219
|
+
|
3220
|
+
/*
|
3221
|
+
* Task is normalized
|
3222
|
+
*/
|
3223
|
+
if( m%2==0 )
|
3224
|
+
{
|
3225
|
+
|
3226
|
+
/*
|
3227
|
+
* size is even, use fast even-size FFT
|
3228
|
+
*/
|
3229
|
+
ae_vector_set_length(&buf, m, _state);
|
3230
|
+
ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1));
|
3231
|
+
ae_vector_set_length(&buf2, m, _state);
|
3232
|
+
ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1));
|
3233
|
+
for(i=n; i<=m-1; i++)
|
3234
|
+
{
|
3235
|
+
buf2.ptr.p_double[i] = (double)(0);
|
3236
|
+
}
|
3237
|
+
ae_vector_set_length(&buf3, m, _state);
|
3238
|
+
ftcomplexfftplan(m/2, 1, &plan, _state);
|
3239
|
+
fftr1dinternaleven(&buf, m, &buf3, &plan, _state);
|
3240
|
+
fftr1dinternaleven(&buf2, m, &buf3, &plan, _state);
|
3241
|
+
buf.ptr.p_double[0] = buf.ptr.p_double[0]/buf2.ptr.p_double[0];
|
3242
|
+
buf.ptr.p_double[1] = buf.ptr.p_double[1]/buf2.ptr.p_double[1];
|
3243
|
+
for(i=1; i<=m/2-1; i++)
|
3244
|
+
{
|
3245
|
+
c1.x = buf.ptr.p_double[2*i+0];
|
3246
|
+
c1.y = buf.ptr.p_double[2*i+1];
|
3247
|
+
c2.x = buf2.ptr.p_double[2*i+0];
|
3248
|
+
c2.y = buf2.ptr.p_double[2*i+1];
|
3249
|
+
c3 = ae_c_div(c1,c2);
|
3250
|
+
buf.ptr.p_double[2*i+0] = c3.x;
|
3251
|
+
buf.ptr.p_double[2*i+1] = c3.y;
|
3252
|
+
}
|
3253
|
+
fftr1dinvinternaleven(&buf, m, &buf3, &plan, _state);
|
3254
|
+
rallocv(m, r, _state);
|
3255
|
+
ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m-1));
|
3256
|
+
}
|
3257
|
+
else
|
3258
|
+
{
|
3259
|
+
|
3260
|
+
/*
|
3261
|
+
* odd-size, use general real FFT
|
3262
|
+
*/
|
3263
|
+
fftr1d(a, m, &cbuf, _state);
|
3264
|
+
ae_vector_set_length(&buf2, m, _state);
|
3265
|
+
ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1));
|
3266
|
+
for(i=n; i<=m-1; i++)
|
3267
|
+
{
|
3268
|
+
buf2.ptr.p_double[i] = (double)(0);
|
3269
|
+
}
|
3270
|
+
fftr1d(&buf2, m, &cbuf2, _state);
|
3271
|
+
for(i=0; i<=ae_ifloor((double)m/(double)2, _state); i++)
|
3272
|
+
{
|
3273
|
+
cbuf.ptr.p_complex[i] = ae_c_div(cbuf.ptr.p_complex[i],cbuf2.ptr.p_complex[i]);
|
3274
|
+
}
|
3275
|
+
fftr1dinvbuf(&cbuf, m, r, _state);
|
3276
|
+
}
|
3277
|
+
ae_frame_leave(_state);
|
3278
|
+
}
|
3279
|
+
|
3280
|
+
|
3281
|
+
/*************************************************************************
|
3282
|
+
1-dimensional complex convolution.
|
3283
|
+
|
3284
|
+
Extended subroutine which allows to choose convolution algorithm.
|
3285
|
+
Intended for internal use, ALGLIB users should call ConvC1D()/ConvC1DCircular().
|
3286
|
+
|
3287
|
+
INPUT PARAMETERS
|
3288
|
+
A - array[0..M-1] - complex function to be transformed
|
3289
|
+
M - problem size
|
3290
|
+
B - array[0..N-1] - complex function to be transformed
|
3291
|
+
N - problem size, N<=M
|
3292
|
+
Alg - algorithm type:
|
3293
|
+
*-2 auto-select Q for overlap-add
|
3294
|
+
*-1 auto-select algorithm and parameters
|
3295
|
+
* 0 straightforward formula for small N's
|
3296
|
+
* 1 general FFT-based code
|
3297
|
+
* 2 overlap-add with length Q
|
3298
|
+
Q - length for overlap-add
|
3299
|
+
|
3300
|
+
OUTPUT PARAMETERS
|
3301
|
+
R - convolution: A*B. array[0..N+M-1].
|
3302
|
+
|
3303
|
+
-- ALGLIB --
|
3304
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
3305
|
+
*************************************************************************/
|
3306
|
+
void convc1dx(/* Complex */ const ae_vector* a,
|
3307
|
+
ae_int_t m,
|
3308
|
+
/* Complex */ const ae_vector* b,
|
3309
|
+
ae_int_t n,
|
3310
|
+
ae_bool circular,
|
3311
|
+
ae_int_t alg,
|
3312
|
+
ae_int_t q,
|
3313
|
+
/* Complex */ ae_vector* r,
|
3314
|
+
ae_state *_state)
|
3315
|
+
{
|
3316
|
+
ae_frame _frame_block;
|
3317
|
+
ae_int_t i;
|
3318
|
+
ae_int_t j;
|
3319
|
+
ae_int_t p;
|
3320
|
+
ae_int_t ptotal;
|
3321
|
+
ae_int_t i1;
|
3322
|
+
ae_int_t i2;
|
3323
|
+
ae_int_t j1;
|
3324
|
+
ae_int_t j2;
|
3325
|
+
ae_vector bbuf;
|
3326
|
+
ae_complex v;
|
3327
|
+
double ax;
|
3328
|
+
double ay;
|
3329
|
+
double bx;
|
3330
|
+
double by;
|
3331
|
+
double t;
|
3332
|
+
double tx;
|
3333
|
+
double ty;
|
3334
|
+
double flopcand;
|
3335
|
+
double flopbest;
|
3336
|
+
ae_int_t algbest;
|
3337
|
+
fasttransformplan plan;
|
3338
|
+
ae_vector buf;
|
3339
|
+
ae_vector buf2;
|
3340
|
+
|
3341
|
+
ae_frame_make(_state, &_frame_block);
|
3342
|
+
memset(&bbuf, 0, sizeof(bbuf));
|
3343
|
+
memset(&plan, 0, sizeof(plan));
|
3344
|
+
memset(&buf, 0, sizeof(buf));
|
3345
|
+
memset(&buf2, 0, sizeof(buf2));
|
3346
|
+
ae_vector_init(&bbuf, 0, DT_COMPLEX, _state, ae_true);
|
3347
|
+
_fasttransformplan_init(&plan, _state, ae_true);
|
3348
|
+
ae_vector_init(&buf, 0, DT_REAL, _state, ae_true);
|
3349
|
+
ae_vector_init(&buf2, 0, DT_REAL, _state, ae_true);
|
3350
|
+
|
3351
|
+
ae_assert(n>0&&m>0, "ConvC1DX: incorrect N or M!", _state);
|
3352
|
+
ae_assert(n<=m, "ConvC1DX: N<M assumption is false!", _state);
|
3353
|
+
|
3354
|
+
/*
|
3355
|
+
* Auto-select
|
3356
|
+
*/
|
3357
|
+
if( alg==-1||alg==-2 )
|
3358
|
+
{
|
3359
|
+
|
3360
|
+
/*
|
3361
|
+
* Initial candidate: straightforward implementation.
|
3362
|
+
*
|
3363
|
+
* If we want to use auto-fitted overlap-add,
|
3364
|
+
* flop count is initialized by large real number - to force
|
3365
|
+
* another algorithm selection
|
3366
|
+
*/
|
3367
|
+
algbest = 0;
|
3368
|
+
if( alg==-1 )
|
3369
|
+
{
|
3370
|
+
flopbest = (double)(2*m*n);
|
3371
|
+
}
|
3372
|
+
else
|
3373
|
+
{
|
3374
|
+
flopbest = ae_maxrealnumber;
|
3375
|
+
}
|
3376
|
+
|
3377
|
+
/*
|
3378
|
+
* Another candidate - generic FFT code
|
3379
|
+
*/
|
3380
|
+
if( alg==-1 )
|
3381
|
+
{
|
3382
|
+
if( circular&&ftbaseissmooth(m, _state) )
|
3383
|
+
{
|
3384
|
+
|
3385
|
+
/*
|
3386
|
+
* special code for circular convolution of a sequence with a smooth length
|
3387
|
+
*/
|
3388
|
+
flopcand = (double)3*ftbasegetflopestimate(m, _state)+(double)(6*m);
|
3389
|
+
if( ae_fp_less(flopcand,flopbest) )
|
3390
|
+
{
|
3391
|
+
algbest = 1;
|
3392
|
+
flopbest = flopcand;
|
3393
|
+
}
|
3394
|
+
}
|
3395
|
+
else
|
3396
|
+
{
|
3397
|
+
|
3398
|
+
/*
|
3399
|
+
* general cyclic/non-cyclic convolution
|
3400
|
+
*/
|
3401
|
+
p = ftbasefindsmooth(m+n-1, _state);
|
3402
|
+
flopcand = (double)3*ftbasegetflopestimate(p, _state)+(double)(6*p);
|
3403
|
+
if( ae_fp_less(flopcand,flopbest) )
|
3404
|
+
{
|
3405
|
+
algbest = 1;
|
3406
|
+
flopbest = flopcand;
|
3407
|
+
}
|
3408
|
+
}
|
3409
|
+
}
|
3410
|
+
|
3411
|
+
/*
|
3412
|
+
* Another candidate - overlap-add
|
3413
|
+
*/
|
3414
|
+
q = 1;
|
3415
|
+
ptotal = 1;
|
3416
|
+
while(ptotal<n)
|
3417
|
+
{
|
3418
|
+
ptotal = ptotal*2;
|
3419
|
+
}
|
3420
|
+
while(ptotal<=m+n-1)
|
3421
|
+
{
|
3422
|
+
p = ptotal-n+1;
|
3423
|
+
flopcand = (double)ae_iceil((double)m/(double)p, _state)*((double)2*ftbasegetflopestimate(ptotal, _state)+(double)(8*ptotal));
|
3424
|
+
if( ae_fp_less(flopcand,flopbest) )
|
3425
|
+
{
|
3426
|
+
flopbest = flopcand;
|
3427
|
+
algbest = 2;
|
3428
|
+
q = p;
|
3429
|
+
}
|
3430
|
+
ptotal = ptotal*2;
|
3431
|
+
}
|
3432
|
+
alg = algbest;
|
3433
|
+
convc1dx(a, m, b, n, circular, alg, q, r, _state);
|
3434
|
+
ae_frame_leave(_state);
|
3435
|
+
return;
|
3436
|
+
}
|
3437
|
+
|
3438
|
+
/*
|
3439
|
+
* straightforward formula for
|
3440
|
+
* circular and non-circular convolutions.
|
3441
|
+
*
|
3442
|
+
* Very simple code, no further comments needed.
|
3443
|
+
*/
|
3444
|
+
if( alg==0 )
|
3445
|
+
{
|
3446
|
+
|
3447
|
+
/*
|
3448
|
+
* Special case: N=1
|
3449
|
+
*/
|
3450
|
+
if( n==1 )
|
3451
|
+
{
|
3452
|
+
callocv(m, r, _state);
|
3453
|
+
v = b->ptr.p_complex[0];
|
3454
|
+
ae_v_cmovec(&r->ptr.p_complex[0], 1, &a->ptr.p_complex[0], 1, "N", ae_v_len(0,m-1), v);
|
3455
|
+
ae_frame_leave(_state);
|
3456
|
+
return;
|
3457
|
+
}
|
3458
|
+
|
3459
|
+
/*
|
3460
|
+
* use straightforward formula
|
3461
|
+
*/
|
3462
|
+
if( circular )
|
3463
|
+
{
|
3464
|
+
|
3465
|
+
/*
|
3466
|
+
* circular convolution
|
3467
|
+
*/
|
3468
|
+
callocv(m, r, _state);
|
3469
|
+
v = b->ptr.p_complex[0];
|
3470
|
+
ae_v_cmovec(&r->ptr.p_complex[0], 1, &a->ptr.p_complex[0], 1, "N", ae_v_len(0,m-1), v);
|
3471
|
+
for(i=1; i<=n-1; i++)
|
3472
|
+
{
|
3473
|
+
v = b->ptr.p_complex[i];
|
3474
|
+
i1 = 0;
|
3475
|
+
i2 = i-1;
|
3476
|
+
j1 = m-i;
|
3477
|
+
j2 = m-1;
|
3478
|
+
ae_v_caddc(&r->ptr.p_complex[i1], 1, &a->ptr.p_complex[j1], 1, "N", ae_v_len(i1,i2), v);
|
3479
|
+
i1 = i;
|
3480
|
+
i2 = m-1;
|
3481
|
+
j1 = 0;
|
3482
|
+
j2 = m-i-1;
|
3483
|
+
ae_v_caddc(&r->ptr.p_complex[i1], 1, &a->ptr.p_complex[j1], 1, "N", ae_v_len(i1,i2), v);
|
3484
|
+
}
|
3485
|
+
}
|
3486
|
+
else
|
3487
|
+
{
|
3488
|
+
|
3489
|
+
/*
|
3490
|
+
* non-circular convolution
|
3491
|
+
*/
|
3492
|
+
callocv(m+n-1, r, _state);
|
3493
|
+
for(i=0; i<=m+n-2; i++)
|
3494
|
+
{
|
3495
|
+
r->ptr.p_complex[i] = ae_complex_from_i(0);
|
3496
|
+
}
|
3497
|
+
for(i=0; i<=n-1; i++)
|
3498
|
+
{
|
3499
|
+
v = b->ptr.p_complex[i];
|
3500
|
+
ae_v_caddc(&r->ptr.p_complex[i], 1, &a->ptr.p_complex[0], 1, "N", ae_v_len(i,i+m-1), v);
|
3501
|
+
}
|
3502
|
+
}
|
3503
|
+
ae_frame_leave(_state);
|
3504
|
+
return;
|
3505
|
+
}
|
3506
|
+
|
3507
|
+
/*
|
3508
|
+
* general FFT-based code for
|
3509
|
+
* circular and non-circular convolutions.
|
3510
|
+
*
|
3511
|
+
* First, if convolution is circular, we test whether M is smooth or not.
|
3512
|
+
* If it is smooth, we just use M-length FFT to calculate convolution.
|
3513
|
+
* If it is not, we calculate non-circular convolution and wrap it arount.
|
3514
|
+
*
|
3515
|
+
* IF convolution is non-circular, we use zero-padding + FFT.
|
3516
|
+
*/
|
3517
|
+
if( alg==1 )
|
3518
|
+
{
|
3519
|
+
if( circular&&ftbaseissmooth(m, _state) )
|
3520
|
+
{
|
3521
|
+
|
3522
|
+
/*
|
3523
|
+
* special code for circular convolution with smooth M
|
3524
|
+
*/
|
3525
|
+
ftcomplexfftplan(m, 1, &plan, _state);
|
3526
|
+
ae_vector_set_length(&buf, 2*m, _state);
|
3527
|
+
for(i=0; i<=m-1; i++)
|
3528
|
+
{
|
3529
|
+
buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x;
|
3530
|
+
buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y;
|
3531
|
+
}
|
3532
|
+
ae_vector_set_length(&buf2, 2*m, _state);
|
3533
|
+
for(i=0; i<=n-1; i++)
|
3534
|
+
{
|
3535
|
+
buf2.ptr.p_double[2*i+0] = b->ptr.p_complex[i].x;
|
3536
|
+
buf2.ptr.p_double[2*i+1] = b->ptr.p_complex[i].y;
|
3537
|
+
}
|
3538
|
+
for(i=n; i<=m-1; i++)
|
3539
|
+
{
|
3540
|
+
buf2.ptr.p_double[2*i+0] = (double)(0);
|
3541
|
+
buf2.ptr.p_double[2*i+1] = (double)(0);
|
3542
|
+
}
|
3543
|
+
ftapplyplan(&plan, &buf, 0, 1, _state);
|
3544
|
+
ftapplyplan(&plan, &buf2, 0, 1, _state);
|
3545
|
+
for(i=0; i<=m-1; i++)
|
3546
|
+
{
|
3547
|
+
ax = buf.ptr.p_double[2*i+0];
|
3548
|
+
ay = buf.ptr.p_double[2*i+1];
|
3549
|
+
bx = buf2.ptr.p_double[2*i+0];
|
3550
|
+
by = buf2.ptr.p_double[2*i+1];
|
3551
|
+
tx = ax*bx-ay*by;
|
3552
|
+
ty = ax*by+ay*bx;
|
3553
|
+
buf.ptr.p_double[2*i+0] = tx;
|
3554
|
+
buf.ptr.p_double[2*i+1] = -ty;
|
3555
|
+
}
|
3556
|
+
ftapplyplan(&plan, &buf, 0, 1, _state);
|
3557
|
+
t = (double)1/(double)m;
|
3558
|
+
callocv(m, r, _state);
|
3559
|
+
for(i=0; i<=m-1; i++)
|
3560
|
+
{
|
3561
|
+
r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0];
|
3562
|
+
r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1];
|
3563
|
+
}
|
3564
|
+
}
|
3565
|
+
else
|
3566
|
+
{
|
3567
|
+
|
3568
|
+
/*
|
3569
|
+
* M is non-smooth, general code (circular/non-circular):
|
3570
|
+
* * first part is the same for circular and non-circular
|
3571
|
+
* convolutions. zero padding, FFTs, inverse FFTs
|
3572
|
+
* * second part differs:
|
3573
|
+
* * for non-circular convolution we just copy array
|
3574
|
+
* * for circular convolution we add array tail to its head
|
3575
|
+
*/
|
3576
|
+
p = ftbasefindsmooth(m+n-1, _state);
|
3577
|
+
ftcomplexfftplan(p, 1, &plan, _state);
|
3578
|
+
ae_vector_set_length(&buf, 2*p, _state);
|
3579
|
+
for(i=0; i<=m-1; i++)
|
3580
|
+
{
|
3581
|
+
buf.ptr.p_double[2*i+0] = a->ptr.p_complex[i].x;
|
3582
|
+
buf.ptr.p_double[2*i+1] = a->ptr.p_complex[i].y;
|
3583
|
+
}
|
3584
|
+
for(i=m; i<=p-1; i++)
|
3585
|
+
{
|
3586
|
+
buf.ptr.p_double[2*i+0] = (double)(0);
|
3587
|
+
buf.ptr.p_double[2*i+1] = (double)(0);
|
3588
|
+
}
|
3589
|
+
ae_vector_set_length(&buf2, 2*p, _state);
|
3590
|
+
for(i=0; i<=n-1; i++)
|
3591
|
+
{
|
3592
|
+
buf2.ptr.p_double[2*i+0] = b->ptr.p_complex[i].x;
|
3593
|
+
buf2.ptr.p_double[2*i+1] = b->ptr.p_complex[i].y;
|
3594
|
+
}
|
3595
|
+
for(i=n; i<=p-1; i++)
|
3596
|
+
{
|
3597
|
+
buf2.ptr.p_double[2*i+0] = (double)(0);
|
3598
|
+
buf2.ptr.p_double[2*i+1] = (double)(0);
|
3599
|
+
}
|
3600
|
+
ftapplyplan(&plan, &buf, 0, 1, _state);
|
3601
|
+
ftapplyplan(&plan, &buf2, 0, 1, _state);
|
3602
|
+
for(i=0; i<=p-1; i++)
|
3603
|
+
{
|
3604
|
+
ax = buf.ptr.p_double[2*i+0];
|
3605
|
+
ay = buf.ptr.p_double[2*i+1];
|
3606
|
+
bx = buf2.ptr.p_double[2*i+0];
|
3607
|
+
by = buf2.ptr.p_double[2*i+1];
|
3608
|
+
tx = ax*bx-ay*by;
|
3609
|
+
ty = ax*by+ay*bx;
|
3610
|
+
buf.ptr.p_double[2*i+0] = tx;
|
3611
|
+
buf.ptr.p_double[2*i+1] = -ty;
|
3612
|
+
}
|
3613
|
+
ftapplyplan(&plan, &buf, 0, 1, _state);
|
3614
|
+
t = (double)1/(double)p;
|
3615
|
+
if( circular )
|
3616
|
+
{
|
3617
|
+
|
3618
|
+
/*
|
3619
|
+
* circular, add tail to head
|
3620
|
+
*/
|
3621
|
+
callocv(m, r, _state);
|
3622
|
+
for(i=0; i<=m-1; i++)
|
3623
|
+
{
|
3624
|
+
r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0];
|
3625
|
+
r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1];
|
3626
|
+
}
|
3627
|
+
for(i=m; i<=m+n-2; i++)
|
3628
|
+
{
|
3629
|
+
r->ptr.p_complex[i-m].x = r->ptr.p_complex[i-m].x+t*buf.ptr.p_double[2*i+0];
|
3630
|
+
r->ptr.p_complex[i-m].y = r->ptr.p_complex[i-m].y-t*buf.ptr.p_double[2*i+1];
|
3631
|
+
}
|
3632
|
+
}
|
3633
|
+
else
|
3634
|
+
{
|
3635
|
+
|
3636
|
+
/*
|
3637
|
+
* non-circular, just copy
|
3638
|
+
*/
|
3639
|
+
callocv(m+n-1, r, _state);
|
3640
|
+
for(i=0; i<=m+n-2; i++)
|
3641
|
+
{
|
3642
|
+
r->ptr.p_complex[i].x = t*buf.ptr.p_double[2*i+0];
|
3643
|
+
r->ptr.p_complex[i].y = -t*buf.ptr.p_double[2*i+1];
|
3644
|
+
}
|
3645
|
+
}
|
3646
|
+
}
|
3647
|
+
ae_frame_leave(_state);
|
3648
|
+
return;
|
3649
|
+
}
|
3650
|
+
|
3651
|
+
/*
|
3652
|
+
* overlap-add method for
|
3653
|
+
* circular and non-circular convolutions.
|
3654
|
+
*
|
3655
|
+
* First part of code (separate FFTs of input blocks) is the same
|
3656
|
+
* for all types of convolution. Second part (overlapping outputs)
|
3657
|
+
* differs for different types of convolution. We just copy output
|
3658
|
+
* when convolution is non-circular. We wrap it around, if it is
|
3659
|
+
* circular.
|
3660
|
+
*/
|
3661
|
+
if( alg==2 )
|
3662
|
+
{
|
3663
|
+
ae_vector_set_length(&buf, 2*(q+n-1), _state);
|
3664
|
+
|
3665
|
+
/*
|
3666
|
+
* prepare R
|
3667
|
+
*/
|
3668
|
+
if( circular )
|
3669
|
+
{
|
3670
|
+
callocv(m, r, _state);
|
3671
|
+
for(i=0; i<=m-1; i++)
|
3672
|
+
{
|
3673
|
+
r->ptr.p_complex[i] = ae_complex_from_i(0);
|
3674
|
+
}
|
3675
|
+
}
|
3676
|
+
else
|
3677
|
+
{
|
3678
|
+
callocv(m+n-1, r, _state);
|
3679
|
+
for(i=0; i<=m+n-2; i++)
|
3680
|
+
{
|
3681
|
+
r->ptr.p_complex[i] = ae_complex_from_i(0);
|
3682
|
+
}
|
3683
|
+
}
|
3684
|
+
|
3685
|
+
/*
|
3686
|
+
* pre-calculated FFT(B)
|
3687
|
+
*/
|
3688
|
+
ae_vector_set_length(&bbuf, q+n-1, _state);
|
3689
|
+
ae_v_cmove(&bbuf.ptr.p_complex[0], 1, &b->ptr.p_complex[0], 1, "N", ae_v_len(0,n-1));
|
3690
|
+
for(j=n; j<=q+n-2; j++)
|
3691
|
+
{
|
3692
|
+
bbuf.ptr.p_complex[j] = ae_complex_from_i(0);
|
3693
|
+
}
|
3694
|
+
fftc1d(&bbuf, q+n-1, _state);
|
3695
|
+
|
3696
|
+
/*
|
3697
|
+
* prepare FFT plan for chunks of A
|
3698
|
+
*/
|
3699
|
+
ftcomplexfftplan(q+n-1, 1, &plan, _state);
|
3700
|
+
|
3701
|
+
/*
|
3702
|
+
* main overlap-add cycle
|
3703
|
+
*/
|
3704
|
+
i = 0;
|
3705
|
+
while(i<=m-1)
|
3706
|
+
{
|
3707
|
+
p = ae_minint(q, m-i, _state);
|
3708
|
+
for(j=0; j<=p-1; j++)
|
3709
|
+
{
|
3710
|
+
buf.ptr.p_double[2*j+0] = a->ptr.p_complex[i+j].x;
|
3711
|
+
buf.ptr.p_double[2*j+1] = a->ptr.p_complex[i+j].y;
|
3712
|
+
}
|
3713
|
+
for(j=p; j<=q+n-2; j++)
|
3714
|
+
{
|
3715
|
+
buf.ptr.p_double[2*j+0] = (double)(0);
|
3716
|
+
buf.ptr.p_double[2*j+1] = (double)(0);
|
3717
|
+
}
|
3718
|
+
ftapplyplan(&plan, &buf, 0, 1, _state);
|
3719
|
+
for(j=0; j<=q+n-2; j++)
|
3720
|
+
{
|
3721
|
+
ax = buf.ptr.p_double[2*j+0];
|
3722
|
+
ay = buf.ptr.p_double[2*j+1];
|
3723
|
+
bx = bbuf.ptr.p_complex[j].x;
|
3724
|
+
by = bbuf.ptr.p_complex[j].y;
|
3725
|
+
tx = ax*bx-ay*by;
|
3726
|
+
ty = ax*by+ay*bx;
|
3727
|
+
buf.ptr.p_double[2*j+0] = tx;
|
3728
|
+
buf.ptr.p_double[2*j+1] = -ty;
|
3729
|
+
}
|
3730
|
+
ftapplyplan(&plan, &buf, 0, 1, _state);
|
3731
|
+
t = (double)1/(double)(q+n-1);
|
3732
|
+
if( circular )
|
3733
|
+
{
|
3734
|
+
j1 = ae_minint(i+p+n-2, m-1, _state)-i;
|
3735
|
+
j2 = j1+1;
|
3736
|
+
}
|
3737
|
+
else
|
3738
|
+
{
|
3739
|
+
j1 = p+n-2;
|
3740
|
+
j2 = j1+1;
|
3741
|
+
}
|
3742
|
+
for(j=0; j<=j1; j++)
|
3743
|
+
{
|
3744
|
+
r->ptr.p_complex[i+j].x = r->ptr.p_complex[i+j].x+buf.ptr.p_double[2*j+0]*t;
|
3745
|
+
r->ptr.p_complex[i+j].y = r->ptr.p_complex[i+j].y-buf.ptr.p_double[2*j+1]*t;
|
3746
|
+
}
|
3747
|
+
for(j=j2; j<=p+n-2; j++)
|
3748
|
+
{
|
3749
|
+
r->ptr.p_complex[j-j2].x = r->ptr.p_complex[j-j2].x+buf.ptr.p_double[2*j+0]*t;
|
3750
|
+
r->ptr.p_complex[j-j2].y = r->ptr.p_complex[j-j2].y-buf.ptr.p_double[2*j+1]*t;
|
3751
|
+
}
|
3752
|
+
i = i+p;
|
3753
|
+
}
|
3754
|
+
ae_frame_leave(_state);
|
3755
|
+
return;
|
3756
|
+
}
|
3757
|
+
ae_frame_leave(_state);
|
3758
|
+
}
|
3759
|
+
|
3760
|
+
|
3761
|
+
/*************************************************************************
|
3762
|
+
1-dimensional real convolution.
|
3763
|
+
|
3764
|
+
Extended subroutine which allows to choose convolution algorithm.
|
3765
|
+
Intended for internal use, ALGLIB users should call ConvR1D().
|
3766
|
+
|
3767
|
+
INPUT PARAMETERS
|
3768
|
+
A - array[0..M-1] - complex function to be transformed
|
3769
|
+
M - problem size
|
3770
|
+
B - array[0..N-1] - complex function to be transformed
|
3771
|
+
N - problem size, N<=M
|
3772
|
+
Alg - algorithm type:
|
3773
|
+
*-2 auto-select Q for overlap-add
|
3774
|
+
*-1 auto-select algorithm and parameters
|
3775
|
+
* 0 straightforward formula for small N's
|
3776
|
+
* 1 general FFT-based code
|
3777
|
+
* 2 overlap-add with length Q
|
3778
|
+
Q - length for overlap-add
|
3779
|
+
|
3780
|
+
OUTPUT PARAMETERS
|
3781
|
+
R - convolution: A*B. array[0..N+M-1].
|
3782
|
+
|
3783
|
+
-- ALGLIB --
|
3784
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
3785
|
+
*************************************************************************/
|
3786
|
+
void convr1dx(/* Real */ const ae_vector* a,
|
3787
|
+
ae_int_t m,
|
3788
|
+
/* Real */ const ae_vector* b,
|
3789
|
+
ae_int_t n,
|
3790
|
+
ae_bool circular,
|
3791
|
+
ae_int_t alg,
|
3792
|
+
ae_int_t q,
|
3793
|
+
/* Real */ ae_vector* r,
|
3794
|
+
ae_state *_state)
|
3795
|
+
{
|
3796
|
+
ae_frame _frame_block;
|
3797
|
+
double v;
|
3798
|
+
ae_int_t i;
|
3799
|
+
ae_int_t j;
|
3800
|
+
ae_int_t p;
|
3801
|
+
ae_int_t ptotal;
|
3802
|
+
ae_int_t i1;
|
3803
|
+
ae_int_t i2;
|
3804
|
+
ae_int_t j1;
|
3805
|
+
ae_int_t j2;
|
3806
|
+
double ax;
|
3807
|
+
double ay;
|
3808
|
+
double bx;
|
3809
|
+
double by;
|
3810
|
+
double tx;
|
3811
|
+
double ty;
|
3812
|
+
double flopcand;
|
3813
|
+
double flopbest;
|
3814
|
+
ae_int_t algbest;
|
3815
|
+
fasttransformplan plan;
|
3816
|
+
ae_vector buf;
|
3817
|
+
ae_vector buf2;
|
3818
|
+
ae_vector buf3;
|
3819
|
+
|
3820
|
+
ae_frame_make(_state, &_frame_block);
|
3821
|
+
memset(&plan, 0, sizeof(plan));
|
3822
|
+
memset(&buf, 0, sizeof(buf));
|
3823
|
+
memset(&buf2, 0, sizeof(buf2));
|
3824
|
+
memset(&buf3, 0, sizeof(buf3));
|
3825
|
+
_fasttransformplan_init(&plan, _state, ae_true);
|
3826
|
+
ae_vector_init(&buf, 0, DT_REAL, _state, ae_true);
|
3827
|
+
ae_vector_init(&buf2, 0, DT_REAL, _state, ae_true);
|
3828
|
+
ae_vector_init(&buf3, 0, DT_REAL, _state, ae_true);
|
3829
|
+
|
3830
|
+
ae_assert(n>0&&m>0, "ConvR1DX: incorrect N or M!", _state);
|
3831
|
+
ae_assert(n<=m, "ConvR1DX: N<M assumption is false!", _state);
|
3832
|
+
|
3833
|
+
/*
|
3834
|
+
* handle special cases
|
3835
|
+
*/
|
3836
|
+
if( ae_minint(m, n, _state)<=2 )
|
3837
|
+
{
|
3838
|
+
alg = 0;
|
3839
|
+
}
|
3840
|
+
|
3841
|
+
/*
|
3842
|
+
* Auto-select
|
3843
|
+
*/
|
3844
|
+
if( alg<0 )
|
3845
|
+
{
|
3846
|
+
|
3847
|
+
/*
|
3848
|
+
* Initial candidate: straightforward implementation.
|
3849
|
+
*
|
3850
|
+
* If we want to use auto-fitted overlap-add,
|
3851
|
+
* flop count is initialized by large real number - to force
|
3852
|
+
* another algorithm selection
|
3853
|
+
*/
|
3854
|
+
algbest = 0;
|
3855
|
+
if( alg==-1 )
|
3856
|
+
{
|
3857
|
+
flopbest = 0.15*(double)m*(double)n;
|
3858
|
+
}
|
3859
|
+
else
|
3860
|
+
{
|
3861
|
+
flopbest = ae_maxrealnumber;
|
3862
|
+
}
|
3863
|
+
|
3864
|
+
/*
|
3865
|
+
* Another candidate - generic FFT code
|
3866
|
+
*/
|
3867
|
+
if( alg==-1 )
|
3868
|
+
{
|
3869
|
+
if( (circular&&ftbaseissmooth(m, _state))&&m%2==0 )
|
3870
|
+
{
|
3871
|
+
|
3872
|
+
/*
|
3873
|
+
* special code for circular convolution of a sequence with a smooth length
|
3874
|
+
*/
|
3875
|
+
flopcand = (double)3*ftbasegetflopestimate(m/2, _state)+(double)(6*m)/(double)2;
|
3876
|
+
if( ae_fp_less(flopcand,flopbest) )
|
3877
|
+
{
|
3878
|
+
algbest = 1;
|
3879
|
+
flopbest = flopcand;
|
3880
|
+
}
|
3881
|
+
}
|
3882
|
+
else
|
3883
|
+
{
|
3884
|
+
|
3885
|
+
/*
|
3886
|
+
* general cyclic/non-cyclic convolution
|
3887
|
+
*/
|
3888
|
+
p = ftbasefindsmootheven(m+n-1, _state);
|
3889
|
+
flopcand = (double)3*ftbasegetflopestimate(p/2, _state)+(double)(6*p)/(double)2;
|
3890
|
+
if( ae_fp_less(flopcand,flopbest) )
|
3891
|
+
{
|
3892
|
+
algbest = 1;
|
3893
|
+
flopbest = flopcand;
|
3894
|
+
}
|
3895
|
+
}
|
3896
|
+
}
|
3897
|
+
|
3898
|
+
/*
|
3899
|
+
* Another candidate - overlap-add
|
3900
|
+
*/
|
3901
|
+
q = 1;
|
3902
|
+
ptotal = 1;
|
3903
|
+
while(ptotal<n)
|
3904
|
+
{
|
3905
|
+
ptotal = ptotal*2;
|
3906
|
+
}
|
3907
|
+
while(ptotal<=m+n-1)
|
3908
|
+
{
|
3909
|
+
p = ptotal-n+1;
|
3910
|
+
flopcand = (double)ae_iceil((double)m/(double)p, _state)*((double)2*ftbasegetflopestimate(ptotal/2, _state)+(double)(1*(ptotal/2)));
|
3911
|
+
if( ae_fp_less(flopcand,flopbest) )
|
3912
|
+
{
|
3913
|
+
flopbest = flopcand;
|
3914
|
+
algbest = 2;
|
3915
|
+
q = p;
|
3916
|
+
}
|
3917
|
+
ptotal = ptotal*2;
|
3918
|
+
}
|
3919
|
+
alg = algbest;
|
3920
|
+
convr1dx(a, m, b, n, circular, alg, q, r, _state);
|
3921
|
+
ae_frame_leave(_state);
|
3922
|
+
return;
|
3923
|
+
}
|
3924
|
+
|
3925
|
+
/*
|
3926
|
+
* straightforward formula for
|
3927
|
+
* circular and non-circular convolutions.
|
3928
|
+
*
|
3929
|
+
* Very simple code, no further comments needed.
|
3930
|
+
*/
|
3931
|
+
if( alg==0 )
|
3932
|
+
{
|
3933
|
+
|
3934
|
+
/*
|
3935
|
+
* Special case: N=1
|
3936
|
+
*/
|
3937
|
+
if( n==1 )
|
3938
|
+
{
|
3939
|
+
rallocv(m, r, _state);
|
3940
|
+
v = b->ptr.p_double[0];
|
3941
|
+
ae_v_moved(&r->ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1), v);
|
3942
|
+
ae_frame_leave(_state);
|
3943
|
+
return;
|
3944
|
+
}
|
3945
|
+
|
3946
|
+
/*
|
3947
|
+
* use straightforward formula
|
3948
|
+
*/
|
3949
|
+
if( circular )
|
3950
|
+
{
|
3951
|
+
|
3952
|
+
/*
|
3953
|
+
* circular convolution
|
3954
|
+
*/
|
3955
|
+
rallocv(m, r, _state);
|
3956
|
+
v = b->ptr.p_double[0];
|
3957
|
+
ae_v_moved(&r->ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1), v);
|
3958
|
+
for(i=1; i<=n-1; i++)
|
3959
|
+
{
|
3960
|
+
v = b->ptr.p_double[i];
|
3961
|
+
i1 = 0;
|
3962
|
+
i2 = i-1;
|
3963
|
+
j1 = m-i;
|
3964
|
+
j2 = m-1;
|
3965
|
+
ae_v_addd(&r->ptr.p_double[i1], 1, &a->ptr.p_double[j1], 1, ae_v_len(i1,i2), v);
|
3966
|
+
i1 = i;
|
3967
|
+
i2 = m-1;
|
3968
|
+
j1 = 0;
|
3969
|
+
j2 = m-i-1;
|
3970
|
+
ae_v_addd(&r->ptr.p_double[i1], 1, &a->ptr.p_double[j1], 1, ae_v_len(i1,i2), v);
|
3971
|
+
}
|
3972
|
+
}
|
3973
|
+
else
|
3974
|
+
{
|
3975
|
+
|
3976
|
+
/*
|
3977
|
+
* non-circular convolution
|
3978
|
+
*/
|
3979
|
+
rallocv(m+n-1, r, _state);
|
3980
|
+
for(i=0; i<=m+n-2; i++)
|
3981
|
+
{
|
3982
|
+
r->ptr.p_double[i] = (double)(0);
|
3983
|
+
}
|
3984
|
+
for(i=0; i<=n-1; i++)
|
3985
|
+
{
|
3986
|
+
v = b->ptr.p_double[i];
|
3987
|
+
ae_v_addd(&r->ptr.p_double[i], 1, &a->ptr.p_double[0], 1, ae_v_len(i,i+m-1), v);
|
3988
|
+
}
|
3989
|
+
}
|
3990
|
+
ae_frame_leave(_state);
|
3991
|
+
return;
|
3992
|
+
}
|
3993
|
+
|
3994
|
+
/*
|
3995
|
+
* general FFT-based code for
|
3996
|
+
* circular and non-circular convolutions.
|
3997
|
+
*
|
3998
|
+
* First, if convolution is circular, we test whether M is smooth or not.
|
3999
|
+
* If it is smooth, we just use M-length FFT to calculate convolution.
|
4000
|
+
* If it is not, we calculate non-circular convolution and wrap it arount.
|
4001
|
+
*
|
4002
|
+
* If convolution is non-circular, we use zero-padding + FFT.
|
4003
|
+
*
|
4004
|
+
* We assume that M+N-1>2 - we should call small case code otherwise
|
4005
|
+
*/
|
4006
|
+
if( alg==1 )
|
4007
|
+
{
|
4008
|
+
ae_assert(m+n-1>2, "ConvR1DX: internal error!", _state);
|
4009
|
+
if( (circular&&ftbaseissmooth(m, _state))&&m%2==0 )
|
4010
|
+
{
|
4011
|
+
|
4012
|
+
/*
|
4013
|
+
* special code for circular convolution with smooth even M
|
4014
|
+
*/
|
4015
|
+
ae_vector_set_length(&buf, m, _state);
|
4016
|
+
ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1));
|
4017
|
+
ae_vector_set_length(&buf2, m, _state);
|
4018
|
+
ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1));
|
4019
|
+
for(i=n; i<=m-1; i++)
|
4020
|
+
{
|
4021
|
+
buf2.ptr.p_double[i] = (double)(0);
|
4022
|
+
}
|
4023
|
+
ae_vector_set_length(&buf3, m, _state);
|
4024
|
+
ftcomplexfftplan(m/2, 1, &plan, _state);
|
4025
|
+
fftr1dinternaleven(&buf, m, &buf3, &plan, _state);
|
4026
|
+
fftr1dinternaleven(&buf2, m, &buf3, &plan, _state);
|
4027
|
+
buf.ptr.p_double[0] = buf.ptr.p_double[0]*buf2.ptr.p_double[0];
|
4028
|
+
buf.ptr.p_double[1] = buf.ptr.p_double[1]*buf2.ptr.p_double[1];
|
4029
|
+
for(i=1; i<=m/2-1; i++)
|
4030
|
+
{
|
4031
|
+
ax = buf.ptr.p_double[2*i+0];
|
4032
|
+
ay = buf.ptr.p_double[2*i+1];
|
4033
|
+
bx = buf2.ptr.p_double[2*i+0];
|
4034
|
+
by = buf2.ptr.p_double[2*i+1];
|
4035
|
+
tx = ax*bx-ay*by;
|
4036
|
+
ty = ax*by+ay*bx;
|
4037
|
+
buf.ptr.p_double[2*i+0] = tx;
|
4038
|
+
buf.ptr.p_double[2*i+1] = ty;
|
4039
|
+
}
|
4040
|
+
fftr1dinvinternaleven(&buf, m, &buf3, &plan, _state);
|
4041
|
+
rallocv(m, r, _state);
|
4042
|
+
ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m-1));
|
4043
|
+
}
|
4044
|
+
else
|
4045
|
+
{
|
4046
|
+
|
4047
|
+
/*
|
4048
|
+
* M is non-smooth or non-even, general code (circular/non-circular):
|
4049
|
+
* * first part is the same for circular and non-circular
|
4050
|
+
* convolutions. zero padding, FFTs, inverse FFTs
|
4051
|
+
* * second part differs:
|
4052
|
+
* * for non-circular convolution we just copy array
|
4053
|
+
* * for circular convolution we add array tail to its head
|
4054
|
+
*/
|
4055
|
+
p = ftbasefindsmootheven(m+n-1, _state);
|
4056
|
+
ae_vector_set_length(&buf, p, _state);
|
4057
|
+
ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[0], 1, ae_v_len(0,m-1));
|
4058
|
+
for(i=m; i<=p-1; i++)
|
4059
|
+
{
|
4060
|
+
buf.ptr.p_double[i] = (double)(0);
|
4061
|
+
}
|
4062
|
+
ae_vector_set_length(&buf2, p, _state);
|
4063
|
+
ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1));
|
4064
|
+
for(i=n; i<=p-1; i++)
|
4065
|
+
{
|
4066
|
+
buf2.ptr.p_double[i] = (double)(0);
|
4067
|
+
}
|
4068
|
+
ae_vector_set_length(&buf3, p, _state);
|
4069
|
+
ftcomplexfftplan(p/2, 1, &plan, _state);
|
4070
|
+
fftr1dinternaleven(&buf, p, &buf3, &plan, _state);
|
4071
|
+
fftr1dinternaleven(&buf2, p, &buf3, &plan, _state);
|
4072
|
+
buf.ptr.p_double[0] = buf.ptr.p_double[0]*buf2.ptr.p_double[0];
|
4073
|
+
buf.ptr.p_double[1] = buf.ptr.p_double[1]*buf2.ptr.p_double[1];
|
4074
|
+
for(i=1; i<=p/2-1; i++)
|
4075
|
+
{
|
4076
|
+
ax = buf.ptr.p_double[2*i+0];
|
4077
|
+
ay = buf.ptr.p_double[2*i+1];
|
4078
|
+
bx = buf2.ptr.p_double[2*i+0];
|
4079
|
+
by = buf2.ptr.p_double[2*i+1];
|
4080
|
+
tx = ax*bx-ay*by;
|
4081
|
+
ty = ax*by+ay*bx;
|
4082
|
+
buf.ptr.p_double[2*i+0] = tx;
|
4083
|
+
buf.ptr.p_double[2*i+1] = ty;
|
4084
|
+
}
|
4085
|
+
fftr1dinvinternaleven(&buf, p, &buf3, &plan, _state);
|
4086
|
+
if( circular )
|
4087
|
+
{
|
4088
|
+
|
4089
|
+
/*
|
4090
|
+
* circular, add tail to head
|
4091
|
+
*/
|
4092
|
+
rallocv(m, r, _state);
|
4093
|
+
ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m-1));
|
4094
|
+
if( n>=2 )
|
4095
|
+
{
|
4096
|
+
ae_v_add(&r->ptr.p_double[0], 1, &buf.ptr.p_double[m], 1, ae_v_len(0,n-2));
|
4097
|
+
}
|
4098
|
+
}
|
4099
|
+
else
|
4100
|
+
{
|
4101
|
+
|
4102
|
+
/*
|
4103
|
+
* non-circular, just copy
|
4104
|
+
*/
|
4105
|
+
rallocv(m+n-1, r, _state);
|
4106
|
+
ae_v_move(&r->ptr.p_double[0], 1, &buf.ptr.p_double[0], 1, ae_v_len(0,m+n-2));
|
4107
|
+
}
|
4108
|
+
}
|
4109
|
+
ae_frame_leave(_state);
|
4110
|
+
return;
|
4111
|
+
}
|
4112
|
+
|
4113
|
+
/*
|
4114
|
+
* overlap-add method
|
4115
|
+
*/
|
4116
|
+
if( alg==2 )
|
4117
|
+
{
|
4118
|
+
ae_assert((q+n-1)%2==0, "ConvR1DX: internal error!", _state);
|
4119
|
+
ae_vector_set_length(&buf, q+n-1, _state);
|
4120
|
+
ae_vector_set_length(&buf2, q+n-1, _state);
|
4121
|
+
ae_vector_set_length(&buf3, q+n-1, _state);
|
4122
|
+
ftcomplexfftplan((q+n-1)/2, 1, &plan, _state);
|
4123
|
+
|
4124
|
+
/*
|
4125
|
+
* prepare R
|
4126
|
+
*/
|
4127
|
+
if( circular )
|
4128
|
+
{
|
4129
|
+
rallocv(m, r, _state);
|
4130
|
+
for(i=0; i<=m-1; i++)
|
4131
|
+
{
|
4132
|
+
r->ptr.p_double[i] = (double)(0);
|
4133
|
+
}
|
4134
|
+
}
|
4135
|
+
else
|
4136
|
+
{
|
4137
|
+
rallocv(m+n-1, r, _state);
|
4138
|
+
for(i=0; i<=m+n-2; i++)
|
4139
|
+
{
|
4140
|
+
r->ptr.p_double[i] = (double)(0);
|
4141
|
+
}
|
4142
|
+
}
|
4143
|
+
|
4144
|
+
/*
|
4145
|
+
* pre-calculated FFT(B)
|
4146
|
+
*/
|
4147
|
+
ae_v_move(&buf2.ptr.p_double[0], 1, &b->ptr.p_double[0], 1, ae_v_len(0,n-1));
|
4148
|
+
for(j=n; j<=q+n-2; j++)
|
4149
|
+
{
|
4150
|
+
buf2.ptr.p_double[j] = (double)(0);
|
4151
|
+
}
|
4152
|
+
fftr1dinternaleven(&buf2, q+n-1, &buf3, &plan, _state);
|
4153
|
+
|
4154
|
+
/*
|
4155
|
+
* main overlap-add cycle
|
4156
|
+
*/
|
4157
|
+
i = 0;
|
4158
|
+
while(i<=m-1)
|
4159
|
+
{
|
4160
|
+
p = ae_minint(q, m-i, _state);
|
4161
|
+
ae_v_move(&buf.ptr.p_double[0], 1, &a->ptr.p_double[i], 1, ae_v_len(0,p-1));
|
4162
|
+
for(j=p; j<=q+n-2; j++)
|
4163
|
+
{
|
4164
|
+
buf.ptr.p_double[j] = (double)(0);
|
4165
|
+
}
|
4166
|
+
fftr1dinternaleven(&buf, q+n-1, &buf3, &plan, _state);
|
4167
|
+
buf.ptr.p_double[0] = buf.ptr.p_double[0]*buf2.ptr.p_double[0];
|
4168
|
+
buf.ptr.p_double[1] = buf.ptr.p_double[1]*buf2.ptr.p_double[1];
|
4169
|
+
for(j=1; j<=(q+n-1)/2-1; j++)
|
4170
|
+
{
|
4171
|
+
ax = buf.ptr.p_double[2*j+0];
|
4172
|
+
ay = buf.ptr.p_double[2*j+1];
|
4173
|
+
bx = buf2.ptr.p_double[2*j+0];
|
4174
|
+
by = buf2.ptr.p_double[2*j+1];
|
4175
|
+
tx = ax*bx-ay*by;
|
4176
|
+
ty = ax*by+ay*bx;
|
4177
|
+
buf.ptr.p_double[2*j+0] = tx;
|
4178
|
+
buf.ptr.p_double[2*j+1] = ty;
|
4179
|
+
}
|
4180
|
+
fftr1dinvinternaleven(&buf, q+n-1, &buf3, &plan, _state);
|
4181
|
+
if( circular )
|
4182
|
+
{
|
4183
|
+
j1 = ae_minint(i+p+n-2, m-1, _state)-i;
|
4184
|
+
j2 = j1+1;
|
4185
|
+
}
|
4186
|
+
else
|
4187
|
+
{
|
4188
|
+
j1 = p+n-2;
|
4189
|
+
j2 = j1+1;
|
4190
|
+
}
|
4191
|
+
ae_v_add(&r->ptr.p_double[i], 1, &buf.ptr.p_double[0], 1, ae_v_len(i,i+j1));
|
4192
|
+
if( p+n-2>=j2 )
|
4193
|
+
{
|
4194
|
+
ae_v_add(&r->ptr.p_double[0], 1, &buf.ptr.p_double[j2], 1, ae_v_len(0,p+n-2-j2));
|
4195
|
+
}
|
4196
|
+
i = i+p;
|
4197
|
+
}
|
4198
|
+
ae_frame_leave(_state);
|
4199
|
+
return;
|
4200
|
+
}
|
4201
|
+
ae_frame_leave(_state);
|
4202
|
+
}
|
4203
|
+
|
4204
|
+
|
4205
|
+
#endif
|
4206
|
+
#if defined(AE_COMPILE_CORR) || !defined(AE_PARTIAL_BUILD)
|
4207
|
+
|
4208
|
+
|
4209
|
+
/*************************************************************************
|
4210
|
+
1-dimensional complex cross-correlation.
|
4211
|
+
|
4212
|
+
For given Pattern/Signal returns corr(Pattern,Signal) (non-circular).
|
4213
|
+
|
4214
|
+
Correlation is calculated using reduction to convolution. Algorithm with
|
4215
|
+
max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info
|
4216
|
+
about performance).
|
4217
|
+
|
4218
|
+
IMPORTANT:
|
4219
|
+
for historical reasons subroutine accepts its parameters in reversed
|
4220
|
+
order: CorrC1D(Signal, Pattern) = Pattern x Signal (using traditional
|
4221
|
+
definition of cross-correlation, denoting cross-correlation as "x").
|
4222
|
+
|
4223
|
+
INPUT PARAMETERS
|
4224
|
+
Signal - array[0..N-1] - complex function to be transformed,
|
4225
|
+
signal containing pattern
|
4226
|
+
N - problem size
|
4227
|
+
Pattern - array[0..M-1] - complex function to be transformed,
|
4228
|
+
pattern to 'search' within a signal
|
4229
|
+
M - problem size
|
4230
|
+
|
4231
|
+
OUTPUT PARAMETERS
|
4232
|
+
R - cross-correlation, array[0..N+M-2]:
|
4233
|
+
* positive lags are stored in R[0..N-1],
|
4234
|
+
R[i] = sum(conj(pattern[j])*signal[i+j]
|
4235
|
+
* negative lags are stored in R[N..N+M-2],
|
4236
|
+
R[N+M-1-i] = sum(conj(pattern[j])*signal[-i+j]
|
4237
|
+
|
4238
|
+
NOTE:
|
4239
|
+
It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero
|
4240
|
+
on [-K..M-1], you can still use this subroutine, just shift result by K.
|
4241
|
+
|
4242
|
+
NOTE: there is a buffered version of this function, CorrC1DBuf(), which
|
4243
|
+
can reuse space previously allocated in its output parameter R.
|
4244
|
+
|
4245
|
+
-- ALGLIB --
|
4246
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
4247
|
+
*************************************************************************/
|
4248
|
+
void corrc1d(/* Complex */ const ae_vector* signal,
|
4249
|
+
ae_int_t n,
|
4250
|
+
/* Complex */ const ae_vector* pattern,
|
4251
|
+
ae_int_t m,
|
4252
|
+
/* Complex */ ae_vector* r,
|
4253
|
+
ae_state *_state)
|
4254
|
+
{
|
4255
|
+
|
4256
|
+
ae_vector_clear(r);
|
4257
|
+
|
4258
|
+
ae_assert(n>0&&m>0, "CorrC1D: incorrect N or M!", _state);
|
4259
|
+
corrc1dbuf(signal, n, pattern, m, r, _state);
|
4260
|
+
}
|
4261
|
+
|
4262
|
+
|
4263
|
+
/*************************************************************************
|
4264
|
+
1-dimensional complex cross-correlation, a buffered version of CorrC1D()
|
4265
|
+
which does not reallocate R[] if its length is enough to store the result
|
4266
|
+
(i.e. it reuses previously allocated memory as much as possible).
|
4267
|
+
|
4268
|
+
-- ALGLIB --
|
4269
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
4270
|
+
*************************************************************************/
|
4271
|
+
void corrc1dbuf(/* Complex */ const ae_vector* signal,
|
4272
|
+
ae_int_t n,
|
4273
|
+
/* Complex */ const ae_vector* pattern,
|
4274
|
+
ae_int_t m,
|
4275
|
+
/* Complex */ ae_vector* r,
|
4276
|
+
ae_state *_state)
|
4277
|
+
{
|
4278
|
+
ae_frame _frame_block;
|
4279
|
+
ae_vector p;
|
4280
|
+
ae_vector b;
|
4281
|
+
ae_int_t i;
|
4282
|
+
|
4283
|
+
ae_frame_make(_state, &_frame_block);
|
4284
|
+
memset(&p, 0, sizeof(p));
|
4285
|
+
memset(&b, 0, sizeof(b));
|
4286
|
+
ae_vector_init(&p, 0, DT_COMPLEX, _state, ae_true);
|
4287
|
+
ae_vector_init(&b, 0, DT_COMPLEX, _state, ae_true);
|
4288
|
+
|
4289
|
+
ae_assert(n>0&&m>0, "CorrC1DBuf: incorrect N or M!", _state);
|
4290
|
+
ae_vector_set_length(&p, m, _state);
|
4291
|
+
for(i=0; i<=m-1; i++)
|
4292
|
+
{
|
4293
|
+
p.ptr.p_complex[m-1-i] = ae_c_conj(pattern->ptr.p_complex[i], _state);
|
4294
|
+
}
|
4295
|
+
convc1d(&p, m, signal, n, &b, _state);
|
4296
|
+
callocv(m+n-1, r, _state);
|
4297
|
+
ae_v_cmove(&r->ptr.p_complex[0], 1, &b.ptr.p_complex[m-1], 1, "N", ae_v_len(0,n-1));
|
4298
|
+
if( m+n-2>=n )
|
4299
|
+
{
|
4300
|
+
ae_v_cmove(&r->ptr.p_complex[n], 1, &b.ptr.p_complex[0], 1, "N", ae_v_len(n,m+n-2));
|
4301
|
+
}
|
4302
|
+
ae_frame_leave(_state);
|
4303
|
+
}
|
4304
|
+
|
4305
|
+
|
4306
|
+
/*************************************************************************
|
4307
|
+
1-dimensional circular complex cross-correlation.
|
4308
|
+
|
4309
|
+
For given Pattern/Signal returns corr(Pattern,Signal) (circular).
|
4310
|
+
Algorithm has linearithmic complexity for any M/N.
|
4311
|
+
|
4312
|
+
IMPORTANT:
|
4313
|
+
for historical reasons subroutine accepts its parameters in reversed
|
4314
|
+
order: CorrC1DCircular(Signal, Pattern) = Pattern x Signal (using
|
4315
|
+
traditional definition of cross-correlation, denoting cross-correlation
|
4316
|
+
as "x").
|
4317
|
+
|
4318
|
+
INPUT PARAMETERS
|
4319
|
+
Signal - array[0..N-1] - complex function to be transformed,
|
4320
|
+
periodic signal containing pattern
|
4321
|
+
N - problem size
|
4322
|
+
Pattern - array[0..M-1] - complex function to be transformed,
|
4323
|
+
non-periodic pattern to 'search' within a signal
|
4324
|
+
M - problem size
|
4325
|
+
|
4326
|
+
OUTPUT PARAMETERS
|
4327
|
+
R - convolution: A*B. array[0..M-1].
|
4328
|
+
|
4329
|
+
NOTE: there is a buffered version of this function, CorrC1DCircular(),
|
4330
|
+
which can reuse space previously allocated in its output parameter R.
|
4331
|
+
|
4332
|
+
-- ALGLIB --
|
4333
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
4334
|
+
*************************************************************************/
|
4335
|
+
void corrc1dcircular(/* Complex */ const ae_vector* signal,
|
4336
|
+
ae_int_t m,
|
4337
|
+
/* Complex */ const ae_vector* pattern,
|
4338
|
+
ae_int_t n,
|
4339
|
+
/* Complex */ ae_vector* c,
|
4340
|
+
ae_state *_state)
|
4341
|
+
{
|
4342
|
+
ae_frame _frame_block;
|
4343
|
+
ae_vector p;
|
4344
|
+
ae_vector b;
|
4345
|
+
ae_int_t i1;
|
4346
|
+
ae_int_t i2;
|
4347
|
+
ae_int_t i;
|
4348
|
+
ae_int_t j2;
|
4349
|
+
|
4350
|
+
ae_frame_make(_state, &_frame_block);
|
4351
|
+
memset(&p, 0, sizeof(p));
|
4352
|
+
memset(&b, 0, sizeof(b));
|
4353
|
+
ae_vector_clear(c);
|
4354
|
+
ae_vector_init(&p, 0, DT_COMPLEX, _state, ae_true);
|
4355
|
+
ae_vector_init(&b, 0, DT_COMPLEX, _state, ae_true);
|
4356
|
+
|
4357
|
+
ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state);
|
4358
|
+
|
4359
|
+
/*
|
4360
|
+
* normalize task: make M>=N,
|
4361
|
+
* so A will be longer (at least - not shorter) that B.
|
4362
|
+
*/
|
4363
|
+
if( m<n )
|
4364
|
+
{
|
4365
|
+
ae_vector_set_length(&b, m, _state);
|
4366
|
+
for(i1=0; i1<=m-1; i1++)
|
4367
|
+
{
|
4368
|
+
b.ptr.p_complex[i1] = ae_complex_from_i(0);
|
4369
|
+
}
|
4370
|
+
i1 = 0;
|
4371
|
+
while(i1<n)
|
4372
|
+
{
|
4373
|
+
i2 = ae_minint(i1+m-1, n-1, _state);
|
4374
|
+
j2 = i2-i1;
|
4375
|
+
ae_v_cadd(&b.ptr.p_complex[0], 1, &pattern->ptr.p_complex[i1], 1, "N", ae_v_len(0,j2));
|
4376
|
+
i1 = i1+m;
|
4377
|
+
}
|
4378
|
+
corrc1dcircular(signal, m, &b, m, c, _state);
|
4379
|
+
ae_frame_leave(_state);
|
4380
|
+
return;
|
4381
|
+
}
|
4382
|
+
|
4383
|
+
/*
|
4384
|
+
* Task is normalized
|
4385
|
+
*/
|
4386
|
+
ae_vector_set_length(&p, n, _state);
|
4387
|
+
for(i=0; i<=n-1; i++)
|
4388
|
+
{
|
4389
|
+
p.ptr.p_complex[n-1-i] = ae_c_conj(pattern->ptr.p_complex[i], _state);
|
4390
|
+
}
|
4391
|
+
convc1dcircular(signal, m, &p, n, &b, _state);
|
4392
|
+
ae_vector_set_length(c, m, _state);
|
4393
|
+
ae_v_cmove(&c->ptr.p_complex[0], 1, &b.ptr.p_complex[n-1], 1, "N", ae_v_len(0,m-n));
|
4394
|
+
if( m-n+1<=m-1 )
|
4395
|
+
{
|
4396
|
+
ae_v_cmove(&c->ptr.p_complex[m-n+1], 1, &b.ptr.p_complex[0], 1, "N", ae_v_len(m-n+1,m-1));
|
4397
|
+
}
|
4398
|
+
ae_frame_leave(_state);
|
4399
|
+
}
|
4400
|
+
|
4401
|
+
|
4402
|
+
/*************************************************************************
|
4403
|
+
1-dimensional circular complex cross-correlation.
|
4404
|
+
|
4405
|
+
A buffered function which does not reallocate C[] if its length is enough
|
4406
|
+
to store the result (i.e. it reuses previously allocated memory as much as
|
4407
|
+
possible).
|
4408
|
+
|
4409
|
+
-- ALGLIB --
|
4410
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
4411
|
+
*************************************************************************/
|
4412
|
+
void corrc1dcircularbuf(/* Complex */ const ae_vector* signal,
|
4413
|
+
ae_int_t m,
|
4414
|
+
/* Complex */ const ae_vector* pattern,
|
4415
|
+
ae_int_t n,
|
4416
|
+
/* Complex */ ae_vector* c,
|
4417
|
+
ae_state *_state)
|
4418
|
+
{
|
4419
|
+
ae_frame _frame_block;
|
4420
|
+
ae_vector p;
|
4421
|
+
ae_vector b;
|
4422
|
+
ae_int_t i1;
|
4423
|
+
ae_int_t i2;
|
4424
|
+
ae_int_t i;
|
4425
|
+
ae_int_t j2;
|
4426
|
+
|
4427
|
+
ae_frame_make(_state, &_frame_block);
|
4428
|
+
memset(&p, 0, sizeof(p));
|
4429
|
+
memset(&b, 0, sizeof(b));
|
4430
|
+
ae_vector_init(&p, 0, DT_COMPLEX, _state, ae_true);
|
4431
|
+
ae_vector_init(&b, 0, DT_COMPLEX, _state, ae_true);
|
4432
|
+
|
4433
|
+
ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state);
|
4434
|
+
|
4435
|
+
/*
|
4436
|
+
* normalize task: make M>=N,
|
4437
|
+
* so A will be longer (at least - not shorter) that B.
|
4438
|
+
*/
|
4439
|
+
if( m<n )
|
4440
|
+
{
|
4441
|
+
ae_vector_set_length(&b, m, _state);
|
4442
|
+
for(i1=0; i1<=m-1; i1++)
|
4443
|
+
{
|
4444
|
+
b.ptr.p_complex[i1] = ae_complex_from_i(0);
|
4445
|
+
}
|
4446
|
+
i1 = 0;
|
4447
|
+
while(i1<n)
|
4448
|
+
{
|
4449
|
+
i2 = ae_minint(i1+m-1, n-1, _state);
|
4450
|
+
j2 = i2-i1;
|
4451
|
+
ae_v_cadd(&b.ptr.p_complex[0], 1, &pattern->ptr.p_complex[i1], 1, "N", ae_v_len(0,j2));
|
4452
|
+
i1 = i1+m;
|
4453
|
+
}
|
4454
|
+
corrc1dcircularbuf(signal, m, &b, m, c, _state);
|
4455
|
+
ae_frame_leave(_state);
|
4456
|
+
return;
|
4457
|
+
}
|
4458
|
+
|
4459
|
+
/*
|
4460
|
+
* Task is normalized
|
4461
|
+
*/
|
4462
|
+
ae_vector_set_length(&p, n, _state);
|
4463
|
+
for(i=0; i<=n-1; i++)
|
4464
|
+
{
|
4465
|
+
p.ptr.p_complex[n-1-i] = ae_c_conj(pattern->ptr.p_complex[i], _state);
|
4466
|
+
}
|
4467
|
+
convc1dcircular(signal, m, &p, n, &b, _state);
|
4468
|
+
callocv(m, c, _state);
|
4469
|
+
ae_v_cmove(&c->ptr.p_complex[0], 1, &b.ptr.p_complex[n-1], 1, "N", ae_v_len(0,m-n));
|
4470
|
+
if( m-n+1<=m-1 )
|
4471
|
+
{
|
4472
|
+
ae_v_cmove(&c->ptr.p_complex[m-n+1], 1, &b.ptr.p_complex[0], 1, "N", ae_v_len(m-n+1,m-1));
|
4473
|
+
}
|
4474
|
+
ae_frame_leave(_state);
|
4475
|
+
}
|
4476
|
+
|
4477
|
+
|
4478
|
+
/*************************************************************************
|
4479
|
+
1-dimensional real cross-correlation.
|
4480
|
+
|
4481
|
+
For given Pattern/Signal returns corr(Pattern,Signal) (non-circular).
|
4482
|
+
|
4483
|
+
Correlation is calculated using reduction to convolution. Algorithm with
|
4484
|
+
max(N,N)*log(max(N,N)) complexity is used (see ConvC1D() for more info
|
4485
|
+
about performance).
|
4486
|
+
|
4487
|
+
IMPORTANT:
|
4488
|
+
for historical reasons subroutine accepts its parameters in reversed
|
4489
|
+
order: CorrR1D(Signal, Pattern) = Pattern x Signal (using traditional
|
4490
|
+
definition of cross-correlation, denoting cross-correlation as "x").
|
4491
|
+
|
4492
|
+
INPUT PARAMETERS
|
4493
|
+
Signal - array[0..N-1] - real function to be transformed,
|
4494
|
+
signal containing pattern
|
4495
|
+
N - problem size
|
4496
|
+
Pattern - array[0..M-1] - real function to be transformed,
|
4497
|
+
pattern to 'search' withing signal
|
4498
|
+
M - problem size
|
4499
|
+
|
4500
|
+
OUTPUT PARAMETERS
|
4501
|
+
R - cross-correlation, array[0..N+M-2]:
|
4502
|
+
* positive lags are stored in R[0..N-1],
|
4503
|
+
R[i] = sum(pattern[j]*signal[i+j]
|
4504
|
+
* negative lags are stored in R[N..N+M-2],
|
4505
|
+
R[N+M-1-i] = sum(pattern[j]*signal[-i+j]
|
4506
|
+
|
4507
|
+
NOTE:
|
4508
|
+
It is assumed that pattern domain is [0..M-1]. If Pattern is non-zero
|
4509
|
+
on [-K..M-1], you can still use this subroutine, just shift result by K.
|
4510
|
+
|
4511
|
+
NOTE: there is a buffered version of this function, CorrR1DBuf(), which
|
4512
|
+
can reuse space previously allocated in its output parameter R.
|
4513
|
+
|
4514
|
+
-- ALGLIB --
|
4515
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
4516
|
+
*************************************************************************/
|
4517
|
+
void corrr1d(/* Real */ const ae_vector* signal,
|
4518
|
+
ae_int_t n,
|
4519
|
+
/* Real */ const ae_vector* pattern,
|
4520
|
+
ae_int_t m,
|
4521
|
+
/* Real */ ae_vector* r,
|
4522
|
+
ae_state *_state)
|
4523
|
+
{
|
4524
|
+
|
4525
|
+
ae_vector_clear(r);
|
4526
|
+
|
4527
|
+
ae_assert(n>0&&m>0, "CorrR1D: incorrect N or M!", _state);
|
4528
|
+
corrr1dbuf(signal, n, pattern, m, r, _state);
|
4529
|
+
}
|
4530
|
+
|
4531
|
+
|
4532
|
+
/*************************************************************************
|
4533
|
+
1-dimensional real cross-correlation, buffered function, which does not
|
4534
|
+
reallocate R[] if its length is enough to store the result (i.e. it reuses
|
4535
|
+
previously allocated memory as much as possible).
|
4536
|
+
|
4537
|
+
-- ALGLIB --
|
4538
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
4539
|
+
*************************************************************************/
|
4540
|
+
void corrr1dbuf(/* Real */ const ae_vector* signal,
|
4541
|
+
ae_int_t n,
|
4542
|
+
/* Real */ const ae_vector* pattern,
|
4543
|
+
ae_int_t m,
|
4544
|
+
/* Real */ ae_vector* r,
|
4545
|
+
ae_state *_state)
|
4546
|
+
{
|
4547
|
+
ae_frame _frame_block;
|
4548
|
+
ae_vector p;
|
4549
|
+
ae_vector b;
|
4550
|
+
ae_int_t i;
|
4551
|
+
|
4552
|
+
ae_frame_make(_state, &_frame_block);
|
4553
|
+
memset(&p, 0, sizeof(p));
|
4554
|
+
memset(&b, 0, sizeof(b));
|
4555
|
+
ae_vector_init(&p, 0, DT_REAL, _state, ae_true);
|
4556
|
+
ae_vector_init(&b, 0, DT_REAL, _state, ae_true);
|
4557
|
+
|
4558
|
+
ae_assert(n>0&&m>0, "CorrR1DBuf: incorrect N or M!", _state);
|
4559
|
+
ae_vector_set_length(&p, m, _state);
|
4560
|
+
for(i=0; i<=m-1; i++)
|
4561
|
+
{
|
4562
|
+
p.ptr.p_double[m-1-i] = pattern->ptr.p_double[i];
|
4563
|
+
}
|
4564
|
+
convr1d(&p, m, signal, n, &b, _state);
|
4565
|
+
rallocv(m+n-1, r, _state);
|
4566
|
+
ae_v_move(&r->ptr.p_double[0], 1, &b.ptr.p_double[m-1], 1, ae_v_len(0,n-1));
|
4567
|
+
if( m+n-2>=n )
|
4568
|
+
{
|
4569
|
+
ae_v_move(&r->ptr.p_double[n], 1, &b.ptr.p_double[0], 1, ae_v_len(n,m+n-2));
|
4570
|
+
}
|
4571
|
+
ae_frame_leave(_state);
|
4572
|
+
}
|
4573
|
+
|
4574
|
+
|
4575
|
+
/*************************************************************************
|
4576
|
+
1-dimensional circular real cross-correlation.
|
4577
|
+
|
4578
|
+
For given Pattern/Signal returns corr(Pattern,Signal) (circular).
|
4579
|
+
Algorithm has linearithmic complexity for any M/N.
|
4580
|
+
|
4581
|
+
IMPORTANT:
|
4582
|
+
for historical reasons subroutine accepts its parameters in reversed
|
4583
|
+
order: CorrR1DCircular(Signal, Pattern) = Pattern x Signal (using
|
4584
|
+
traditional definition of cross-correlation, denoting cross-correlation
|
4585
|
+
as "x").
|
4586
|
+
|
4587
|
+
INPUT PARAMETERS
|
4588
|
+
Signal - array[0..N-1] - real function to be transformed,
|
4589
|
+
periodic signal containing pattern
|
4590
|
+
N - problem size
|
4591
|
+
Pattern - array[0..M-1] - real function to be transformed,
|
4592
|
+
non-periodic pattern to search withing signal
|
4593
|
+
M - problem size
|
4594
|
+
|
4595
|
+
OUTPUT PARAMETERS
|
4596
|
+
R - convolution: A*B. array[0..M-1].
|
4597
|
+
|
4598
|
+
NOTE: there is a buffered version of this function, CorrR1DCircularBuf(),
|
4599
|
+
which can reuse space previously allocated in its output parameter C.
|
4600
|
+
|
4601
|
+
-- ALGLIB --
|
4602
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
4603
|
+
*************************************************************************/
|
4604
|
+
void corrr1dcircular(/* Real */ const ae_vector* signal,
|
4605
|
+
ae_int_t m,
|
4606
|
+
/* Real */ const ae_vector* pattern,
|
4607
|
+
ae_int_t n,
|
4608
|
+
/* Real */ ae_vector* c,
|
4609
|
+
ae_state *_state)
|
4610
|
+
{
|
4611
|
+
|
4612
|
+
ae_vector_clear(c);
|
4613
|
+
|
4614
|
+
ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state);
|
4615
|
+
corrr1dcircularbuf(signal, m, pattern, n, c, _state);
|
4616
|
+
}
|
4617
|
+
|
4618
|
+
|
4619
|
+
/*************************************************************************
|
4620
|
+
1-dimensional circular real cross-correlation, buffered version , which
|
4621
|
+
does not reallocate C[] if its length is enough to store the result (i.e.
|
4622
|
+
it reuses previously allocated memory as much as possible).
|
4623
|
+
|
4624
|
+
-- ALGLIB --
|
4625
|
+
Copyright 21.07.2009 by Bochkanov Sergey
|
4626
|
+
*************************************************************************/
|
4627
|
+
void corrr1dcircularbuf(/* Real */ const ae_vector* signal,
|
4628
|
+
ae_int_t m,
|
4629
|
+
/* Real */ const ae_vector* pattern,
|
4630
|
+
ae_int_t n,
|
4631
|
+
/* Real */ ae_vector* c,
|
4632
|
+
ae_state *_state)
|
4633
|
+
{
|
4634
|
+
ae_frame _frame_block;
|
4635
|
+
ae_vector p;
|
4636
|
+
ae_vector b;
|
4637
|
+
ae_int_t i1;
|
4638
|
+
ae_int_t i2;
|
4639
|
+
ae_int_t i;
|
4640
|
+
ae_int_t j2;
|
4641
|
+
|
4642
|
+
ae_frame_make(_state, &_frame_block);
|
4643
|
+
memset(&p, 0, sizeof(p));
|
4644
|
+
memset(&b, 0, sizeof(b));
|
4645
|
+
ae_vector_init(&p, 0, DT_REAL, _state, ae_true);
|
4646
|
+
ae_vector_init(&b, 0, DT_REAL, _state, ae_true);
|
4647
|
+
|
4648
|
+
ae_assert(n>0&&m>0, "ConvC1DCircular: incorrect N or M!", _state);
|
4649
|
+
|
4650
|
+
/*
|
4651
|
+
* normalize task: make M>=N,
|
4652
|
+
* so A will be longer (at least - not shorter) that B.
|
4653
|
+
*/
|
4654
|
+
if( m<n )
|
4655
|
+
{
|
4656
|
+
ae_vector_set_length(&b, m, _state);
|
4657
|
+
for(i1=0; i1<=m-1; i1++)
|
4658
|
+
{
|
4659
|
+
b.ptr.p_double[i1] = (double)(0);
|
4660
|
+
}
|
4661
|
+
i1 = 0;
|
4662
|
+
while(i1<n)
|
4663
|
+
{
|
4664
|
+
i2 = ae_minint(i1+m-1, n-1, _state);
|
4665
|
+
j2 = i2-i1;
|
4666
|
+
ae_v_add(&b.ptr.p_double[0], 1, &pattern->ptr.p_double[i1], 1, ae_v_len(0,j2));
|
4667
|
+
i1 = i1+m;
|
4668
|
+
}
|
4669
|
+
corrr1dcircularbuf(signal, m, &b, m, c, _state);
|
4670
|
+
ae_frame_leave(_state);
|
4671
|
+
return;
|
4672
|
+
}
|
4673
|
+
|
4674
|
+
/*
|
4675
|
+
* Task is normalized
|
4676
|
+
*/
|
4677
|
+
ae_vector_set_length(&p, n, _state);
|
4678
|
+
for(i=0; i<=n-1; i++)
|
4679
|
+
{
|
4680
|
+
p.ptr.p_double[n-1-i] = pattern->ptr.p_double[i];
|
4681
|
+
}
|
4682
|
+
convr1dcircularbuf(signal, m, &p, n, &b, _state);
|
4683
|
+
rallocv(m, c, _state);
|
4684
|
+
ae_v_move(&c->ptr.p_double[0], 1, &b.ptr.p_double[n-1], 1, ae_v_len(0,m-n));
|
4685
|
+
if( m-n+1<=m-1 )
|
4686
|
+
{
|
4687
|
+
ae_v_move(&c->ptr.p_double[m-n+1], 1, &b.ptr.p_double[0], 1, ae_v_len(m-n+1,m-1));
|
4688
|
+
}
|
4689
|
+
ae_frame_leave(_state);
|
4690
|
+
}
|
4691
|
+
|
4692
|
+
|
4693
|
+
#endif
|
4694
|
+
|
4695
|
+
}
|
4696
|
+
|