Line data Source code
1 : /** \file strehlEstimator.hpp
2 : * \brief The MagAO-X XXXXXX header file
3 : *
4 : * \ingroup strehlEstimator_files
5 : */
6 :
7 : #ifndef strehlEstimator_hpp
8 : #define strehlEstimator_hpp
9 :
10 : #include <mx/ao/analysis/aoSystem.hpp>
11 : using namespace mx::math;
12 :
13 : #include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
14 : #include "../../magaox_git_version.h"
15 :
16 : /** \defgroup strehlEstimator
17 : * \brief The XXXXXX application to do YYYYYYY
18 : *
19 : * <a href="../handbook/operating/software/apps/XXXXXX.html">Application Documentation</a>
20 : *
21 : * \ingroup apps
22 : *
23 : */
24 :
25 : /** \defgroup strehlEstimator_files
26 : * \ingroup strehlEstimator
27 : */
28 :
29 : namespace MagAOX
30 : {
31 : namespace app
32 : {
33 :
34 : struct wfsavgShmimT
35 : {
36 0 : static std::string configSection()
37 : {
38 0 : return "wfsavgShmim";
39 : };
40 :
41 0 : static std::string indiPrefix()
42 : {
43 0 : return "wfsavg";
44 : };
45 : };
46 :
47 : struct wfsmaskShmimT
48 : {
49 0 : static std::string configSection()
50 : {
51 0 : return "wfsmaskShmim";
52 : };
53 :
54 0 : static std::string indiPrefix()
55 : {
56 0 : return "wfsmask";
57 : };
58 : };
59 :
60 : /// The MagAO-X xxxxxxxx
61 : /**
62 : * \ingroup strehlEstimator
63 : */
64 : class strehlEstimator : public MagAOXApp<true>,
65 : dev::shmimMonitor<strehlEstimator, wfsavgShmimT>,
66 : dev::shmimMonitor<strehlEstimator, wfsmaskShmimT>
67 : {
68 :
69 : // Give the test harness access.
70 : friend class strehlEstimator_test;
71 :
72 : friend class dev::shmimMonitor<strehlEstimator, wfsavgShmimT>;
73 : friend class dev::shmimMonitor<strehlEstimator, wfsmaskShmimT>;
74 :
75 : public:
76 : typedef dev::shmimMonitor<strehlEstimator, wfsavgShmimT> wfsavgShmimMonitorT;
77 : typedef dev::shmimMonitor<strehlEstimator, wfsmaskShmimT> wfsmaskShmimMonitorT;
78 :
79 : protected:
80 : /** \name Configurable Parameters
81 : *@{
82 : */
83 :
84 : int m_loopNum{ 1 }; ///< The number of the loop. Used to set shmim names, as in aolN_wfsmask.
85 :
86 : std::string m_wfsDevice{ "camwfs" };
87 :
88 : std::string m_stagebsDevice{ "stagebs" };
89 :
90 : float m_again{ 28.547 };
91 :
92 : float m_qe{ 0.53 };
93 :
94 : float m_F0_6535{ 4.2e10 };
95 :
96 : float m_F0_HaIR{ 5.3e10 };
97 :
98 : float m_lam0_6535{ 0.791 };
99 :
100 : float m_lam0_HaIR{ 0.837 };
101 :
102 : float m_qe_6535{ 0.53 };
103 :
104 : float m_qe_HaIR{ 0.53 };
105 :
106 : ///@}
107 :
108 : float m_fps{ 2000 };
109 :
110 : float m_emg{ 1 };
111 :
112 : float m_F0{ m_F0_6535 };
113 :
114 : float m_lam0{ m_lam0_6535 };
115 :
116 : float m_seeing{ 0.64 };
117 :
118 : float m_r0{ 0.16 };
119 :
120 : float m_elevation{ 90 };
121 :
122 : int m_npix;
123 :
124 : float m_counts{ 0 };
125 :
126 : float m_mag{ 0 };
127 :
128 : mx::improc::eigenImage<float> m_wfsmask;
129 : mx::improc::eigenImage<float> m_wfsavg;
130 :
131 : mx::AO::analysis::aoSystem<float, mx::AO::analysis::vonKarmanSpectrum<float>> m_aosys;
132 :
133 : double m_dimm_fwhm_corr{ 0 }; ///< DIMM elevation corrected FWHM
134 : int m_dimm_time{ 0 }; ///< Seconds since midnight of DIMM measurement.
135 :
136 : double m_mag1_fwhm_corr{ 0 }; ///< MAG1 elevation corrected FWHM
137 : int m_mag1_time{ 0 }; ///< Seconds since midnight of MAG1 measurement.
138 :
139 : double m_mag2_fwhm_corr{ 0 }; ///< MAG2 elevation corrected FWHM
140 : int m_mag2_time{ 0 }; ///< Seconds since midnight of MAG2 measurement.
141 :
142 : public:
143 : /// Default c'tor.
144 : strehlEstimator();
145 :
146 : /// D'tor, declared and defined for noexcept.
147 0 : ~strehlEstimator() noexcept
148 0 : {
149 0 : }
150 :
151 : virtual void setupConfig();
152 :
153 : /// Implementation of loadConfig logic, separated for testing.
154 : /** This is called by loadConfig().
155 : */
156 : int loadConfigImpl(
157 : mx::app::appConfigurator &_config /**< [in] an application configuration from which to load values*/ );
158 :
159 : virtual void loadConfig();
160 :
161 : /// Startup function
162 : /**
163 : *
164 : */
165 : virtual int appStartup();
166 :
167 : /// Implementation of the FSM for strehlEstimator.
168 : /**
169 : * \returns 0 on no critical error
170 : * \returns -1 on an error requiring shutdown
171 : */
172 : virtual int appLogic();
173 :
174 : /// Shutdown the app.
175 : /**
176 : *
177 : */
178 : virtual int appShutdown();
179 :
180 : int allocate( const wfsavgShmimT & ///< [in] tag to differentiate shmimMonitor parents.
181 : );
182 :
183 : int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
184 : const wfsavgShmimT & ///< [in] tag to differentiate shmimMonitor parents.
185 : );
186 :
187 : int allocate( const wfsmaskShmimT & ///< [in] tag to differentiate shmimMonitor parents.
188 : );
189 :
190 : int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
191 : const wfsmaskShmimT & ///< [in] tag to differentiate shmimMonitor parents.
192 : );
193 :
194 : void calcMag();
195 :
196 : /** INDI
197 : * @{
198 : */
199 :
200 : pcf::IndiProperty m_indiP_fps;
201 : pcf::IndiProperty m_indiP_emg;
202 :
203 : pcf::IndiProperty m_indiP_stage;
204 :
205 : pcf::IndiProperty m_indiP_tcsi_seeing;
206 : pcf::IndiProperty m_indiP_tcsi_telpos;
207 : pcf::IndiProperty m_indiP_seeing_magaox;
208 :
209 : pcf::IndiProperty m_indiP_mag;
210 : pcf::IndiProperty m_indiP_strehl;
211 : pcf::IndiProperty m_indiP_wfe;
212 :
213 0 : INDI_SETCALLBACK_DECL( strehlEstimator, m_indiP_fps );
214 0 : INDI_SETCALLBACK_DECL( strehlEstimator, m_indiP_emg );
215 0 : INDI_SETCALLBACK_DECL( strehlEstimator, m_indiP_stage );
216 0 : INDI_SETCALLBACK_DECL( strehlEstimator, m_indiP_tcsi_seeing );
217 0 : INDI_SETCALLBACK_DECL( strehlEstimator, m_indiP_tcsi_telpos );
218 :
219 : ///@}
220 : };
221 :
222 0 : strehlEstimator::strehlEstimator() : MagAOXApp( MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED )
223 : {
224 :
225 0 : wfsavgShmimMonitorT::m_getExistingFirst = true;
226 0 : wfsmaskShmimMonitorT::m_getExistingFirst = true;
227 :
228 0 : return;
229 0 : }
230 :
231 0 : void strehlEstimator::setupConfig()
232 : {
233 0 : m_aosys.loadMagAOX();
234 :
235 0 : config.add( "loop.number",
236 : "",
237 : "loop.number",
238 : argType::Required,
239 : "loop",
240 : "number",
241 : false,
242 : "int",
243 : "The number of the loop. Used to set shmim names, as in aolN_mgainfact." );
244 :
245 0 : config.add( "phot.qe_6535",
246 : "",
247 : "phot.qe_6535",
248 : argType::Required,
249 : "phot",
250 : "qe_6535",
251 : false,
252 : "float",
253 : "The WFS QE in the 65-35 B/S." );
254 :
255 0 : config.add( "phot.qe_HaIR",
256 : "",
257 : "phot.qe_HaIR",
258 : argType::Required,
259 : "phot",
260 : "qe_HaIR",
261 : false,
262 : "float",
263 : "The WFS QE in the Ha-IR B/S." );
264 :
265 0 : SHMIMMONITORT_SETUP_CONFIG( wfsavgShmimMonitorT, config );
266 0 : SHMIMMONITORT_SETUP_CONFIG( wfsmaskShmimMonitorT, config );
267 : }
268 :
269 0 : int strehlEstimator::loadConfigImpl( mx::app::appConfigurator &_config )
270 : {
271 :
272 0 : _config( m_loopNum, "loop.number" );
273 :
274 0 : _config( m_qe_6535, "phot.qe_6535" );
275 0 : _config( m_qe_HaIR, "phot.qe_HaIR" );
276 :
277 : char shmim[1024];
278 0 : snprintf( shmim, sizeof( shmim ), "aol%d_wfsavg", m_loopNum );
279 0 : wfsavgShmimMonitorT::m_shmimName = shmim;
280 0 : SHMIMMONITORT_LOAD_CONFIG( wfsavgShmimMonitorT, _config );
281 :
282 0 : snprintf( shmim, sizeof( shmim ), "aol%d_wfsmask", m_loopNum );
283 0 : wfsmaskShmimMonitorT::m_shmimName = shmim;
284 0 : SHMIMMONITORT_LOAD_CONFIG( wfsmaskShmimMonitorT, _config );
285 :
286 0 : return 0;
287 : }
288 :
289 0 : void strehlEstimator::loadConfig()
290 : {
291 0 : loadConfigImpl( config );
292 0 : }
293 :
294 0 : int strehlEstimator::appStartup()
295 : {
296 :
297 0 : SHMIMMONITORT_APP_STARTUP( wfsavgShmimMonitorT );
298 0 : SHMIMMONITORT_APP_STARTUP( wfsmaskShmimMonitorT );
299 :
300 0 : REG_INDI_SETPROP( m_indiP_fps, m_wfsDevice, "fps" );
301 :
302 0 : REG_INDI_SETPROP( m_indiP_emg, m_wfsDevice, "emgain" );
303 :
304 0 : REG_INDI_SETPROP( m_indiP_stage, m_stagebsDevice, "presetName" );
305 :
306 0 : REG_INDI_SETPROP( m_indiP_tcsi_seeing, "tcsi", "seeing" );
307 0 : REG_INDI_SETPROP( m_indiP_tcsi_telpos, "tcsi", "telpos" );
308 :
309 0 : CREATE_REG_INDI_RO_NUMBER( m_indiP_mag, "star_mag", "Star Magnitude", "Error Budget" );
310 0 : m_indiP_mag.add( pcf::IndiElement( "current", 0 ) );
311 :
312 0 : CREATE_REG_INDI_RO_NUMBER( m_indiP_strehl, "strehl_optimal", "Strehl", "Error Budget" );
313 0 : m_indiP_strehl.add( pcf::IndiElement( "pyramid", 0 ) );
314 :
315 0 : CREATE_REG_INDI_RO_NUMBER( m_indiP_wfe, "wfe_predicted", "WFE", "Error Budget" );
316 0 : m_indiP_wfe.add( pcf::IndiElement( "total", 0 ) );
317 0 : m_indiP_wfe.add( pcf::IndiElement( "measurement", 0 ) );
318 0 : m_indiP_wfe.add( pcf::IndiElement( "time_delay", 0 ) );
319 0 : m_indiP_wfe.add( pcf::IndiElement( "fitting", 0 ) );
320 :
321 0 : state( stateCodes::OPERATING );
322 :
323 0 : return 0;
324 : }
325 :
326 0 : int strehlEstimator::appLogic()
327 : {
328 0 : SHMIMMONITORT_APP_LOGIC( wfsavgShmimMonitorT );
329 0 : SHMIMMONITORT_APP_LOGIC( wfsmaskShmimMonitorT );
330 :
331 0 : SHMIMMONITORT_UPDATE_INDI( wfsavgShmimMonitorT );
332 0 : SHMIMMONITORT_UPDATE_INDI( wfsmaskShmimMonitorT );
333 :
334 0 : m_aosys.starMag( m_mag );
335 0 : m_aosys.F0( m_qe * m_F0 );
336 0 : m_aosys.lam_wfs( m_lam0 * 1e-6 );
337 0 : m_aosys.lam_sci( m_lam0 * 1e-6 );
338 0 : m_aosys.ron_wfs( std::vector<float>( { 245.0f / m_emg } ) );
339 0 : m_aosys.npix_wfs( std::vector<float>( { 1.0f * m_npix } ) );
340 0 : m_aosys.minTauWFS( std::vector<float>( { 1.0f / m_fps } ) );
341 0 : m_aosys.tauWFS( 1. / m_fps );
342 0 : m_aosys.atm.r_0( m_r0, 0.5e-6 );
343 0 : m_aosys.zeta( ( 90. - m_elevation ) * 3.14159 / 180. );
344 :
345 0 : updateIfChanged( m_indiP_strehl, "pyramid", m_aosys.strehl() );
346 0 : updatesIfChanged<double>( m_indiP_wfe,
347 : { "total", "measurement", "time_delay", "fitting" },
348 0 : { sqrt( m_aosys.wfeVar() ) * ( 1000 * m_lam0 / two_pi<float>() ),
349 0 : sqrt( m_aosys.measurementErrorTotal() ) * ( 1000 * m_lam0 / two_pi<float>() ),
350 0 : sqrt( m_aosys.timeDelayErrorTotal() ) * ( 1000 * m_lam0 / two_pi<float>() ),
351 0 : sqrt( m_aosys.fittingErrorTotal() ) * ( 1000 * m_lam0 / two_pi<float>() ) } );
352 0 : return 0;
353 : }
354 :
355 0 : int strehlEstimator::appShutdown()
356 : {
357 0 : SHMIMMONITORT_APP_SHUTDOWN( wfsavgShmimMonitorT );
358 0 : SHMIMMONITORT_APP_SHUTDOWN( wfsmaskShmimMonitorT );
359 :
360 0 : return 0;
361 : }
362 :
363 0 : int strehlEstimator::allocate( const wfsavgShmimT &dummy )
364 : {
365 : static_cast<void>( dummy );
366 :
367 0 : std::cerr << "Got WFS avg: " << wfsavgShmimMonitorT::m_width << " x " << wfsavgShmimMonitorT::m_height << '\n';
368 0 : return 0;
369 : }
370 :
371 0 : int strehlEstimator::processImage( void *curr_src, const wfsavgShmimT &dummy )
372 : {
373 : static_cast<void>( dummy );
374 :
375 0 : m_wfsavg = mx::improc::eigenMap<float>(
376 0 : reinterpret_cast<float *>( curr_src ), wfsavgShmimMonitorT::m_width, wfsavgShmimMonitorT::m_height );
377 :
378 0 : if( m_wfsavg.rows() == m_wfsmask.rows() && m_wfsavg.cols() == m_wfsmask.cols() )
379 : {
380 0 : m_counts = ( m_wfsavg * m_wfsmask ).sum();
381 :
382 0 : std::cerr << "counts: " << m_counts << '\n';
383 :
384 0 : calcMag();
385 : }
386 :
387 0 : return 0;
388 : }
389 :
390 0 : int strehlEstimator::allocate( const wfsmaskShmimT &dummy )
391 : {
392 : static_cast<void>( dummy );
393 :
394 0 : std::cerr << "Got WFS mask: " << wfsmaskShmimMonitorT::m_width << " x " << wfsmaskShmimMonitorT::m_height << '\n';
395 0 : return 0;
396 : }
397 :
398 0 : int strehlEstimator::processImage( void *curr_src, const wfsmaskShmimT &dummy )
399 : {
400 : static_cast<void>( dummy );
401 :
402 0 : m_wfsmask = mx::improc::eigenMap<float>(
403 0 : reinterpret_cast<float *>( curr_src ), wfsmaskShmimMonitorT::m_width, wfsmaskShmimMonitorT::m_height );
404 :
405 0 : m_npix = m_wfsmask.sum();
406 :
407 0 : if( m_wfsavg.rows() == m_wfsmask.rows() && m_wfsavg.cols() == m_wfsmask.cols() )
408 : {
409 : // update counts because we might have been waiting on this.
410 0 : m_counts = ( m_wfsavg * m_wfsmask ).sum();
411 :
412 0 : calcMag();
413 : }
414 :
415 0 : return 0;
416 : }
417 :
418 0 : void strehlEstimator::calcMag()
419 : {
420 0 : std::cerr << "calcMag: " << m_counts << ' ' << m_again << ' ' << ' ' << m_emg << ' ' << m_fps << ' ' << m_qe << ' '
421 0 : << m_F0 << '\n';
422 :
423 0 : m_mag = -2.5 * log10( m_counts * m_again / m_emg * m_fps / ( m_qe * m_F0 ) );
424 :
425 0 : updateIfChanged( m_indiP_mag, "current", m_mag );
426 0 : }
427 :
428 0 : INDI_SETCALLBACK_DEFN( strehlEstimator, m_indiP_fps )( const pcf::IndiProperty &ipRecv )
429 : {
430 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_fps, ipRecv );
431 :
432 0 : if( ipRecv.find( "current" ) )
433 : {
434 0 : float fps = ipRecv["current"].get<float>();
435 :
436 0 : if( fps != m_fps )
437 : {
438 0 : m_fps = fps;
439 0 : std::cerr << "Got FPS: " << m_fps << '\n';
440 :
441 0 : calcMag();
442 : }
443 : }
444 0 : return 0;
445 : }
446 :
447 0 : INDI_SETCALLBACK_DEFN( strehlEstimator, m_indiP_emg )( const pcf::IndiProperty &ipRecv )
448 : {
449 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_emg, ipRecv );
450 :
451 0 : if( ipRecv.find( "current" ) )
452 : {
453 0 : float emg = ipRecv["current"].get<float>();
454 :
455 0 : if( emg != m_emg )
456 : {
457 0 : m_emg = emg;
458 0 : std::cerr << "Got EMG: " << m_emg << '\n';
459 :
460 0 : calcMag();
461 : }
462 : }
463 0 : return 0;
464 : }
465 :
466 0 : INDI_SETCALLBACK_DEFN( strehlEstimator, m_indiP_stage )( const pcf::IndiProperty &ipRecv )
467 : {
468 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_stage, ipRecv );
469 :
470 : // if( ipRecv.find( "presetName" ) )
471 : {
472 0 : std::string preset = "none";
473 :
474 0 : for( auto &&el : ipRecv.getElements() )
475 : {
476 0 : if( el.second.getSwitchState() == pcf::IndiElement::On )
477 : {
478 0 : preset = el.first;
479 0 : break;
480 : }
481 : }
482 :
483 0 : std::cerr << "Got stage bs: " << preset << '\n';
484 :
485 0 : if( preset == "ha-ir" )
486 : {
487 0 : m_F0 = m_F0_HaIR;
488 0 : m_lam0 = m_lam0_HaIR;
489 0 : m_qe = m_qe_HaIR;
490 : }
491 : else
492 : {
493 0 : m_F0 = m_F0_6535;
494 0 : m_lam0 = m_lam0_6535;
495 0 : m_qe = m_qe_6535;
496 : }
497 :
498 0 : calcMag();
499 0 : }
500 :
501 0 : return 0;
502 : }
503 :
504 0 : INDI_SETCALLBACK_DEFN( strehlEstimator, m_indiP_tcsi_seeing )( const pcf::IndiProperty &ipRecv )
505 : {
506 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_tcsi_seeing, ipRecv );
507 :
508 0 : if( ipRecv.find( "dimm_fwhm_corr" ) )
509 : {
510 0 : float seeing = ipRecv["dimm_fwhm_corr"].get<float>();
511 :
512 0 : if( seeing != m_seeing )
513 : {
514 0 : m_seeing = seeing;
515 0 : std::cerr << "Got seeing: " << m_seeing << '\n';
516 :
517 0 : m_r0 = 0.2063 * 0.5 / m_seeing;
518 : }
519 : }
520 :
521 0 : return 0;
522 : }
523 :
524 0 : INDI_SETCALLBACK_DEFN( strehlEstimator, m_indiP_tcsi_telpos )( const pcf::IndiProperty &ipRecv )
525 : {
526 0 : INDI_VALIDATE_CALLBACK_PROPS( m_indiP_tcsi_telpos, ipRecv );
527 :
528 0 : if( ipRecv.find( "el" ) )
529 : {
530 0 : float elevation = ipRecv["el"].get<float>();
531 :
532 0 : if( elevation != m_elevation )
533 : {
534 0 : m_elevation = elevation;
535 0 : std::cerr << "Got elevation: " << m_elevation << '\n';
536 : }
537 : }
538 0 : return 0;
539 : }
540 :
541 : } // namespace app
542 : } // namespace MagAOX
543 :
544 : #endif // strehlEstimator_hpp
|