mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
linearPredictor.hpp
Go to the documentation of this file.
1/** \file linearPredictor.hpp
2 * \brief Working with linear prediction.
3 *
4 * \author Jared R. Males (jaredmales@gmail.com)
5 *
6 * \ingroup signal_processing_files
7 *
8 */
9
10//***********************************************************************//
11// Copyright 2015, 2016, 2017 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 linearPredictor_hpp
30#define linearPredictor_hpp
31
32#include <vector>
33#include <complex>
34
35#include "../math/constants.hpp"
36#include "../math/eigenLapack.hpp"
37
38#include "levinsonRecursion.hpp"
39
40namespace mx
41{
42namespace sigproc
43{
44
45#define LP_BREADCRUMB
46
47//#define LP_BREADCRUMB std::cerr << __FILE__ << ' ' << __LINE__ << '\n';
48
49
50/// A class to support linear prediction.
51/** \ingroup signal_processing
52 *
53 * \todo document linearPredictor
54 */
55template <typename _realT>
57{
58 typedef _realT realT;
59
60 std::vector<realT> m_c;
61
62 realT _setCondition{ 0 };
63 realT _actCondition{ 0 };
64 int _nRejected{ 0 };
65
66 /// Calculate the LP coefficients given an autocorrelation.
67 /** If condition==0 then the levinson recursion is used.
68 * Otherwise, SVD pseudo-inversion is used with the given condition number.
69 */
70 int calcCoefficients( const std::vector<realT> &ac,
71 size_t Nc,
72 size_t Npred = 1,
73 realT condition = 0
74 )
75 {
76 return calcCoefficients( ac.data(), ac.size(), Nc, Npred, condition);
77 }
78
79 int calcCoefficients( const realT *ac,
80 size_t acSz,
81 size_t Nc,
82 size_t Npred = 1,
83 realT condition = 0
84 )
85 {
86
87 if( condition == 0 )
88 {
89 LP_BREADCRUMB;
90 return calcCoefficientsLevinson( ac, acSz, Nc, Npred );
91 }
92
93 Eigen::Array<realT, -1, -1> Rmat, Rvec, PInv, LPcoeff;
94
95 Rmat.resize( Nc, Nc );
96 Rvec.resize( 1, Nc );
97
98 for( int i = 0; i < Nc && i < acSz; ++i )
99 {
100 for( int j = 0; j < Nc && i < acSz; ++j )
101 {
102 Rmat( i, j ) = ac[abs( i - j )];
103 }
104
105 Rvec( 0, i ) = ac[i + Npred];
106 }
107
108 realT tmpCond = condition;
109
110 _setCondition = condition;
111 math::eigenPseudoInverse( PInv, tmpCond, _nRejected, Rmat, condition );
112
113 _actCondition = tmpCond;
114
115 m_c.resize(Nc);
116 Eigen::Map<Eigen::Array<realT,-1,-1>> cmap(m_c.data(), 1, m_c.size());
117 cmap = Rvec.matrix() * PInv.matrix();
118
119 return 0;
120 }
121
122 int calcCoefficientsLevinson( const std::vector<realT> &ac, /**< [in] The autocorrelation, at least
123 Nc+Npred in length */
124 size_t Nc, /**< [in] The number of LP coefficients desired */
125 size_t Npred = 1 /**< [in] [optional] The prediction length,
126 default is 1 */
127 )
128 {
129 LP_BREADCRUMB;
130
131 return calcCoefficientsLevinson( ac.data(), ac.size(), Nc, Npred );
132 }
133
134 int calcCoefficientsLevinson( const realT *ac, /**< [in] The autocorrelation, at least Nc+Npred in length */
135 size_t acSz, /**< [in] The length of the autocorrelation */
136 size_t Nc, /**< [in] The number of LP coefficients desired */
137 unsigned Npred = 1 /**< [in] [optional] The prediction length, default is 1 */
138 )
139 {
140 LP_BREADCRUMB;
141 if( acSz < Nc + Npred )
142 {
143 std::string msg = "too many coefficients for size and prediction length\n";
144 msg += " acSz = " + std::to_string( acSz ) + "\n";
145 msg += " Nc = " + std::to_string( Nc ) + "\n";
146 msg += " Npred = " + std::to_string( Npred ) + "\n";
147 mxThrowException( err::invalidarg, "linearPredictor::calcCoefficientsLevinson", msg );
148 }
149
150 if(Nc == 0)
151 {
152 std::string msg = "Nc can't be 0";
153 mxThrowException( err::invalidarg, "linearPredictor::calcCoefficientsLevinson", msg );
154 }
155
156 std::vector<realT> r, x, y;
157
158 LP_BREADCRUMB;
159 r.resize( 2. * Nc - 1 );
160 m_c.resize( Nc );
161 y.resize( Nc );
162
163 LP_BREADCRUMB;
164 for( size_t i = 0; i < Nc; ++i )
165 {
166 r[i] = ac[Nc - i - 1]; // this runs from Nc-1 to 0
167 }
168
169 LP_BREADCRUMB;
170 for( size_t i = Nc; i < 2 * Nc - 1; ++i )
171 {
172 r[i] = ac[i - Nc + 1]; // this runs from 1 to Nc-1
173 }
174
175 LP_BREADCRUMB;
176 for( size_t i = 0; i < Nc; ++i )
177 {
178 y[i] = ac[i + Npred]; // this runs from Npred to Nc-1 + Npred
179 }
180
181 LP_BREADCRUMB;
182 return levinsonRecursion( r.data(), m_c.data(), y.data(), Nc );
183 }
184
185 realT c( size_t i )
186 {
187 return m_c[i];
188 }
189
190 size_t Nc()
191 {
192 return m_c.size();
193 }
194
195 realT predict( std::vector<realT> &hist, int idx )
196 {
197 realT x = 0;
198
199 if( idx < m_c.size() )
200 {
201 return x;
202 }
203
204 for( int i = 0; i < m_c.size(); ++i )
205 {
206 x += m_c[i] * hist[idx - i];
207 }
208
209 return x;
210 }
211
212 realT spectralResponse( realT f, realT fs )
213 {
214 int n = m_c.size();
215
216 std::complex<realT> He = 0;
217 for( int j = 0; j < n; ++j )
218 {
219 realT s = ( j + 1.0 ) * math::two_pi<realT>();
220 He += m_c[j] * exp( s * std::complex<realT>( 0, -1.0 ) * f / fs );
221 }
222
223 realT one = 1.0;
224 return std::norm( one / ( one - He ) );
225 }
226};
227
228} // namespace sigproc
229} // namespace mx
230#endif // linearPredictor_hpp
mxException for invalid arguments
int eigenPseudoInverse(Eigen::Array< dataT, -1, -1 > &PInv, dataT &condition, int &nRejected, Eigen::Array< dataT, -1, -1 > &U, Eigen::Array< dataT, -1, -1 > &S, Eigen::Array< dataT, -1, -1 > &VT, int minMN, dataT &maxCondition, dataT alpha=0, int interact=MX_PINV_NO_INTERACT)
Calculate the pseudo-inverse of a patrix given its SVD.
#define mxThrowException(extype, src, expl)
Throw an exception. This macro takes care of the file and line.
constexpr floatT six_fifths()
Return 6/5 in the specified precision.
The mxlib c++ namespace.
Definition mxError.hpp:40
A class to support linear prediction.
int calcCoefficients(const std::vector< realT > &ac, size_t Nc, size_t Npred=1, realT condition=0)
Calculate the LP coefficients given an autocorrelation.
int calcCoefficientsLevinson(const realT *ac, size_t acSz, size_t Nc, unsigned Npred=1)
int calcCoefficientsLevinson(const std::vector< realT > &ac, size_t Nc, size_t Npred=1)