ar.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 "ar.h"
15 
16 template <class Context>
17 YuleWalkerCousin<Context>::YuleWalkerCousin(tfuncIC ic) : SpectrumSolver(), m_funcARIC(ic) {
18 }
19 
20 template <class Context>
21 void
22 YuleWalkerCousin<Context>::genSpectrum(const std::vector<std::complex<double> >& memin, std::vector<std::complex<double> >& memout,
23  int t0, double tol, FFT::twindowfunc windowfunc, double windowlength) {
24  int t = memin.size();
25  int n = memout.size();
26 
27  int wpoints = lrint(numberOfNoises(memin)); //# of fittable data in freq. domain.
28  wpoints = std::min(std::max(wpoints, t/100 + 1), t);
29 // fprintf(stderr, "# of data points = %d\n", wpoints);
30 
31  int taps_div = t - 1;
32  taps_div = std::max(taps_div / 10, 1);
33  shared_ptr<Context> context(new Context);
34  context->a.resize(t);
35  std::fill(context->a.begin(), context->a.end(), std::complex<double>(0.0));
36  context->a[0] = 1.0;
37  context->t = t;
38  context->sigma2 = 0.0;
39  for(unsigned int i = 0; i < t; i++) {
40  context->sigma2 += std::norm(memin[i]) / (double)t;
41  }
42  context->p = 0;
43  first(memin, context);
44  unsigned int taps = 0;
45  double ic = 1e99;
46  for(unsigned int p = 0; p < t - 2; p++) {
47  if(p % taps_div == 0) {
48  m_contexts.push_back(std::make_shared<Context>(*context));
49  if(taps + taps_div/2 < p)
50  break;
51  }
52  step(context);
53  context->p++;
54  if(context->sigma2 < 0)
55  break;
56  double new_ic = arIC(context->sigma2, context->p, wpoints);
57  if(new_ic < ic) {
58  taps = p + 1;
59  ic = new_ic;
60  }
61  }
62  taps = std::min((int)lrint(windowlength * taps), (int)t - 2);
63  int cidx = std::min((int)taps / taps_div, (int)m_contexts.size() - 1);
64  context = m_contexts[cidx];
65  m_contexts.clear();
66  for(unsigned int p = cidx * taps_div; p < taps; p++) {
67  assert(context->p == p);
68  step(context);
69  context->p++;
70  }
71  dbgPrint(formatString("MEM/AR: t=%d, taps=%d, IC_min=%g, IC=%g\n", t, taps, ic, m_funcARIC(context->sigma2, context->p, t)));
72 
73  std::vector<std::complex<double> > zfbuf(n), fftbuf(n);
74  std::fill(zfbuf.begin(), zfbuf.end(), std::complex<double>(0.0));
75  for(int i = 0; i < taps + 1; i++) {
76  zfbuf[i] = context->a[i];
77  }
78  m_fftN->exec(zfbuf, fftbuf);
79 
80  //Power spectrum density.
81  std::vector<double> psd(n);
82  for(int i = 0; i < n; i++) {
83  double z = t * context->sigma2 / (std::norm(fftbuf[i]));
84  psd[i] = std::max(z, 0.0);
85  }
86  //Least-Square Phase Estimation.
87  double coeff = lspe(memin, t0, psd, memout, tol, true, windowfunc);
88 
89  // Derivative of denominator.
90  std::fill(zfbuf.begin(), zfbuf.end(), std::complex<double>(0.0));
91  for(int i = 0; i < taps + 1; i++) {
92  zfbuf[i] = context->a[i] * (double)((i >= n/2) ? (i - n) : i) * std::complex<double>(0, -1);
93  }
94  std::vector<std::complex<double> > fftbuf2(n);
95  m_fftN->exec(zfbuf, fftbuf2);
96  //Peak detection. Sub-resolution detection for smooth curves.
97  double dy_old = std::real(fftbuf2[0] * std::conj(fftbuf[0]));
98  for(int ip = 0; ip < n; ip++) {
99  int in = (ip + 1) % n;
100  double dy = std::real(fftbuf2[in] * std::conj(fftbuf[in]));
101  if((dy_old < 0) && (dy > 0)) {
102  double dx = - dy_old / (dy - dy_old);
103  if((dx >= 0) && (dx <= 1.0)) {
104  std::complex<double> z = 0.0, xn = 1.0,
105  x = std::polar(1.0, -2 * M_PI * (dx + ip) / (double)n);
106  for(int i = 0; i < taps + 1; i++) {
107  z += context->a[i] * xn;
108  xn *= x;
109  }
110  double r = coeff * sqrt(std::max(t * context->sigma2 / std::norm(z), 0.0));
111  m_peaks.push_back(std::pair<double, double>(r, dx + ip));
112  }
113  }
114  dy_old = dy;
115  }
116 }
117 
118 template class YuleWalkerCousin<ARContext>;
119 template class YuleWalkerCousin<MEMBurgContext>;
120 
121 void
122 MEMBurg::first(
123  const std::vector<std::complex<double> >& memin, const shared_ptr<MEMBurgContext> &context) {
124  unsigned int t = context->t;
125  context->epsilon.resize(t);
126  context->eta.resize(t);
127  std::copy(memin.begin(), memin.end(), context->epsilon.begin());
128  std::copy(memin.begin(), memin.end(), context->eta.begin());
129 }
130 void
131 MEMBurg::step(const shared_ptr<MEMBurgContext> &context) {
132  unsigned int t = context->t;
133  unsigned int p = context->p;
134  std::complex<double> x = 0.0, y = 0.0;
135  for(unsigned int i = p + 1; i < t; i++) {
136  x += context->epsilon[i] * std::conj(context->eta[i-1]);
137  y += std::norm(context->epsilon[i]) + std::norm(context->eta[i-1]);
138  }
139  std::complex<double> alpha = x / y;
140  alpha *= -2;
141  for(unsigned int i = t - 1; i >= p + 1; i--) {
142  context->eta[i] = context->eta[i-1] + std::conj(alpha) * context->epsilon[i];
143  context->epsilon[i] += alpha * context->eta[i-1];
144  }
145  std::vector<std::complex<double> > a_next(p + 2);
146  for(unsigned int i = 0; i < p + 2; i++) {
147  a_next[i] = context->a[i] + alpha * std::conj(context->a[p + 1 - i]);
148  }
149  std::copy(a_next.begin(), a_next.end(), context->a.begin());
150  context->sigma2 *= 1 - std::norm(alpha);
151 }
152 void
153 YuleWalkerAR::first(
154  const std::vector<std::complex<double> >& memin, const shared_ptr<ARContext> &context) {
155  unsigned int t = context->t;
156  m_rx.resize(t);
157  autoCorrelation(memin, m_rx);
158 }
159 void
160 YuleWalkerAR::step(const shared_ptr<ARContext> &context) {
161  unsigned int p = context->p;
162  std::complex<double> delta = 0.0;
163  for(unsigned int i = 0; i < p + 1; i++) {
164  delta += context->a[i] * m_rx[p + 1 - i];
165  }
166  std::vector<std::complex<double> > a_next(p + 2);
167  for(unsigned int i = 0; i < p + 2; i++) {
168  a_next[i] = context->a[i] - delta/context->sigma2 * std::conj(context->a[p + 1 - i]);
169  }
170  std::copy(a_next.begin(), a_next.end(), context->a.begin());
171  context->sigma2 += - std::norm(delta) / context->sigma2;
172 }
173 

Generated for KAME4 by  doxygen 1.8.3