spectrumsolver.cpp
1 /***************************************************************************
2  Copyright (C) 2002-2015 Kentaro Kitagawa
3  kitagawa@phys.s.u-tokyo.ac.jp
4 
5  This program is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License as published by the Free Software Foundation; either
8  version 2 of the License, or (at your option) any later version.
9 
10  You should have received a copy of the GNU Library General
11  Public License and a list of authors along with this program;
12  see the files COPYING and AUTHORS.
13 ***************************************************************************/
14 #include "spectrumsolver.h"
15 #include <algorithm>
16 #include <gsl/gsl_sf.h>
17 #define lambertW0 gsl_sf_lambert_W0
18 
19 SpectrumSolver::SpectrumSolver() {}
20 SpectrumSolver::~SpectrumSolver() {}
21 
22 double
23 SpectrumSolver::icAIC(double loglikelifood, int k, int /*n*/) {
24  return -2 * loglikelifood + 2 * k;
25 }
26 double
27 SpectrumSolver::icAICc(double loglikelifood, int k, int n) {
28  return -2 * loglikelifood + 2 * (k + 1) * n / (double)(n - k - 2);
29 }
30 double
31 SpectrumSolver::icHQ(double loglikelifood, int k, int n) {
32  return -2 * loglikelifood + 2 * k * log(log(n) / log(2.0));
33 }
34 double
35 SpectrumSolver::icMDL(double loglikelifood, int k, int n) {
36  return -loglikelifood + k * log(n) / 2.0;
37 }
38 
39 void
40 SpectrumSolver::genIFFT(const std::vector<std::complex<double> >& wavein) {
41  m_ifftN->exec(wavein, m_ifft);
42  int n = wavein.size();
43  double k = 1.0 / n;
44  std::complex<double> *pifft = &m_ifft[0];
45  for(unsigned int i = 0; i < n; i++) {
46  *pifft *= k;
47  pifft++;
48  }
49 }
50 
51 void
52 SpectrumSolver::window(int t, int t0, FFT::twindowfunc windowfunc,
53  double windowlength, std::vector<double> &window) {
54  double wk = 1.0 / windowLength(t, t0, windowlength);
55  window.resize(t);
56  for(int i = 0; i < t; i++) {
57  window[i] = windowfunc((i + t0) * wk);
58  }
59 }
60 void
61 SpectrumSolver::exec(const std::vector<std::complex<double> >& memin, std::vector<std::complex<double> >& memout,
62  int t0, double torr, FFT::twindowfunc windowfunc, double windowlength) throw (XKameError&) {
63  windowlength = std::max(0.0, windowlength);
64  unsigned int t = memin.size();
65  unsigned int n = memout.size();
66  if (m_ifft.size() != n) {
67  m_fftN.reset(new FFT(-1, n));
68  m_ifftN.reset(new FFT(1, n));
69  m_ifft.resize(n);
70  }
71  m_peaks.clear();
72 
73  if(hasWeighting()) {
74  genSpectrum(memin, memout, t0, torr, windowfunc, windowlength);
75  }
76  else {
77  //Rectangular window.
78  double wlen = windowLength(t, t0, windowlength);
79  int idx1 = std::max(0, std::min((int)memin.size() - 1, -t0 + (int)lrint(wlen / 2.0)));
80  int idx0 = std::min(std::max(0, -t0 - (int)lrint(wlen / 2.0)), idx1);
81  std::vector<std::complex<double> > memin1(idx1 + 1 - idx0);
82  for(unsigned int i = 0; i < memin1.size(); i++)
83  memin1[i] = memin[i + idx0];
84  t0 += idx0;
85  genSpectrum(memin1, memout, t0, torr, windowfunc, 1.0);
86  }
87 
88  std::sort(m_peaks.begin(), m_peaks.end(), std::greater<std::pair<double, double> >());
89 // std::reverse(m_peaks.begin(), m_peaks.end());
90 }
91 
92 void
93 SpectrumSolver::autoCorrelation(const std::vector<std::complex<double> >&wave,
94  std::vector<std::complex<double> >&corr) {
95  if(!m_fftRX || (m_fftRX->length() != wave.size())) {
96  int len = FFT::fitLength(wave.size() * 2);
97  m_fftRX.reset(new FFT(-1, len));
98  m_ifftRX.reset(new FFT(1, len));
99  }
100  std::vector<std::complex<double> > wavezf(m_fftRX->length(), 0.0), corrzf(m_fftRX->length());
101  std::copy(wave.begin(), wave.end(), wavezf.begin());
102  m_fftRX->exec(wavezf, corrzf);
103  for(int i = 0; i < corrzf.size(); i++)
104  wavezf[i] = std::norm(corrzf[i]);
105  m_ifftRX->exec(wavezf, corrzf);
106  corr.resize(wave.size());
107  double normalize = 1.0 / (corr.size() * m_fftRX->length());
108  for(int i = 0; i < corr.size(); i++) {
109  corr[i] = corrzf[i] * normalize;
110  }
111 }
112 double
113 SpectrumSolver::lspe(const std::vector<std::complex<double> >& wavein, int origin,
114  const std::vector<double>& psd, std::vector<std::complex<double> >& waveout,
115  double tol, bool powfit, FFT::twindowfunc windowfunc) {
116  int t = wavein.size();
117  int n = waveout.size();
118  int t0a = origin;
119  if(t0a < 0)
120  t0a += (-t0a / n + 1) * n;
121 
122  std::vector<std::complex<double> > wavezf(n, 0.0);
123  for(int i = 0; i < t; i++) {
124  int j = (t0a + i) % n;
125  wavezf[j] = wavein[i];
126  }
127  m_fftN->exec(wavezf, waveout);
128 
129  // Initial values.
130  for(int i = 0; i < n; i++) {
131  std::complex<double> z = waveout[i];
132  waveout[i] = z * sqrt(psd[i] / std::norm(z));
133  }
134  genIFFT(waveout);
135 
136  std::vector<double> weight;
137  window(t, origin, windowfunc, 1.0, weight);
138 
139  double sigma20 = 0.0, sigma2 = 0.0, coeff = 1.0;
140  for(int it = 0; it < 20; it++) {
141  double ns2 = stepLSPE(wavein, origin, psd, waveout, powfit, coeff, weight);
142  if(it == 0)
143  sigma20 = ns2;
144  dbgPrint(formatString("LSPE: err=%g, coeff=%g, it=%u\n", ns2, coeff, it));
145  genIFFT(waveout);
146  if((it > 3) && (sigma2 - ns2 < sigma20 * tol)) {
147  break;
148  }
149  sigma2 = ns2;
150  }
151  return coeff;
152 }
153 double
154 SpectrumSolver::stepLSPE(const std::vector<std::complex<double> >& wavein, int origin,
155  const std::vector<double>& psd, std::vector<std::complex<double> >& waveout,
156  bool powfit, double &coeff, const std::vector<double> &weight) {
157  int t = wavein.size();
158  int n = waveout.size();
159  int t0a = origin;
160  if(t0a < 0)
161  t0a += (-t0a / n + 1) * n;
162  double dcoeff = 1.0;
163  if(powfit) {
164  double den = 0.0;
165  double nom = 0.0;
166  for(int i = 0; i < t; i++) {
167  double w = weight[i];
168  int j = (t0a + i) % n;
169  std::complex<double> z = m_ifft[j];
170  den += std::norm(z) * w;
171  nom += std::real(std::conj(wavein[i]) * z) * w;
172  }
173  dcoeff = nom / den;
174  coeff *= dcoeff;
175  }
176  std::vector<std::complex<double> > zfin(n, 0.0), zfout(n);
177  double sigma2 = 0.0;
178  double sumw = 0.0;
179  for(int i = 0; i < t; i++) {
180  double w = weight[i];
181  sumw += w;
182  int j = (t0a + i) % n;
183  std::complex<double> z = dcoeff * m_ifft[j] - wavein[i];
184  zfin[j] = z * w;
185  sigma2 += std::norm(z) * w;
186  }
187  m_fftN->exec(zfin, zfout);
188  double sor = 1.0 / sumw;
189  double wdiag = dcoeff * sor * sumw;
190  for(int i = 0; i < n; i++) {
191  std::complex<double> z = - (zfout[i] - waveout[i] * wdiag);
192  waveout[i] = coeff * z * sqrt(psd[i] / std::norm(z));
193  }
194  return sigma2;
195 }
196 
197 double
198 SpectrumSolver::windowLength(int t, int t0, double windowlength) {
199  return 2.0 * (std::max(-t0, (int)t + t0) * windowlength);
200 }
201 
202 double
203 SpectrumSolver::numberOfNoises(const std::vector<std::complex<double> >& memin) {
204  int t = memin.size();
205  int n = fftlen();
206 
207  std::vector<std::complex<double> > zfin(n), zfft(n);
208  std::fill(zfin.begin(), zfin.end(), std::complex<double>(0.0));
209  for(int i = 0; i < t; i++) {
210  zfin[i % n] = memin[i];
211  }
212  m_fftN->exec(zfin, zfft);
213 
214  double ssum = 0.0, s2sum = 0.0;
215  for(int i = 0; i < n; i++) {
216  double s = std::abs(zfft[i]);
217  ssum += s;
218  s2sum += s*s;
219  }
220  double num = ssum*ssum/s2sum/n*t;
221 // fprintf(stderr, "# of noises = %g, ratio=%f\n", num, num/t);
222  return num;
223 }
224 
225 void
226 FFTSolver::genSpectrum(const std::vector<std::complex<double> >& fftin, std::vector<std::complex<double> >& fftout,
227  int t0, double /*torr*/, FFT::twindowfunc windowfunc, double windowlength) {
228  unsigned int t = fftin.size();
229  unsigned int n = fftout.size();
230  int t0a = t0;
231  if(t0a < 0)
232  t0a += (-t0a / n + 1) * n;
233 
234  std::vector<double> weight;
235  window(t, t0, windowfunc, windowlength, weight);
236  std::fill(m_ifft.begin(), m_ifft.end(), std::complex<double>(0.0));
237  std::vector<std::complex<double> > zffftin(n, 0.0), fftout2(n);
238  for(int i = 0; i < t; i++) {
239  int j = (t0a + i) % n;
240  m_ifft[j] = fftin[i] * weight[i];
241  zffftin[j] = m_ifft[j] * (double)(t0 + i) * std::complex<double>(0, -1);
242  }
243  m_fftN->exec(m_ifft, fftout);
244  m_fftN->exec(zffftin, fftout2);
245 
246  //Peak detection. Sub-resolution detection for smooth curves.
247  std::vector<double> dy(n); //Derivative.
248  for(int i = 0; i < n; i++) {
249  dy[i] = std::real(fftout2[i] * std::conj(fftout[i]));
250  }
251  for(int ip = 0; ip < n; ip++) {
252  int in = (ip + 1) % n;
253  if((dy[ip] > 0) && (dy[in] < 0)) {
254  double dx = - dy[ip] / (dy[in] - dy[ip]);
255 // dx = std::max(0.0, std::min(dx, 1.0));
256  if((dx >= 0) && (dx <= 1.0)) {
257 /*
258  std::complex<double> z = 0.0, xn = 1.0,
259  x = std::polar(1.0, -2 * M_PI * (dx + i - 1) / (double)n);
260  for(int j = 0; j < t; j++) {
261  z += fftin[j] * w * xn;
262  xn *= x;
263  }
264  double r = std::abs(z);
265 */
266  double r = std::abs(fftout[ip] * (1 - dx) + fftout[in] * dx);
267  m_peaks.push_back(std::pair<double, double>(r, dx + ip));
268  }
269  }
270  }
271 }
272 
273 MEMStrict::~MEMStrict() {
274 }
275 
276 void
277 MEMStrict::setup(unsigned int t, unsigned int n) {
278  if (m_lambda.size() != t) {
279  m_fftT.reset(new FFT(-1, t));
280  m_accumDY.resize(t);
281  m_accumDYFT.resize(t);
282  m_lambda.resize(t);
283  m_accumG2.resize(t);
284  }
285 }
286 void
287 MEMStrict::solveZ(double tol) {
288  unsigned int size = m_accumDYFT.size();
289  std::vector<double> dy2(size);
290  std::vector<double> &g2(m_accumG2);
291 
292  for(unsigned int i = 0; i < size; i++) {
293  dy2[i] = std::norm(m_accumDYFT[i]);
294  }
295  for(unsigned int it = 0; it < lrint(log(size) + 2); it++) {
296  double k = 2 * m_accumZ * m_accumZ;
297  for(unsigned int i = 0; i < size; i++) {
298  g2[i] = lambertW0(k * dy2[i]) * 0.5;
299  }
300  double nsumz = 0.0;
301  for(unsigned int i = 0; i < size; i++) {
302  nsumz += exp(g2[i]);
303  }
304  double err = fabs(nsumz - m_accumZ) / nsumz;
305  m_accumZ = nsumz;
306  if(err < tol) {
307 // fprintf(stderr, "MEM: Z solved w/ it=%u,err=%g\n", it, err);
308  break;
309  }
310  }
311 }
312 
313 void
314 MEMStrict::genSpectrum(const std::vector<std::complex<double> >& memin, std::vector<std::complex<double> >& memout,
315  int t0, double tol, FFT::twindowfunc /*windowfunc*/, double /*windowlength*/) {
316  int t = memin.size();
317  int n = memout.size();
318  if(t0 < 0)
319  t0 += (-t0 / n + 1) * n;
320  setup(t, n);
321  double sqrtpow = 0.0;
322  for(unsigned int i = 0; i < memin.size(); i++)
323  sqrtpow += std::norm(memin[i]);
324  sqrtpow = sqrt(sqrtpow);
325  double err = sqrtpow;
326  double alpha = 0.3;
327  for(double sigma = sqrtpow / 4.0; sigma < sqrtpow; sigma *= 1.2) {
328  // fprintf(stderr, "MEM: Using T=%u,N=%u,sigma=%g\n", t,n,sigma);
329  std::fill(m_accumDYFT.begin(), m_accumDYFT.end(), std::complex<double>(0.0));
330  std::fill(m_ifft.begin(), m_ifft.end(), std::complex<double>(0.0));
331  std::fill(m_lambda.begin(), m_lambda.end(), std::complex<double>(0.0));
332  std::fill(m_accumDY.begin(), m_accumDY.end(), std::complex<double>(0.0));
333  std::fill(m_accumG2.begin(), m_accumG2.end(), 0.0);
334  m_accumZ = t;
335  double oerr = sqrtpow;
336  unsigned int it;
337  for(it = 0; it < 50; it++) {
338  err = stepMEM(memin, memout, alpha, sigma, t0, tol);
339  if(err < tol * sqrtpow) {
340  break;
341  }
342  if(err > sqrtpow * 1.1) {
343  break;
344  }
345  if(err > oerr * 1.0) {
346  break;
347  }
348  oerr = err;
349  }
350  if(err < tol * sqrtpow) {
351  dbgPrint(formatString("MEM: Converged w/ sigma=%g, alpha=%g, err=%g, it=%u\n", sigma, alpha, err, it));
352  double osqrtpow = 0.0;
353  for(unsigned int i = 0; i < memout.size(); i++)
354  osqrtpow += std::norm(memout[i]);
355  osqrtpow = sqrt(osqrtpow / n);
356  dbgPrint(formatString("MEM: Pout/Pin=%g\n", osqrtpow/sqrtpow));
357  break;
358  }
359  else {
360  dbgPrint(formatString("MEM: Failed w/ sigma=%g, alpha=%g, err=%g, it=%u\n", sigma, alpha, err, it));
361  }
362  }
363  if(err >= tol * sqrtpow) {
364  dbgPrint(formatString("MEM: Use ZF-FFT instead.\n"));
365  std::fill(m_ifft.begin(), m_ifft.end(), std::complex<double>(0.0));
366  for(unsigned int i = 0; i < t; i++) {
367  m_ifft[(t0 + i) % n] = memin[i];
368  }
369  m_fftN->exec(m_ifft, memout);
370  }
371 
372  std::vector<std::complex<double> > zffftin(n), fftout2(n);
373  for(int i = 0; i < n; i++) {
374  zffftin[i] = m_ifft[i] * (double)((i >= n/2) ? (i - n) : i) * std::complex<double>(0, -1);
375  }
376 
377  //Peak detection. Sub-resolution detection for smooth curves.
378  m_fftN->exec(zffftin, fftout2);
379  std::vector<double> dy(n);
380  for(int i = 0; i < n; i++) {
381  dy[i] = std::real(fftout2[i] * std::conj(memout[i])); //Derivative.
382  }
383  for(int ip = 0; ip < n; ip++) {
384  int in = (ip + 1) % n;
385  if((dy[ip] > 0) && (dy[in] < 0)) {
386  double dx = - dy[ip] / (dy[in] - dy[ip]);
387  if((dx >= 0) && (dx <= 1.0)) {
388  double r = std::abs(memout[ip] * (1 - dx) + memout[in] * dx);
389  m_peaks.push_back(std::pair<double, double>(r, dx + ip));
390  }
391  }
392  }
393 }
394 double
395 MEMStrict::stepMEM(const std::vector<std::complex<double> >& memin, std::vector<std::complex<double> >& memout,
396  double alpha, double sigma, int t0, double tol) {
397  unsigned int n = m_ifft.size();
398  unsigned int t = memin.size();
399  double isigma = 1.0 / sigma;
400  std::vector<std::complex<double> > &lambdaZF(m_ifft);
401  std::fill(lambdaZF.begin(), lambdaZF.end(), std::complex<double>(0.0));
402  std::complex<double> *plambda = &m_lambda[0];
403  for(unsigned int i = 0; i < t; i++) {
404  lambdaZF[(t0 + i) % n] = *plambda * isigma;
405  plambda++;
406  }
407  m_ifftN->exec(lambdaZF, memout);
408  std::vector<double> pfz(n);
409  double sumz = 0.0;
410  double *ppfz = &pfz[0];
411  std::complex<double> *pmemout = &memout[0];
412  for(unsigned int i = 0; i < n; i++) {
413  *ppfz = exp(std::norm(*pmemout));
414  sumz += *ppfz++;
415  pmemout++;
416  }
417  double k = 2.0 * sigma / sumz * n;
418  ppfz = &pfz[0];
419  pmemout = &memout[0];
420  for(unsigned int i = 0; i < n; i++) {
421  double p = k * *ppfz++;
422  *pmemout = std::conj(*pmemout) * p;
423  pmemout++;
424  }
425  genIFFT(memout);
426 
427  k = alpha / t / sigma / 2;
428  double err = 0.0;
429  const std::complex<double> *pmemin = &memin[0];
430  std::complex<double> *pout = &m_accumDY[0];
431  for(unsigned int i = 0; i < t; i++) {
432  std::complex<double> *pifft = &m_ifft[(t0 + i) % n];
433  std::complex<double> dy = *pmemin - *pifft;
434  pmemin++;
435  err += std::norm(dy);
436  *pout += dy * k;
437  pout++;
438  }
439  err = sqrt(err);
440 
441  m_fftT->exec(m_accumDY, m_accumDYFT);
442  solveZ(tol);
443  k = sigma / t;
444  pout = &m_accumDYFT[0];
445  for(unsigned int i = 0; i < t; i++) {
446  double p = k * sqrt(m_accumG2[i] / (std::norm(*pout)));
447  *pout = std::conj(*pout) * p;
448  pout++;
449  }
450  m_fftT->exec(m_accumDYFT, m_lambda);
451  return err;
452 }

Generated for KAME4 by  doxygen 1.8.3