freqest.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 "freqest.h"
15 
16 #ifdef HAVE_LAPACK
17 
18 #include "matrix.h"
19 #include <numeric>
20 #include <boost/numeric/ublas/matrix_proxy.hpp>
21 #include <boost/numeric/ublas/io.hpp>
22 
23 void
24 FreqEstimation::genSpectrum(const std::vector<std::complex<double> >& memin,
25  std::vector<std::complex<double> >& memout,
26  int t0, double tol, FFT::twindowfunc windowfunc, double windowlength) {
27  int t = memin.size();
28  int n = memout.size();
29 
30  if(t > 1024)
31  throw XKameError(i18n("Too large size to allocate a matrix."), __FILE__, __LINE__);
32 
33  int wpoints = lrint(numberOfNoises(memin)); //# of fittable data in freq. domain.
34  wpoints = std::min(std::max(wpoints, t/100 + 1), t);
35 // fprintf(stderr, "# of data points = %d\n", wpoints);
36 
37  double tpoworg = 0.0;
38  for(int i = 0; i < t; i++) {
39  tpoworg += std::norm(memin[i]);
40  }
41 
42  std::vector<std::complex<double> > rx(t);
43  autoCorrelation(memin, rx);
44  //# of signal space.
45  int p = t; // / 2 - 1;
46  rx.resize(p);
47  // Correlation matrix.
48  ublas::matrix<std::complex<double> > r(p, p);
49  for(int i = 0; i < p; i++) {
50  ublas::matrix_row<ublas::matrix<std::complex<double> > > rrow(r, i);
51  for(int j = i; j < p; j++) {
52  rrow(j) = rx[j - i];
53  }
54  }
55  ublas::matrix<std::complex<double> > eigv;
56  ublas::vector<double> lambda;
57  double tol_lambda = tol * std::abs(rx[0]) * 0.1;
58  eigHermiteRRR(r, lambda, eigv, tol_lambda);
59 
60  //# of signals.
61  int numsig = 0;
62  if(!m_mvdl_method) {
63  //Minimum IC.
64  double minic = 1e99;
65  double sumlambda = 0.0, sumloglambda = 1.0;
66  for(int i = 0; i < p; i++) {
67  sumlambda += lambda[i];
68  sumloglambda += log(lambda[i]);
69  int q = p - 1 - i;
70  double logl = t * (p - q) * (sumloglambda / (double)(p - q) - log(sumlambda / (double)(p - q)));
71  double ic = m_funcIC(logl, q * (2*p - q), wpoints);
72  if(ic < minic) {
73  minic = ic;
74  numsig = q;
75  }
76  }
77  numsig *= windowlength;
78  numsig = std::max(std::min(numsig, p - 1), 0);
79 
80 // fprintf(stderr, "MinIC=%g, # of signal=%d, p=%d\n", minic, numsig, p);
81 
82 // std::cout << lambda << std::endl;
83 // std::cout << eigv << std::endl;
84  }
85  std::vector<std::complex<double> > fftin(t, 0.0), fftout(t), acsum(t, 0.0);
86  for(int i = 0; i < p - numsig; i++) {
87  ublas::matrix_column<ublas::matrix<std::complex<double> > > eigvcol(eigv, i);
88  assert(fabs(norm_2(eigvcol) - 1.0) < 0.1);
89  for(int j = 0; j < p; j++) {
90  fftin[j] = eigvcol(j);
91  }
92  autoCorrelation(fftin, fftout);
93  double z = lambda[i];
94  z = std::max(z, tol_lambda);
95  z = (m_eigenvalue_method) ? (1.0 / z) : 1.0;
96  for(int k = 0; k < p; k++) {
97  acsum[k] += fftout[k] * z;
98  }
99  }
100  std::vector<std::complex<double> > zffftin(n, 0.0), zffftout(n);
101  std::vector<double> ip(n), dy(n);
102  acsum[0] /= (double)2;
103  std::copy(acsum.begin(), acsum.end(), zffftin.begin());
104  m_ifftN->exec(zffftin, zffftout);
105  for(int i = 0; i < n; i++)
106  ip[i] = std::real(zffftout[i]);
107  for(int i = 0; i < p; i++)
108  zffftin[i] = (double)((i >= n/2) ? (i - n) : i) * acsum[i] * std::complex<double>(0, 1);
109  m_ifftN->exec(zffftin, zffftout);
110  for(int i = 0; i < n; i++)
111  dy[i] = std::real(zffftout[i]);
112 
113  //Power spectrum density.
114  std::vector<double> psd(n);
115  double tpow = 0.0;
116  for(int i = 0; i < n; i++) {
117  double z = 1.0 / ip[i];
118  tpow += z;
119  psd[i] = z;
120  }
121  double normalize = n * tpoworg / tpow;
122  for(int i = 0; i < n; i++) {
123  psd[i] *= normalize;
124  }
125  //Least-Square Phase Estimation.
126  double coeff = lspe(memin, t0, psd, memout, tol, true, windowfunc);
127  normalize *= coeff * coeff;
128 
129  //Peak detection. Sub-resolution detection for smooth curves.
130  for(int ip = 0; ip < n; ip++) {
131  int in = (ip + 1) % n;
132  if((dy[ip] < 0) && (dy[in] > 0)) {
133  double dx = - dy[ip] / (dy[in] - dy[ip]);
134  if((dx >= 0) && (dx <= 1.0)) {
135  std::complex<double> z = 0.0, xn = 1.0,
136  x = std::polar(1.0, 2 * M_PI * (dx + ip) / (double)n);
137  for(int j = 0; j < p; j++) {
138  z += acsum[j] * xn;
139  xn *= x;
140  }
141  double r = sqrt(normalize * std::max(1.0 / std::real(z), 0.0));
142  m_peaks.push_back(std::pair<double, double>(r, dx + ip));
143  }
144  }
145  }
146 }
147 #endif// HAVE_LAPACK

Generated for KAME4 by  doxygen 1.8.3