mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
clAOLinearPredictor.hpp
Go to the documentation of this file.
1/** \file clAOLinearPredictor.hpp
2 * \author Jared R. Males (jaredmales@gmail.com)
3 * \brief Provides a class to manage closed loop gain linear predictor determination.
4 * \ingroup mxAO_files
5 *
6 */
7
8#ifndef clAOLinearPredictor_hpp
9#define clAOLinearPredictor_hpp
10
11#include <vector>
12
13#include "../../math/geo.hpp"
14
15#include "../../sigproc/psdUtils.hpp"
16
17#include "../../sigproc/autocorrelation.hpp"
18#include "../../sigproc/linearPredictor.hpp"
19
20#include "clGainOpt.hpp"
21
22namespace mx
23{
24namespace AO
25{
26namespace analysis
27{
28
29#define CLAOLP_BREADCRUMB
30
31//#define CLAOLP_BREADCRUMB std::cerr << __FILE__ << ' ' << __LINE__ << '\n';
32
33
34/// Class to manage the calculation of linear predictor coefficients for a closed-loop AO system.
35/**
36 * \tparam _realT the real floating point type in which to do all arithmetic.
37 *
38 * \ingroup mxAOAnalytic
39 */
40template <typename _realT>
42{
43 typedef _realT realT;
44
45public:
46
47 struct regResult
48 {
49 realT sc;
50 realT gopt;
51 realT gmax;
52 realT var;
53 };
54
55 std::vector<realT> m_PSDtn; ///< Working memory for the regularized PSD
56
57 std::vector<realT> m_psd2s; ///< Working memory for the 2-sided regularized PSD
58
59 std::vector<realT> m_ac; ///< Working memory to hold the autocorrelation.
60
62
64
65 realT m_min_var0{ 0 };
66 realT m_min_sc0{ 10 };
67 realT m_precision0{ 2 };
68 realT m_max_sc0{ 100 };
69 realT m_dPrecision{ 3 };
70
71 realT m_gmax_lp{ 5 }; ///< The maximum allowable gain for LP.
72
73 // Stopping conditions:
74 realT m_minPrecision{ 0.001 };
75 int m_maxIts{ 100 };
76
77 int m_extrap {1}; ///< The LP extrapolation length in loop steps. Normally it is 1 step.
78
79 std::vector<regResult> m_regResults;
80public:
81
83 {}
84
85 /// Calculate the LP coefficients for a turbulence PSD and a noise PSD.
86 /** This combines the two PSDs, augments to two-sided, and calls the linearPredictor.calcCoefficients method.
87 *
88 * A regularization constant can be added to the PSD as well.
89 *
90 */
91 int calcCoefficients( std::vector<realT> &PSDt, ///< [in] the turbulence PSD
92 std::vector<realT> &PSDn, ///< [in] the WFS noise PSD
93 realT PSDreg, ///< [in] the regularizing constant. Set to 0 to not use.
94 int Nc, ///< [in] the number of LP coefficients.
95 realT condition = 0 /**< [in] the condition number for the SVD. If 0 then
96 levinson recursion is used. */
97 )
98 {
99 CLAOLP_BREADCRUMB;
100 m_PSDtn.resize( PSDt.size() );
101
102 CLAOLP_BREADCRUMB;
103 for( size_t i = 0; i < PSDt.size(); ++i )
104 {
105 m_PSDtn[i] = PSDt[i] + PSDn[i] + PSDreg;
106 }
107
108 CLAOLP_BREADCRUMB;
110
111 CLAOLP_BREADCRUMB;
112 m_ac.resize( m_psd2s.size() );
113
114 CLAOLP_BREADCRUMB;
115 m_acpsd( m_ac, m_psd2s );
116 CLAOLP_BREADCRUMB;
117
118 return m_lp.calcCoefficients( m_ac, Nc, m_extrap , condition );
119
120 }
121
122 /// Worker function for regularizing the PSD for coefficient calculation.
123 /**
124 * \tparam telem if true then the results are collected in m_regResults.
125 *
126 * On first call (min_var = 0):
127 * loop over scale factors from min_sc to max_sc (<=) in steps of precision.
128 *
129 * On subsequent calls, when min_var and min_sc are passed back in
130 * loop over scale factors from min_sc-precision to max_sc in steps of
131 */
132 template <bool telem>
133 int _regularizeCoefficients( realT &min_var, ///< [in.out] the minimum variance found. Set to 0 on initial call
134 realT &min_sc, ///< [in.out] the scale factor at the minimum variance.
135 realT precision, ///< [in] the step-size for the scale factor
136 realT max_sc, ///< [in] the maximum scale factor to test
137 clGainOpt<realT> &go_lp, ///< [in] the gain optimization object
138 std::vector<realT> &PSDt, ///< [in] the turbulence PSD
139 std::vector<realT> &PSDn, ///< [in] the WFS noise PSD
140 int Nc ///< [in] the number of coefficients
141 )
142 {
143 CLAOLP_BREADCRUMB;
144
145 realT gmax_lp;
146 realT gopt_lp;
147 realT var_lp;
148
149 realT sc0;
150
151 if( min_var == 0 ) //first call
152 {
153 sc0 = min_sc;
154 min_var = std::numeric_limits<realT>::max();
155 }
156 else
157 {
158 sc0 = min_sc - precision * m_dPrecision;
159 }
160
161 CLAOLP_BREADCRUMB;
162
163 // auto it = std::max_element(std::begin(PSDt), std::end(PSDt));
164 realT psdReg = PSDt[0]; //*it/10;
165
166 CLAOLP_BREADCRUMB;
167 // Test from sc0 to max_sc in steps of precision
168 //for( realT sc = sc0; sc <= max_sc; sc += precision )
169 for( realT sc = max_sc; sc >= sc0; sc -= precision )
170 {
171 CLAOLP_BREADCRUMB;
172 int rv = calcCoefficients( PSDt, PSDn, psdReg * pow( 10, -sc / 10 ), Nc );
173 if( rv < 0 )
174 {
175 return rv;
176 }
177
178 CLAOLP_BREADCRUMB;
179
180 CLAOLP_BREADCRUMB;
181 go_lp.a( m_lp.m_c );
182 go_lp.b( m_lp.m_c );
183
184 CLAOLP_BREADCRUMB;
185 realT ll = 0, ul = 0;
186 gmax_lp = go_lp.maxStableGain( ll, ul );
187 if( gmax_lp > m_gmax_lp )
188 {
189 gmax_lp = m_gmax_lp;
190 }
191
192 CLAOLP_BREADCRUMB;
193 gopt_lp = go_lp.optGainOpenLoop( var_lp, PSDt, PSDn, gmax_lp, false );
194
195 if( telem )
196 {
197 m_regResults.push_back({sc, gopt_lp, gmax_lp, var_lp});
198 }
199
200 CLAOLP_BREADCRUMB;
201 if( var_lp < min_var )
202 {
203 min_var = var_lp;
204 min_sc = sc;
205 }
206
207 // A jump by a factor of 10 indicates the wall
208 if( var_lp > 10 * min_var )
209 {
210 return 0;
211 }
212
213 CLAOLP_BREADCRUMB;
214 }
215
216 CLAOLP_BREADCRUMB;
217 return 0;
218 }
219
220 /// Regularize the PSD and calculate the associated LP coefficients.
221 /** The PSD is regularized by adding a constant to it. This constant is found by minimizing the variance of the
222 * residual PSD.
223 *
224 * \tparam telem if true then the results are collected in m_regResults
225 */
226 template <bool telem = false>
227 int regularizeCoefficients( realT &gmax_lp, ///< [out] the maximum gain calculated for the regularized PSD
228 realT &gopt_lp, ///< [out] the optimum gain calculated for the regularized PSD
229 realT &var_lp, ///< [out] the variance at the optimum gain.
230 realT &min_sc, ///< [out] the optimum regularization scale factor
231 clGainOpt<realT> &go_lp, ///< [in] the gain optimization object
232 std::vector<realT> &PSDt, ///< [in] the turbulence PSD
233 std::vector<realT> &PSDn, ///< [in] the WFS noise PSD
234 int Nc ///< [in] the number of coefficients
235 )
236 {
237
238 CLAOLP_BREADCRUMB;
239
240 realT min_var = m_min_var0;
241 min_sc = m_min_sc0;
242 realT precision = m_precision0;
243 realT max_sc = m_max_sc0;
244
245 if(telem)
246 {
247 m_regResults.reserve(m_maxIts * 50);
248 }
249
250 CLAOLP_BREADCRUMB;
251 int its = 0;
252 while( precision > m_minPrecision && its < m_maxIts )
253 {
254 CLAOLP_BREADCRUMB;
255 int rv = _regularizeCoefficients<telem>( min_var, min_sc, precision, max_sc, go_lp, PSDt, PSDn, Nc );
256 if( rv < 0)
257 {
258 return rv;
259 }
260
261 CLAOLP_BREADCRUMB;
262 if( min_sc == max_sc )
263 {
264 if( its == 0 )
265 {
266 min_sc -= precision;
267 max_sc = 200;
268 }
269 else
270 {
271 // std::cerr << "Error in regularizeCoefficients.\n";
272 // return -1;
273 break;
274 }
275 }
276 else
277 {
278 max_sc = min_sc + precision;
279 precision /= m_dPrecision;
280 }
281
282 ++its;
283 }
284
285 CLAOLP_BREADCRUMB;
286 // Now record final values
287 int rv = calcCoefficients( PSDt, PSDn, PSDt[0] * pow( 10, -min_sc / 10 ), Nc );
288 if( rv < 0 )
289 {
290 return rv;
291 }
292
293 CLAOLP_BREADCRUMB;
294 go_lp.a( m_lp.m_c );
295 go_lp.b( m_lp.m_c );
296
297 CLAOLP_BREADCRUMB;
298 realT ll = 0, ul = 0;
299 gmax_lp = go_lp.maxStableGain( ll, ul );
300 gopt_lp = go_lp.optGainOpenLoop( var_lp, PSDt, PSDn, gmax_lp, false );
301
302 CLAOLP_BREADCRUMB;
303 return 0;
304 }
305
306 /// Regularize the PSD and calculate the associated LP coefficients.
307 /** The PSD is regularized by adding a constant to it. This constant is found by minimizing the variance of the
308 * residual PSD.
309 *
310 * \tparam printout if true then the results are printed to stdout as they are calculated.
311 */
312 template <bool printout = false>
313 int optimizeNc( realT &gmax_lp, ///< [out] the maximum gain calculated for the regularized PSD
314 realT &gopt_lp, ///< [out] the optimum gain calculated for the regularized PSD
315 int &Nc,
316 realT &var_lp, ///< [out] the variance at the optimum gain.
317 clGainOpt<realT> &go_lp, ///< [in] the gain optimization object
318 std::vector<realT> &PSDt, ///< [in] the turbulence PSD
319 std::vector<realT> &PSDn, ///< [in] the WFS noise PSD
320 int minNc, ///< [in] the number of coefficients
321 int maxNc )
322 {
323 realT minVar = std::numeric_limits<realT>::max();
324
325 for( int n = minNc; n <= maxNc; ++n )
326 {
327 realT _gmax_lp;
328 realT _gopt_lp;
329 realT _var_lp;
330 regularizeCoefficients<printout>( _gmax_lp, _gopt_lp, _var_lp, go_lp, PSDt, PSDn, n );
331
332 if( _var_lp < minVar )
333 {
334 gmax_lp = _gmax_lp;
335 gopt_lp = _gopt_lp;
336 var_lp = _var_lp;
337 Nc = n;
338
339 minVar = var_lp;
340 }
341 }
342
343 return 0;
344 }
345};
346
347} // namespace analysis
348} // namespace AO
349} // namespace mx
350
351#endif // clAOLinearPredictor_hpp
Provides a class to manage closed loop gain optimization.
void augment1SidedPSD(vectorTout &psdTwoSided, vectorTin &psdOneSided, bool addZeroFreq=false, typename vectorTin::value_type scale=0.5)
Augment a 1-sided PSD to standard 2-sided FFT form.
Definition psdUtils.hpp:817
#define gmax(A, B)
max(A,B) - larger (most +ve) of two numbers (generic) (defined in the SOFA library sofam....
The mxlib c++ namespace.
Definition mxError.hpp:40
Class to manage the calculation of linear predictor coefficients for a closed-loop AO system.
realT m_gmax_lp
The maximum allowable gain for LP.
int calcCoefficients(std::vector< realT > &PSDt, std::vector< realT > &PSDn, realT PSDreg, int Nc, realT condition=0)
Calculate the LP coefficients for a turbulence PSD and a noise PSD.
int _regularizeCoefficients(realT &min_var, realT &min_sc, realT precision, realT max_sc, clGainOpt< realT > &go_lp, std::vector< realT > &PSDt, std::vector< realT > &PSDn, int Nc)
Worker function for regularizing the PSD for coefficient calculation.
std::vector< realT > m_psd2s
Working memory for the 2-sided regularized PSD.
std::vector< realT > m_PSDtn
Working memory for the regularized PSD.
std::vector< realT > m_ac
Working memory to hold the autocorrelation.
int regularizeCoefficients(realT &gmax_lp, realT &gopt_lp, realT &var_lp, realT &min_sc, clGainOpt< realT > &go_lp, std::vector< realT > &PSDt, std::vector< realT > &PSDn, int Nc)
Regularize the PSD and calculate the associated LP coefficients.
int optimizeNc(realT &gmax_lp, realT &gopt_lp, int &Nc, realT &var_lp, clGainOpt< realT > &go_lp, std::vector< realT > &PSDt, std::vector< realT > &PSDn, int minNc, int maxNc)
Regularize the PSD and calculate the associated LP coefficients.
int m_extrap
The LP extrapolation length in loop steps. Normally it is 1 step.
A class to manage optimizing closed-loop gains.
Definition clGainOpt.hpp:64
void a(const std::vector< realT > &newA)
Set the vector of IIR coefficients.
void b(const std::vector< realT > &newB)
Set the vector of FIR coefficients.
realT optGainOpenLoop(realT &var, const std::vector< realT > &PSDerr, const std::vector< realT > &PSDnoise, bool gridSearch)
Return the optimum closed loop gain given an open loop PSD.
realT maxStableGain(realT &ll, realT &ul)
Find the maximum stable gain for the loop parameters.
Functor for calculating the autocorrelation given a PSD.
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.