NEURON
fourier.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 /* (C) Copr. 1986-92 Numerical Recipes Software #.,. */
3 
4 /* Algorithms for Fourier Transform Spectral Methods */
5 
6 #define _USE_MATH_DEFINES
7 
8 #include <math.h>
9 #include <stdio.h>
10 #include <stddef.h>
11 #include <stdlib.h>
12 
13 // to print diagnostic statements
14 // #define DEBUG_SPCTRM
15 // otherwise
16 #undef DEBUG_SPCTRM
17 
18 #undef myfabs
19 #if MAC
20 #if __GNUC__ < 4
21 #define myfabs std::fabs
22 #else
23 #define myfabs ::fabs
24 #endif
25 #else
26 #define myfabs fabs
27 #endif
28 
29 // Apple LLVM version 5.1 (clang-503.0.38) generates "unsequenced modification warning".
30 // #define SQUARE(a) ((x_=(a)) == 0.0 ? 0.0 : x_*x_)
31 static inline double SQUARE(double a) {
32  return a * a;
33 }
34 
35 extern "C" {
36 void hoc_execerror(const char*, const char*);
37 extern void nrn_exit(int);
38 } // extern "C"
39 
40 #include "nrngsl_real_radix2.cpp"
41 #include "nrngsl_hc_radix2.cpp"
42 
43 void nrngsl_realft(double* data, unsigned long n, int direction) {
44  if (direction == 1) {
45  nrngsl_fft_real_radix2_transform(data, 1, n);
46  } else {
47  nrngsl_fft_halfcomplex_radix2_inverse(data, 1, n);
48  }
49 }
50 
51 /*
52  convlv() -- convolution of a read data set with a response function
53  the respns function must be stored in wrap-around order
54 */
55 
56 /* frequency domain format copy from gsl fft to NRC fft */
57 void nrn_gsl2nrc(double* x, double* y, unsigned long n) {
58  unsigned long i, n2;
59  n2 = n / 2;
60  y[0] = x[0];
61  if (n < 2) {
62  return;
63  }
64  y[1] = x[n2];
65  for (i = 1; i < n2; ++i) {
66  y[2 * i] = x[i];
67  y[2 * i + 1] = -x[n - i];
68  }
69 }
70 void nrn_nrc2gsl(double* x, double* y, unsigned long n) {
71  double xn, xn2;
72  unsigned long i, n2;
73  n2 = n / 2;
74  xn = n;
75  xn2 = .5 * xn;
76  y[0] = x[0] * xn2;
77  if (n < 2) {
78  return;
79  }
80  y[n2] = x[1] * xn2;
81  for (i = 1; i < n2; ++i) {
82  y[i] = x[2 * i] * xn2;
83  y[n - i] = -x[2 * i + 1] * xn2;
84  }
85 }
86 
87 void nrn_convlv(double* data,
88  unsigned long n,
89  double* respns,
90  unsigned long m,
91  int isign,
92  double* ans) {
93  // data and respns are modified.
94  unsigned long i;
95  double scl, x_;
96 
97  int n2 = n / 2;
98  for (i = 1; i <= (m - 1) / 2; i++) {
99  respns[n - i] = respns[m - i];
100  }
101  for (i = (m + 1) / 2; i < n - (m - 1) / 2; i++) {
102  respns[i] = 0.0;
103  }
104  nrngsl_realft(data, n, 1);
105  nrngsl_realft(respns, n, 1);
106  ans[0] = data[0] * respns[0];
107  for (i = 1; i < n2; ++i) {
108  if (isign == 1) {
109  ans[i] = data[i] * respns[i] - data[n - i] * respns[n - i];
110  ans[n - i] = data[i] * respns[n - i] + data[n - i] * respns[i];
111  } else if (isign == -1) {
112  if ((scl = SQUARE(ans[i - 1]) + SQUARE(ans[i])) == 0.0) {
113  hoc_execerror("Deconvolving at response zero in nrn_convlv", 0);
114  }
115  scl *= 2.0;
116  ans[i] = (data[i] * respns[i] + data[n - i] * respns[n - i]) / scl;
117  ans[i] = (data[i] * respns[n - i] - data[n - i] * respns[i]) / scl;
118  } else {
119  hoc_execerror("No meaning for isign in nrn_convlv", 0);
120  }
121  }
122  ans[n2] = data[n2] * respns[n2];
123  nrngsl_realft(ans, n, -1);
124 }
125 
126 
127 /*
128  correl() -- correlation of two real data sets
129  see http://www.cv.nrao.edu/course/astr534/FourierTransforms.html SF16
130 */
131 void nrn_correl(double* x, double* y, unsigned long n, double* z) {
132  nrngsl_realft(x, n, 1);
133  nrngsl_realft(y, n, 1);
134  z[0] = x[0] * y[0];
135  int n2 = n / 2;
136  for (int i = 1; i < n2; ++i) {
137  z[i] = x[i] * y[i] + x[n - i] * y[n - i];
138  // with following sign, produces same result as old NRC code
139  z[n - i] = y[i] * x[n - i] - y[n - i] * x[i];
140  }
141  z[n2] = x[n2] * y[n2];
142  nrngsl_realft(z, n, -1);
143 }
144 
145 
146 /*
147  spctrm() -- power spectrum using fourier transforms
148  modified to take array rather than data stream.
149 */
150 
151 #define WINDOW(j, a, b) (1.0 - myfabs((((j) -1) - (a)) * (b))) /* Bartlett */
152 
153 // void nrn_spctrm(double* data, double* p, int m, int k)
154 void nrn_spctrm(double* data, double* psd, int setsize, int numsegpairs) {
155  int j, k, cx, n;
156  double a, ainv, wfac, x_;
157  double* fftv;
158 
159  // 0 is index of first meaningful element of power spectral density
160  for (j = 0; j <= setsize - 1; j++)
161  psd[j] = 0.0; // zero out any prior result
162 
163  // calc factor used to correct for window's effect on psd
164  a = setsize;
165  ainv = 1.0 / a;
166 
167  n = 2 * setsize;
168  wfac = 0.0;
169  for (j = 1; j <= n; j++)
170  wfac += SQUARE(WINDOW(j, a, 1 / a));
171 
172 #ifdef DEBUG_SPCTRM
173  printf("setsize %d, numsegpairs %d\n", setsize, numsegpairs);
174  printf("=============\n");
175  printf("window values\n");
176  for (j = 1; j <= n; j++)
177  printf("%d %f\n", j, WINDOW(j, a, 1 / a));
178  printf("initial wfac %f\n", wfac);
179 #endif
180 
181  // storage for a data segment
182  fftv = (double*) malloc((size_t) (n * sizeof(double)));
183 
184  cx = 0; // data index
185  for (k = 1; k <= numsegpairs * 2; k++) {
186 #ifdef DEBUG_SPCTRM
187  printf("==============\n");
188  printf("segment %d\n", k);
189 #endif
190 
191  // fill fftv with a segment of data
192  for (j = 0; j < n; j++)
193  fftv[j] = data[cx++];
194 #ifdef DEBUG_SPCTRM
195  for (j = 0; j < n; j++)
196  printf("datum %d %f\n", j, fftv[j]);
197  printf("--------------\n");
198 #endif
199 
200  cx -= setsize; // next segment overlaps by this much
201 
202  // apply window
203  for (j = 1; j <= n; j++)
204  fftv[j - 1] *= WINDOW(j, a, 1 / a);
205 
206  // apply fft
207  nrngsl_realft(fftv, n, 1);
208 #ifdef DEBUG_SPCTRM
209  printf("\nfftv:\n");
210  for (j = 0; j < n; j++)
211  printf("%f ", fftv[j]);
212  printf("\n");
213 #endif
214 
215  // add to psd
216  psd[0] += SQUARE(fftv[0]);
217  for (j = 1; j < setsize; j++) {
218  psd[j] += (SQUARE(fftv[j]) + SQUARE(fftv[n - j]));
219  }
220  }
221 
222  wfac = 1 / (wfac * n * numsegpairs);
223  for (j = 0; j < setsize; j++)
224  psd[j] *= wfac;
225  psd[0] *= 0.5;
226 
227 #ifdef DEBUG_SPCTRM
228  printf("1/wfac for all but DC = %f\n", 1. / wfac);
229  printf("1/wfac for DC = %f\n", 2. / wfac);
230  printf("final results--\n");
231  for (j = 0; j < setsize; j++)
232  printf("%d %f\n", j, psd[j]);
233  printf("\ndone\n");
234 #endif
235 
236  free(fftv);
237 }
238 #undef WINDOW
#define WINDOW(j, a, b)
Definition: fourier.cpp:151
void nrngsl_realft(double *data, unsigned long n, int direction)
Definition: fourier.cpp:43
void hoc_execerror(const char *, const char *)
Definition: hoc.cpp:754
void nrn_correl(double *x, double *y, unsigned long n, double *z)
Definition: fourier.cpp:131
void nrn_exit(int)
Definition: hoc.cpp:219
static double SQUARE(double a)
Definition: fourier.cpp:31
void nrn_nrc2gsl(double *x, double *y, unsigned long n)
Definition: fourier.cpp:70
void nrn_convlv(double *data, unsigned long n, double *respns, unsigned long m, int isign, double *ans)
Definition: fourier.cpp:87
void nrn_spctrm(double *data, double *psd, int setsize, int numsegpairs)
Definition: fourier.cpp:154
void nrn_gsl2nrc(double *x, double *y, unsigned long n)
Definition: fourier.cpp:57
#define i
Definition: md1redef.h:12
#define printf
Definition: mwprefix.h:26
int const size_t const size_t n
Definition: nrngsl.h:11
size_t j
static philox4x32_key_t k
Definition: nrnran123.cpp:11
static N_Vector x_
#define data
Definition: rbtqueue.cpp:49