accelerInt  v0.1
cf.c
Go to the documentation of this file.
1 
10 #include <stdlib.h>
11 #include <math.h>
12 #include <string.h>
13 
14 #include "solver_options.h"
15 #include "linear-algebra.h"
16 
18 #define M_PI 4 * atan(1)
19 
21 #include <complex.h>
22 
24 #include <fftw3.h>
25 
27 
41 void cf ( int n, double* poles_r, double* poles_i, double* res_r, double* res_i ) {
42  // number of Chebyshev coefficients
43  const int K = 75;
44 
45  // number of points for FFT
46  const int nf = 1024;
47 
48  // roots of unity
49  fftw_complex *w = fftw_alloc_complex(nf);
50  for (int i = 0; i < nf; ++i) {
51  w[i] = cexp(2.0 * I * M_PI * (double)i / (double)nf);
52  }
53 
54  // Chebyshev points (twice over)
55  double *t = (double*) calloc (nf, sizeof(double));
56  for (int i = 0; i < nf; ++i) {
57  t[i] = creal(w[i]);
58  }
59 
60  // scale factor for stability
61  double scl = 9.0;
62 
63  // exp(x) transpl. to [-1,1]
64  fftw_complex *F = fftw_alloc_complex(nf);
65  for (int i = 0; i < nf; ++i) {
66  F[i] = cexp(scl * (t[i] - 1.0) / (t[i] + 1.0 + ATOL));
67  }
68 
69  free (t);
70 
71  // Chebyshev coefficients of F
72  fftw_complex *fftF = fftw_alloc_complex(nf);
73  fftw_plan p;
74  p = fftw_plan_dft_1d(nf, F, fftF, FFTW_FORWARD, FFTW_ESTIMATE);
75  fftw_execute(p);
76 
77  double *c = (double*) calloc (nf, sizeof(double));
78  for (int i = 0; i < nf; ++i) {
79  c[i] = creal(fftF[i]) / (double)nf;
80  }
81 
82  fftw_free (fftF);
83  fftw_free (F);
84 
85  // analytic part of f of F
86  fftw_complex *f = fftw_alloc_complex(nf);
87  memset (f, 0.0, nf * sizeof(fftw_complex)); // set to zero
88 
89  for (int i = 0; i < nf; ++i) {
90  for (int j = K; j >= 0; --j) {
91  f[i] += c[j] * cpow(w[i], j);
92  }
93  }
94 
95  // SVD of Hankel matrix
96  double *S = (double*) calloc (K, sizeof(double));
97  double *U = (double*) calloc (K * K, sizeof(double));
98  double *V = (double*) calloc (K * K, sizeof(double));
99  double *hankel = (double*) calloc (K * K, sizeof(double));
100 
101  memset (hankel, 0.0, K * K * sizeof(double)); // fill with 0
102 
103  for (int i = 0; i < K; ++i) {
104  for (int j = 0; j <= i; ++j) {
105  hankel[(i - j) + K * j] = c[i + 1];
106  }
107  }
108  svd (K, hankel, S, U, V);
109 
110  free (c);
111  free (hankel);
112 
113  // singular value
114  double s_val = S[n];
115 
116  // singular vectors
117  // need u and v to be complex type for fft
118  fftw_complex *u = fftw_alloc_complex(nf);
119  fftw_complex *v = fftw_alloc_complex(nf);
120 
121  // fill with zeros
122  memset (u, 0.0, nf * sizeof(fftw_complex));
123  memset (v, 0.0, nf * sizeof(fftw_complex));
124 
125  for (int i = 0; i < K; ++i) {
126  u[i] = U[(K - i - 1) + K * n];
127  v[i] = V[i + K * n];
128  }
129 
130  free (U);
131  free (V);
132  free (S);
133 
134  // create copy of v for later use
135  double *v2 = (double*) calloc (K, sizeof(double));
136  for (int i = 0; i < K; ++i) {
137  v2[i] = creal(v[i]);
138  }
139 
140  // finite Blaschke product
141  fftw_complex *b1 = fftw_alloc_complex(nf);
142  fftw_complex *b2 = fftw_alloc_complex(nf);
143  fftw_complex *b = fftw_alloc_complex(nf);
144 
145  p = fftw_plan_dft_1d(nf, u, b1, FFTW_FORWARD, FFTW_ESTIMATE);
146  fftw_execute(p);
147 
148  p = fftw_plan_dft_1d(nf, v, b2, FFTW_FORWARD, FFTW_ESTIMATE);
149  fftw_execute(p);
150 
151  for (int i = 0; i < nf; ++i) {
152  b[i] = b1[i] / b2[i];
153  }
154 
155  fftw_free (u);
156  fftw_free (v);
157  fftw_free (b1);
158  fftw_free (b2);
159 
160  // extended function r-tilde
161  fftw_complex *rt = fftw_alloc_complex(nf);
162  for (int i = 0; i < nf; ++i) {
163  rt[i] = f[i] - s_val * cpow(w[i], K) * b[i];
164  }
165 
166  fftw_free (f);
167  fftw_free (b);
168 
169  // poles
170  double complex *zr = (double complex*) calloc (K - 1, sizeof(double complex));
171 
172  // get roots of v
173  roots (K, v2, zr);
174 
175  free (v2);
176 
177  double complex *qk = (double complex*) calloc (n, sizeof(double complex));
178  memset (qk, 0.0, n * sizeof(double complex));
179 
180  int i = 0;
181  for (int j = 0; j < K - 1; ++j) {
182  if (cabs(zr[j]) > 1.0) {
183  qk[i] = zr[j];
184  i += 1;
185  }
186  }
187 
188  free (zr);
189 
190  // coefficients of denominator
191  double complex *qc_i = (double complex*) calloc (n + 1, sizeof(double complex));
192  memset (qc_i, 0.0, (n + 1) * sizeof(double complex)); // fill with 0
193 
194  qc_i[0] = 1.0;
195  for (int j = 0; j < n; ++j) {
196  double complex qc_old1 = qc_i[0];
197  double complex qc_old2;
198 
199  for (int i = 1; i < j + 2; ++i) {
200  qc_old2 = qc_i[i];
201  qc_i[i] = qc_i[i] - qk[j] * qc_old1;
202  qc_old1 = qc_old2;
203  }
204  }
205 
206  // qc_i will only have real parts, but want real array
207  double *qc = (double*) calloc (n + 1, sizeof(double));
208  for (int i = 0; i < n + 1; ++i) {
209  qc[i] = creal(qc_i[i]);
210  }
211 
212  free (qc_i);
213 
214  // numerator
215  fftw_complex *pt = fftw_alloc_complex(nf);
216  memset (pt, 0.0, nf * sizeof(fftw_complex));
217  for (int i = 0; i < nf; ++i) {
218  for (int j = 0; j < n + 1; ++j) {
219  pt[i] += qc[j] * cpow(w[i], n - j);
220  }
221  pt[i] *= rt[i];
222  }
223 
224  fftw_free (w);
225  free (qc);
226  fftw_free (rt);
227 
228  // coefficients of numerator
229  fftw_complex *ptc_i = fftw_alloc_complex(nf);
230  p = fftw_plan_dft_1d(nf, pt, ptc_i, FFTW_FORWARD, FFTW_ESTIMATE);
231  fftw_execute(p);
232 
233  double *ptc = (double*) calloc(n + 1, sizeof(double));
234  for (int i = 0; i < n + 1; ++i) {
235  ptc[i] = creal(ptc_i[n - i]) / (double)nf;
236  }
237 
238  fftw_destroy_plan(p);
239  fftw_free (pt);
240  fftw_free (ptc_i);
241 
242  // poles
243  double complex *res = (double complex*) calloc (n, sizeof(double complex));
244  memset (res, 0.0, n * sizeof(double complex)); // fill with 0
245 
246  double complex *qk2 = (double complex*) calloc (n - 1, sizeof(double complex));
247  double complex *q2 = (double complex*) calloc (n, sizeof(double complex));
248 
249  // calculate residues
250  for (int k = 0; k < n; ++k) {
251  double complex q = qk[k];
252 
253  int j = 0;
254  for (int i = 0; i < n; ++i) {
255  if (i != k) {
256  qk2[j] = qk[i];
257  j += 1;
258  }
259  }
260 
261  memset (q2, 0.0, n * sizeof(double complex)); // fill with 0
262  q2[0] = 1.0;
263  for (int j = 0; j < n - 1; ++j) {
264  double complex q_old1 = q2[0];
265  double complex q_old2;
266  for (int i = 1; i < j + 2; ++i) {
267  q_old2 = q2[i];
268  q2[i] = q2[i] - qk2[j] * q_old1;
269  q_old1 = q_old2;
270  }
271  }
272 
273  double complex ck1 = 0.0;
274  for (int i = 0; i < n + 1; ++i) {
275  ck1 += ptc[i] * cpow(q, n - i);
276  }
277 
278  double complex ck2 = 0.0;
279  for (int i = 0; i < n; ++i) {
280  ck2 += q2[i] * cpow(q, n - 1 - i);
281  }
282 
283  res[k] = ck1 / ck2;
284  }
285 
286  free (ptc);
287  free (qk2);
288  free (q2);
289 
290  double complex *poles = (double complex*) calloc (n, sizeof(double complex));
291  for (int i = 0; i < n; ++i) {
292  // poles in z-plane
293  poles[i] = scl * (qk[i] - 1.0) * (qk[i] - 1.0) / ((qk[i] + 1.0) * (qk[i] + 1.0));
294 
295  // residues in z-plane
296  res[i] = 4.0 * res[i] * poles[i] / (qk[i] * qk[i] - 1.0);
297  }
298 
299  // separate real and imaginary parts
300  for (int i = 0; i < n; ++i) {
301  poles_r[i] = creal(poles[i]);
302  poles_i[i] = cimag(poles[i]);
303 
304  res_r[i] = creal(res[i]);
305  res_i[i] = cimag(res[i]);
306  }
307 
308  free (qk);
309  free (poles);
310  free (res);
311  fftw_cleanup();
312 }
double complex poles[N_RA]
#define M_PI
Definition: cf.c:18
void cf(int n, double *poles_r, double *poles_i, double *res_r, double *res_i)
Function that calculates the poles and residuals of best rational (partial fraction) approximant to t...
Definition: cf.c:41
A file generated by Scons that specifies various options to the solvers.
#define ATOL
void roots(int n, double *v, double complex *rt)
Polynomial root finding function.
Header definitions of linear algebra routines needed for the Carathéodory-Fejér method.
void svd(int n, double *A, double *S, double *U, double *V)
Singular value decomposition function.
double complex res[N_RA]