mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
arpsd.hpp
Go to the documentation of this file.
1/** \file arpsd.hpp
2 * \brief Tools for working with autogressive PSDs
3 *
4 * \author Jared R. Males (jaredmales@gmail.com)
5 *
6 * \ingroup signal_processing_files
7 *
8 */
9
10//***********************************************************************//
11// Copyright 2023 Jared R. Males (jaredmales@gmail.com)
12//
13// This file is part of mxlib.
14//
15// mxlib is free software: you can redistribute it and/or modify
16// it under the terms of the GNU General Public License as published by
17// the Free Software Foundation, either version 3 of the License, or
18// (at your option) any later version.
19//
20// mxlib is distributed in the hope that it will be useful,
21// but WITHOUT ANY WARRANTY; without even the implied warranty of
22// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23// GNU General Public License for more details.
24//
25// You should have received a copy of the GNU General Public License
26// along with mxlib. If not, see <http://www.gnu.org/licenses/>.
27//***********************************************************************//
28
29#ifndef arpsd_hpp
30#define arpsd_hpp
31
32#include <vector>
33#include <complex>
34
35#include <mx/math/constants.hpp>
36
37namespace mx
38{
39namespace sigproc
40{
41
42/// Get the phase of a given frequency
43/**
44 * \returns \f$ 2\pi \frac{f}{f_s} \f$
45 *
46 * \ingroup arpsds
47 */
48template <typename realT>
49realT ar1FreqPhase( realT f, ///< [in] the desired frequency, usually Hz
50 realT fsamp ///< [in] the samplingfrequency, same units as \p freq
51)
52{
53 return math::two_pi<realT>() * f / fsamp;
54}
55
56/// Calculate the norm of an AR1 PSD
57/** For the PSD of the form
58 * \f[
59 * P(f) = \frac{\beta}{ \left| 1 - \alpha e ^{-i 2\pi f/f_s}\right|^2 }
60 * \f]
61 * where \f$ f_s \f$ is the sampling frequency and \f$ \alpha \f$ is complex with
62 * the pole frequency set by
63 * \f[
64 * f_p = \arg(\alpha)\frac{f_s}{2\pi}
65 * \f]
66 * this returns the one-sided norm
67 * \f[
68 \int_0^{f_s/2} P(f) df
69 * \f]
70 *
71 * Uses 2.553 \#3 of Gradshteyn (2007) \cite gradshteyn_2007
72 *
73 * \ingroup arpsds
74 */
75template <typename realT>
76realT ar1PSDNorm( realT beta, ///< the normalization parameter
77 realT alpha, ///< the magnitude of the AR1 constant
78 realT fpole, ///< the pole frequency, which sets the phase of complex \f$\alpha\f$
79 realT fsamp ///< the sampling frequency
80)
81{
82 realT a = 1 + pow( alpha, 2 );
83 realT b = -2 * alpha;
84
85 realT sqab = sqrt( a * a - b * b );
86
87 realT wf = math::two_pi<realT>() * ( fsamp / 2.0 - fpole ) / fsamp;
88 realT w0 = math::two_pi<realT>() * ( 0.0 - fpole ) / fsamp;
89
90 return ( beta * fsamp / math::two_pi<realT>() ) * 2 / sqab *
91 ( atan( ( ( a - b ) * tan( wf / 2 ) / sqab ) ) - atan( ( ( a - b ) * tan( w0 / 2 ) ) / sqab ) );
92}
93
94/// Generate an AR1 PSD
95/** Fills in the the PSD of the form
96 * \f[
97 * P(f) = \frac{\beta}{ \left| 1 - \alpha e ^{-i 2\pi f/f_s}\right|^2 }
98 * \f]
99 * where \f$ f_s \f$ is the sampling frequency and the AR1 constant \f$ \alpha \f$ is complex
100 * with phase set by the pole frequency
101 * \f[
102 * \alpha = \left|\alpha\right|^2 e^{-i 2\pi f_p/ f_s}
103 * \f]
104 *
105 * \ingroup arpsds
106 */
107template <typename realT>
108void ar1PSD( std::vector<realT> &psd, ///< [out] the PSD, will be resized and filled in with the values of the AR1 PSD
109 const std::vector<realT> &f, ///< [in] the frequency scale. 2*f.back() is the sampling frequency.
110 realT beta, ///< [in] the normalization parameter
111 realT alpha, ///< [in] magnitude of the AR1 constant
112 realT fpole ///< [in] the pole frequency, which sets the phase of complex \f$ \alpha \f$.
113)
114{
115 psd.resize( f.size() );
116
117 realT fmax = 2 * f.back();
118
119 for( size_t n = 0; n < f.size(); ++n )
120 {
121 realT denom = 1 + alpha * alpha - 2 * alpha * cos( math::two_pi<realT>() * ( f[n] - fpole ) / fmax );
122
123 psd[n] = beta / denom;
124 }
125}
126
127/// Generate an AR1 PSD
128/** Fills in the the PSD of the form
129 * \f[
130 * P(f) = \frac{\beta}{ \left| 1 - \alpha e ^{-i 2\pi f/f_s}\right|^2 }
131 * \f]
132 * where \f$ f_s \f$ is the sampling frequency and the AR1 constant \f$ \alpha \f$.
133 *
134 * \overload
135 * \ingroup arpsds
136 */
137template <typename realT>
138void ar1PSD( std::vector<realT> &psd, ///< [out] the PSD, will be resized and filled in with the values of the AR1 PSD
139 const std::vector<realT> &f, ///< [in] the frequency scale. 2*f.back() is the sampling frequency.
140 realT beta, ///< [in] the normalization parameter
141 std::complex<realT> alpha ///< [in] the complex AR1 constant
142)
143{
144 realT fpole = atan2( alpha.imag(), alpha.real() ) * ( 2 * f.back() ) / math::two_pi<realT>();
145
146 return ar1PSD( psd, f, beta, abs( alpha ), fpole );
147}
148
149template <typename realT>
150void arNPSD( std::vector<realT> &psd,
151 const std::vector<realT> &f,
152 realT fmax,
153 realT var,
154 std::vector<realT> alphaMag,
155 std::vector<realT> alphaPhase )
156{
157 psd.resize( f.size() );
158
159 std::complex j = std::complex<realT>( 0, 1 );
160 std::vector<std::complex<realT>> alpha( alphaMag.size() );
161
162 for( size_t n = 0; n < alphaMag.size(); ++n )
163 {
164 alpha[n] = alphaMag[n] * exp( j * alphaPhase[n] );
165 }
166
167 for( size_t n = 0; n < f.size(); ++n )
168 {
169
170 std::complex<realT> denom = 1.0;
171
172 for( size_t m = 0; m < alpha.size(); ++m )
173 {
174 denom -= alpha[m] * exp( -j * math::two_pi<realT>() * f[n] * std::complex<realT>( ( m + 1 ), 0 ) / fmax );
175 }
176
177 psd[n] = var / std::norm( denom );
178 }
179}
180
181} // namespace sigproc
182} // namespace mx
183
184#endif // arpsd_hpp
realT ar1PSDNorm(realT beta, realT alpha, realT fpole, realT fsamp)
Calculate the norm of an AR1 PSD.
Definition arpsd.hpp:76
void ar1PSD(std::vector< realT > &psd, const std::vector< realT > &f, realT beta, realT alpha, realT fpole)
Generate an AR1 PSD.
Definition arpsd.hpp:108
realT ar1FreqPhase(realT f, realT fsamp)
Get the phase of a given frequency.
Definition arpsd.hpp:49
constexpr floatT six_fifths()
Return 6/5 in the specified precision.
The mxlib c++ namespace.
Definition mxError.hpp:106