v2.0.0
Loading...
Searching...
No Matches
dpss.cpp
Go to the documentation of this file.
1//=============================================================================================================
12
13//=============================================================================================================
14// INCLUDES
15//=============================================================================================================
16
17#include "dpss.h"
18
19//=============================================================================================================
20// EIGEN INCLUDES
21//=============================================================================================================
22
23#include <Eigen/Core>
24#include <Eigen/Eigenvalues>
25
26//=============================================================================================================
27// STD INCLUDES
28//=============================================================================================================
29
30#include <cmath>
31
32//=============================================================================================================
33// USED NAMESPACES
34//=============================================================================================================
35
36using namespace UTILSLIB;
37using namespace Eigen;
38
39namespace
40{
41constexpr double DPSS_PI = 3.14159265358979323846;
42}
43
44//=============================================================================================================
45// DEFINE MEMBER METHODS
46//=============================================================================================================
47
48DpssResult Dpss::compute(int N, double halfBandwidth, int nTapers)
49{
50 if (nTapers < 0)
51 nTapers = static_cast<int>(std::floor(2.0 * halfBandwidth - 1.0));
52
53 const double W = halfBandwidth / static_cast<double>(N);
54
55 // Build the symmetric tridiagonal matrix T
56 // Diagonal: d(i) = ((N-1-2*i)/2)^2 * cos(2*pi*W)
57 // Off-diagonal: e(i) = (i+1)*(N-i-1)/2
58 VectorXd diag(N);
59 VectorXd offdiag(N > 1 ? N - 1 : 0);
60
61 const double cosW = std::cos(2.0 * DPSS_PI * W);
62
63 for (int i = 0; i < N; ++i) {
64 const double val = (static_cast<double>(N - 1) - 2.0 * static_cast<double>(i)) / 2.0;
65 diag[i] = val * val * cosW;
66 }
67
68 for (int i = 0; i < N - 1; ++i) {
69 offdiag[i] = static_cast<double>(i + 1) * static_cast<double>(N - i - 1) / 2.0;
70 }
71
72 // Construct tridiagonal matrix and solve eigenvalue problem
73 MatrixXd T = MatrixXd::Zero(N, N);
74 for (int i = 0; i < N; ++i)
75 T(i, i) = diag[i];
76 for (int i = 0; i < N - 1; ++i) {
77 T(i, i + 1) = offdiag[i];
78 T(i + 1, i) = offdiag[i];
79 }
80
81 SelfAdjointEigenSolver<MatrixXd> solver(T);
82
83 // Eigenvalues are sorted ascending; the tapers are the eigenvectors of the largest nTapers
84 const MatrixXd& allEigenvectors = solver.eigenvectors();
85
86 DpssResult result;
87 result.matTapers.resize(nTapers, N);
88 result.vecEigenvalues.resize(nTapers);
89
90 // Concentration kernel r(m) = sin(2 pi W m) / (pi m), r(0) = 2W (Percival & Walden 1993, p. 390)
91 VectorXd kernel(N);
92 kernel[0] = 2.0 * W;
93 for (int m = 1; m < N; ++m)
94 kernel[m] = std::sin(2.0 * DPSS_PI * W * m) / (DPSS_PI * m);
95
96 for (int k = 0; k < nTapers; ++k) {
97 const int idx = N - 1 - k; // largest eigenvalue first
98
99 // Extract eigenvector as a row, normalize to unit L2 norm
100 VectorXd taper = allEigenvectors.col(idx);
101 const double norm = taper.norm();
102 if (norm > 0.0)
103 taper /= norm;
104
105 // Sign convention: first element should be positive
106 if (taper[0] < 0.0)
107 taper = -taper;
108
109 result.matTapers.row(k) = taper.transpose();
110
111 // Fraction of the taper's energy inside [-W, W]: sum over lags of autocorrelation x kernel
112 double ratio = kernel[0] * taper.squaredNorm();
113 for (int m = 1; m < N; ++m)
114 ratio += 2.0 * kernel[m] * taper.head(N - m).dot(taper.tail(N - m));
115 result.vecEigenvalues[k] = ratio;
116 }
117
118 return result;
119}
Discrete Prolate Spheroidal Sequences (Slepian tapers) for multitaper spectral estimation.
Shared utilities (I/O helpers, spectral analysis, layout management, warp algorithms).
Result of a DPSS taper computation.
Definition dpss.h:56
Eigen::MatrixXd matTapers
nTapers × N, each row is a unit-norm taper
Definition dpss.h:57
Eigen::VectorXd vecEigenvalues
Concentration ratios, length nTapers.
Definition dpss.h:58
static DpssResult compute(int N, double halfBandwidth, int nTapers=-1)
Definition dpss.cpp:48