Automatic Differentiation
 
Loading...
Searching...
No Matches
autocorrelation.hpp
Go to the documentation of this file.
1#ifndef STAN_MATH_PRIM_FUN_AUTOCORRELATION_HPP
2#define STAN_MATH_PRIM_FUN_AUTOCORRELATION_HPP
3
6#include <unsupported/Eigen/FFT>
7#include <complex>
8#include <vector>
9
10namespace stan {
11namespace math {
12namespace internal {
13
18inline size_t fft_next_good_size(size_t N) {
19 if (N <= 2) {
20 return 2;
21 }
22 while (true) {
23 size_t m = N;
24 while ((m % 2) == 0) {
25 m /= 2;
26 }
27 while ((m % 3) == 0) {
28 m /= 3;
29 }
30 while ((m % 5) == 0) {
31 m /= 5;
32 }
33 if (m <= 1) {
34 return N;
35 }
36 N++;
37 }
38}
39} // namespace internal
40
61template <typename T>
62void autocorrelation(const std::vector<T>& y, std::vector<T>& ac,
63 Eigen::FFT<T>& fft) {
64 using std::complex;
65 using std::vector;
66
67 size_t N = y.size();
68 size_t M = internal::fft_next_good_size(N);
69 size_t Mt2 = 2 * M;
70
71 vector<complex<T> > freqvec;
72
73 // centered_signal = y-mean(y) followed by N zeroes
74 vector<T> centered_signal(y);
75 centered_signal.insert(centered_signal.end(), Mt2 - N, 0.0);
77 for (size_t i = 0; i < N; i++) {
78 centered_signal[i] -= mean;
79 }
80
81 fft.fwd(freqvec, centered_signal);
82 for (size_t i = 0; i < Mt2; ++i) {
83 freqvec[i] = complex<T>(norm(freqvec[i]), 0.0);
84 }
85
86 fft.inv(ac, freqvec);
87 ac.resize(N);
88
89 for (size_t i = 0; i < N; ++i) {
90 ac[i] /= (N - i);
91 }
92 T var = ac[0];
93 for (size_t i = 0; i < N; ++i) {
94 ac[i] /= var;
95 }
96}
97
118template <typename T, typename DerivedA, typename DerivedB>
119void autocorrelation(const Eigen::MatrixBase<DerivedA>& y,
120 Eigen::MatrixBase<DerivedB>& ac, Eigen::FFT<T>& fft) {
121 size_t N = y.size();
122 size_t M = internal::fft_next_good_size(N);
123 size_t Mt2 = 2 * M;
124
125 // centered_signal = y-mean(y) followed by N zeros
126 Eigen::Matrix<T, Eigen::Dynamic, 1> centered_signal(Mt2);
127 centered_signal.setZero();
128 centered_signal.head(N) = y.array() - y.mean();
129
130 Eigen::Matrix<std::complex<T>, Eigen::Dynamic, 1> freqvec(Mt2);
131 fft.SetFlag(fft.HalfSpectrum);
132 fft.fwd(freqvec, centered_signal);
133 // cwiseAbs2 == norm
134 freqvec = freqvec.cwiseAbs2();
135
136 Eigen::Matrix<T, Eigen::Dynamic, 1> ac_tmp(Mt2);
137 fft.inv(ac_tmp, freqvec);
138 fft.ClearFlag(fft.HalfSpectrum);
139
140 for (size_t i = 0; i < N; ++i) {
141 ac_tmp(i) /= (N - i);
142 }
143
144 ac = ac_tmp.head(N).array() / ac_tmp(0);
145}
146
163template <typename T>
164void autocorrelation(const std::vector<T>& y, std::vector<T>& ac) {
165 Eigen::FFT<T> fft;
166 size_t N = y.size();
167 ac.resize(N);
168
169 const Eigen::Map<const Eigen::Matrix<T, Eigen::Dynamic, 1> > y_map(&y[0], N);
170 Eigen::Map<Eigen::Matrix<T, Eigen::Dynamic, 1> > ac_map(&ac[0], N);
171 autocorrelation<T>(y_map, ac_map, fft);
172}
173
190template <typename T, typename DerivedA, typename DerivedB>
191void autocorrelation(const Eigen::MatrixBase<DerivedA>& y,
192 Eigen::MatrixBase<DerivedB>& ac) {
193 Eigen::FFT<T> fft;
194 autocorrelation(y, ac, fft);
195}
196
197} // namespace math
198} // namespace stan
199
200#endif
size_t fft_next_good_size(size_t N)
Find the optimal next size for the FFT so that a minimum number of zeros are padded.
scalar_type_t< T > mean(const T &m)
Returns the sample mean (i.e., average) of the coefficients in the specified std vector,...
Definition mean.hpp:20
fvar< T > norm(const std::complex< fvar< T > > &z)
Return the squared magnitude of the complex argument.
Definition norm.hpp:20
Eigen::Matrix< scalar_type_t< V >, -1, 1 > fft(const V &x)
Return the discrete Fourier transform of the specified complex vector.
Definition fft.hpp:35
var_value< double > var
Definition var.hpp:1187
void autocorrelation(const std::vector< T > &y, std::vector< T > &ac, Eigen::FFT< T > &fft)
Write autocorrelation estimates for every lag for the specified input sequence into the specified res...
The lgamma implementation in stan-math is based on either the reentrant safe lgamma_r implementation ...