API
 
Loading...
Searching...
No Matches
wooferTweeterRecon.hpp
Go to the documentation of this file.
1/** \file wooferTweeterRecon.hpp
2 * \brief The MagAO-X woofer-tweeter pseudo-open-loop reconstructor
3 *
4 * \ingroup wooferTweeterRecon_files
5 */
6
7#ifndef wooferTweeterRecon_hpp
8#define wooferTweeterRecon_hpp
9
10#include <limits>
11
12#include <mx/improc/eigenCube.hpp>
13#include <mx/improc/eigenImage.hpp>
14#include <mx/sigproc/gramSchmidt.hpp>
15#include <mx/math/templateBLAS.hpp>
16
17#include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
18#include "../../magaox_git_version.h"
19
20namespace MagAOX
21{
22namespace app
23{
24
25/** \defgroup wooferTweeterRecon Woofer Tweeter Pseudo-Open-Loop Reconstructor
26 * \brief Reconstruct the open-loop wavefront from the woofer and tweeter surfaces
27 *
28 * Reconstructs the tweeter shape corresponding to the woofer shape, and combines the woofer and tweeter shapes
29 * and the measured delta.
30 *
31 * <a href="../handbook/operating/software/apps/wooferTweeterRecon.html">Application Documentation</a>
32 *
33 * \ingroup apps
34 *
35 */
36
37/** \defgroup wooferTweeterRecon_files Woofer Tweeter Pseudo-Open-Loop Reconstructor Files
38 * \ingroup wooferTweeterRecon
39 */
40
42{
43 static std::string configSection()
44 {
45 return "wooferModes";
46 };
47
48 static std::string indiPrefix()
49 {
50 return "wooferModes";
51 };
52};
53
55{
56 static std::string configSection()
57 {
58 return "tweeterModes";
59 };
60
61 static std::string indiPrefix()
62 {
63 return "tweeterModes";
64 };
65};
66
68{
69 static std::string configSection()
70 {
71 return "wfsModes";
72 };
73
74 static std::string indiPrefix()
75 {
76 return "wfsModes";
77 };
78};
79
80/** MagAO-X application to perform pseudo-open-loop reconstruction of an offloading woofer-tweeter system
81 *
82 * \ingroup wooferTweeterRecon
83 *
84 */
85class wooferTweeterRecon : public MagAOXApp<true>,
86 public dev::shmimMonitor<wooferTweeterRecon, wooferModesShmimT>,
87 public dev::shmimMonitor<wooferTweeterRecon, tweeterModesShmimT>,
88 public dev::shmimMonitor<wooferTweeterRecon, wfsModesShmimT>//,
89 //public dev::frameGrabber<wooferTweeterRecon>,
90 //public dev::telemeter<wooferTweeterRecon>
91{
92 // Give the test harness access.
94
97
100
103
104 // friend class dev::telemeter<wooferTweeterRecon>;
105
106 // typedef dev::telemeter<wooferTweeterRecon> telemeterT;
107
108 /// Floating point type in which to do all calculations.
109 typedef float realT;
110
111 protected:
112 /** \name Configurable Parameters
113 *@{
114 */
115
116 std::string m_fpsSource{ "camwfs" };
117
118 std::string m_elSource{ "tcsi" };
119
121
122 double m_wooferOffset{ 500e-6 };
123
124 double m_tweeterOffset{ 50e-6 };
125
126 double m_wfsOffset{ -10e-6 };
127
128 ///@}
129
130 bool m_wooferModesReady{ false };
131 bool m_tweeterModesReady{ false };
132 bool m_wfsModesReady{ false };
133
134 struct modevals
135 {
136 double t{ 0 };
137 std::vector<float> vals;
138 bool reconstructed{ false };
139 };
140
141 std::vector<modevals> m_wooferVals;
142 size_t m_lastWooferVal{ 0 };
143
144 std::vector<modevals> m_tweeterVals;
145 size_t m_lastTweeterVal{ 0 };
146
147 std::vector<modevals> m_wfsVals;
148 size_t m_lastWfsVal{ 0 };
149
150 float m_fps{ 0 }; ///< Current FPS from the FPS source.
151
152 float m_invFps{ 0 }; ///< The inverse of FPS
153
154 float m_el {90}; ///< The current elevation
155
156 float m_opticalGain{ 0.8 };
157
158 /// Mutex for locking shared memory access.
159 // std::mutex m_shmimMutex;
160
161 mx::improc::eigenImage<float> m_outputVal;
162 int m_nvals{ 3600*2 }; //2 sec of data at max speed
163 int m_nloaded{ 0 };
164
165 std::vector<float> m_r0;
166 std::vector<float> m_sig;
167 size_t m_lastr0;
168
169 public:
170 /// Default c'tor.
172
173 /// D'tor, declared and defined for noexcept.
177
178 virtual void setupConfig();
179
180 /// Implementation of loadConfig logic, separated for testing.
181 /** This is called by loadConfig().
182 */
183 int loadConfigImpl( mx::app::appConfigurator &_config /**< [in] an application configuration
184 from which to load values*/
185 );
186
187 virtual void loadConfig();
188
189 /// Startup function
190 /**
191 *
192 */
193 virtual int appStartup();
194
195 /// Implementation of the FSM for wooferTweeterRecon.
196 /**
197 * \returns 0 on no critical error
198 * \returns -1 on an error requiring shutdown
199 */
200 virtual int appLogic();
201
202 /// Shutdown the app.
203 /**
204 *
205 */
206 virtual int appShutdown();
207
208 /// Allocate method for the woofer command shmimMonitor
209 /**
210 * \returns 0 on success
211 * \returns -1 on an error
212 */
213 int allocate( const wooferModesShmimT & /**< [in] tag to differentiate shmimMonitor parents.*/ );
214
215 /// Process images for the woofer command shmimMonitor
216 /**
217 * \returns 0 on sucess
218 * \returns -1 on an error
219 */
220 int processImage( void *curr_src, ///< [in] pointer to start of current frame.
221 const wooferModesShmimT & ///< [in] tag to differentiate shmimMonitor parents.
222 );
223
224 int recon();
225
226 /// Allocate method for the tweeter command shmimMonitor
227 /**
228 * \returns 0 on success
229 * \returns -1 on an error
230 */
231 int allocate( const tweeterModesShmimT & /**< [in] tag to differentiate shmimMonitor parents.*/ );
232
233 /// Process images for the tweeter command shmimMonitor
234 /**
235 * \returns 0 on sucess
236 * \returns -1 on an error
237 */
238 int processImage( void *curr_src, ///< [in] pointer to start of current frame.
239 const tweeterModesShmimT & ///< [in] tag to differentiate shmimMonitor parents.
240 );
241
242 /// Allocate method for the wfs modes shmimMonitor
243 /**
244 * \returns 0 on success
245 * \returns -1 on an error
246 */
247 int allocate( const wfsModesShmimT & /**< [in] tag to differentiate shmimMonitor parents.*/ );
248
249 /// Process images for the wfs modes shmimMonitor
250 /**
251 * \returns 0 on sucess
252 * \returns -1 on an error
253 */
254 int processImage( void *curr_src, ///< [in] pointer to start of current frame.
255 const wfsModesShmimT & ///< [in] tag to differentiate shmimMonitor parents.
256 );
257
259
260 protected:
261 /** \name INDI Interface
262 *
263 * @{
264 */
265 pcf::IndiProperty m_indiP_fpsSource;
267
268 pcf::IndiProperty m_indiP_fps;
269
270 pcf::IndiProperty m_indiP_elSource;
272
273 pcf::IndiProperty m_indiP_seeing;
274
275 ///@}
276
277 /** \name Telemeter Interface
278 *
279 * @{
280 */
282
284
285 int recordLoopGain( bool force = false );
286
288
289 int recordOffloading( bool force = false );
290
291 ///@}
292};
293
294inline wooferTweeterRecon::wooferTweeterRecon() : MagAOXApp( MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED )
295{
296 return;
297}
298
300{
301
303
305
307
308 // TELEMETER_SETUP_CONFIG( config );
309
310 config.add( "integrator.fpsSource",
311 "",
312 "integrator.fpsSource",
313 argType::Required,
314 "integrator",
315 "fpsSource",
316 false,
317 "string",
318 "Device name for getting fps of the loop. This device should have *.fps.current. Default is camwfs" );
319
320 config.add( "woofer.offset",
321 "",
322 "woofer.offset",
323 argType::Required,
324 "woofer",
325 "offset",
326 false,
327 "float",
328 "Offset, in seconds, for the woofer command from its write time" );
329
330 config.add( "tweeter.offset",
331 "",
332 "tweeter.offset",
333 argType::Required,
334 "tweeter",
335 "offset",
336 false,
337 "float",
338 "Offset, in seconds, for the tweeter command from its write time" );
339
340 config.add( "wfs.offset",
341 "",
342 "wfs.offset",
343 argType::Required,
344 "wfs",
345 "offset",
346 false,
347 "float",
348 "Offset, in seconds, for the wfs from its acquisition time and 1/fps" );
349}
350
351inline int wooferTweeterRecon::loadConfigImpl( mx::app::appConfigurator &_config )
352{
353
354 wooferModesSMT::m_shmimName = "aol0_modevalDMf_mon";
357
358 tweeterModesSMT::m_shmimName = "aol1_modevalDMf_mon";
361
362 wfsModesSMT::m_shmimName = "aol1_modevalWFS";
365
366 // TELEMETER_LOAD_CONFIG( _config );
367
368 _config( m_fpsSource, "integrator.fpsSource" );
369
370 _config( m_wooferOffset, "woofer.offset" );
371 _config( m_tweeterOffset, "tweeter.offset" );
372 _config( m_wfsOffset, "wfs.offset" );
373
374 return 0;
375}
376
378{
379 loadConfigImpl( config );
380}
381
383{
384
385 REG_INDI_SETPROP( m_indiP_fpsSource, m_fpsSource, std::string( "fps" ) );
386
388 m_indiP_fps.add( pcf::IndiElement( "current" ) );
390 {
392 return -1;
393 }
394
395 REG_INDI_SETPROP( m_indiP_elSource, m_elSource, std::string( "telpos" ) );
396
398 m_indiP_seeing.add( pcf::IndiElement( "r0_1sec" ) );
399 m_indiP_seeing.add( pcf::IndiElement( "r0_1sec_std" ) );
400 m_indiP_seeing.add( pcf::IndiElement( "fwhm_1sec" ) );
401 m_indiP_seeing.add( pcf::IndiElement( "fwhm_1sec_std" ) );
402 m_indiP_seeing.add( pcf::IndiElement( "fwhm_1sec_zenith" ) );
403 m_indiP_seeing.add( pcf::IndiElement( "r0_10sec" ) );
404 m_indiP_seeing.add( pcf::IndiElement( "r0_10sec_std" ) );
405 m_indiP_seeing.add( pcf::IndiElement( "fwhm_10sec" ) );
406 m_indiP_seeing.add( pcf::IndiElement( "fwhm_10sec_std" ) );
407 m_indiP_seeing.add( pcf::IndiElement( "fwhm_10sec_zenith" ) );
408
410 {
412 return -1;
413 }
414
418
419 // TELEMETER_APP_STARTUP;
420
422
423 return 0;
424}
425
427{
431
432 // TELEMETER_APP_LOGIC;
433
434 if( m_fps > 0 )
435 {
436 float cz = pow( cos( 3.14159 / 180. * ( 90 - m_el ) ), 3 / 5. );
437
438 size_t n1sec = m_fps;
439
440 std::vector<float> cr0( n1sec );
441
442 for( size_t n = 0; n < n1sec; ++n )
443 {
444 ssize_t m = m_lastr0 - n;
445 if( m < 0 )
446 {
447 m = m_r0.size() - 1;
448 }
449 cr0[n] = m_r0[m];
450 }
451
452 float r01 = mx::math::vectorMean( cr0 );
453 float vr01 = sqrt( mx::math::vectorVariance( cr0, r01 ) );
454
455 float fwhm1 = 0.2063 * 0.5 / r01;
456 float vfw1 = fwhm1 * ( vr01 / r01 );
457 float fwhm1cz = fwhm1 * cz;
458
459 size_t n10sec = 10 * m_fps;
460
461 cr0.resize( n10sec );
462
463 for( size_t n = 0; n < n10sec; ++n )
464 {
465 ssize_t m = m_lastr0 - n;
466 if( m < 0 )
467 {
468 m = m_r0.size() - 1;
469 }
470 cr0[n] = m_r0[m];
471 }
472
473 float r010 = mx::math::vectorMean( cr0 );
474 float vr010 = sqrt( mx::math::vectorVariance( cr0, r010 ) );
475
476 float fwhm10 = 0.2063 * 0.5 / r010;
477 float vfw10 = fwhm10 * ( vr010 / r010 );
478 float fwhm10cz = fwhm10 * cz;
479
481 { "r0_1sec",
482 "r0_1sec_std",
483 "fwhm_1sec",
484 "fwhm_1sec_std",
485 "fwhm_1sec_zenith",
486 "r0_10sec",
487 "r0_10sec_std",
488 "fwhm_10sec",
489 "fwhm_10sec_std",
490 "fwhm_10sec_zenith" },
492
493 // float s2 = mx::math::vectorMean(m_sig);
494 // float S = exp(-s2*pow(2*3.14159/0.9,2) - 0.28*pow(0.135/r0, 5./3.));
495
496 // std::cerr << std::format("r0 = {} +/- {} fwhm = {}\" +/- {}\" at zenith = {}\" SR = {}", r0, vr0, fwhm, vfw,
497 // fwhm*cz, S) << '\n';
498 }
499
500 std::unique_lock<std::mutex> lock( m_indiMutex );
501
505
506 return 0;
507}
508
510{
514
515 // TELEMETER_APP_SHUTDOWN;
516
517 return 0;
518}
519
521{
522 m_wooferModesReady = false;
523
524 std::cerr << "woofer modes not ready\n";
525
527 {
528 if( m_wfsModesReady )
529 {
531 }
532
534
535 mx::sys::milliSleep( 1000 );
536
537 return 0; // This won't log an error, but setting m_restart will cause it to loop again until sizes match
538 }
539
541
542 for( auto &val : m_wooferVals )
543 {
544 val.t = 0;
545 val.vals.resize( tweeterModesSMT::m_width, 0 );
546 val.reconstructed = false;
547 }
548
549 m_wooferModesReady = true;
550
551 std::cerr << "woofer modes ready\n";
552
553 return 0;
554}
555
557{
558 size_t next = m_lastWooferVal + 1;
559 if( next >= m_wooferVals.size() )
560 {
561 next = 0;
562 }
563
564 for( size_t n = 0; n < wooferModesSMT::m_width; ++n )
565 {
566 m_wooferVals[next].vals[n] = reinterpret_cast<float *>( curr_src )[n];
567 }
568
569 m_wooferVals[next].t = wooferModesSMT::m_imageStream.md->atime.tv_sec +
570 wooferModesSMT::m_imageStream.md->atime.tv_nsec / 1e9 + m_wooferOffset;
571 m_wooferVals[next].reconstructed = false;
572
574
575 recon();
576
577 return 0;
578}
579
581{
582 m_tweeterModesReady = false;
583
586
587 std::cerr << "tweeter modes not ready\n";
588
590
591 m_r0.resize( 3600*30, 0 );
592 m_sig.resize( 3600*30,0 );
593 for( auto &val : m_tweeterVals )
594 {
595 val.t = 0;
596 val.vals.resize( tweeterModesSMT::m_width, 0 );
597 val.reconstructed = false;
598 }
599
601 m_tweeterModesReady = true;
602
603 std::cerr << "tweeter modes ready\n";
604
605 return 0;
606}
607
609{
610 size_t next = m_lastTweeterVal + 1;
611 if( next >= m_tweeterVals.size() )
612 {
613 next = 0;
614 }
615
616 for( size_t n = 0; n < tweeterModesSMT::m_width; ++n )
617 {
618 m_tweeterVals[next].vals[n] = reinterpret_cast<float *>( curr_src )[n];
619 }
620
623 m_tweeterVals[next].reconstructed = false;
624
626
627 return 0;
628}
629
631{
632 m_wfsModesReady = false;
633
634 std::cerr << "wfs modes not ready\n";
635
637 {
639 {
641 }
642
644 mx::sys::milliSleep( 1000 );
645
646 return 0; // This won't log an error, but setting m_restart will cause it to loop again until sizes match
647 }
648
650
651 for( auto &val : m_wfsVals )
652 {
653 val.t = 0;
654 val.vals.resize( wfsModesSMT::m_width, 0 );
655 val.reconstructed = false;
656 }
657
658 m_wfsModesReady = true;
659
660 std::cerr << "wfs modes ready\n";
661
662 return 0;
663}
664
666{
667 size_t next = m_lastWfsVal + 1;
668 if( next >= m_wfsVals.size() )
669 {
670 next = 0;
671 }
672
673 for( size_t n = 0; n < wooferModesSMT::m_width; ++n )
674 {
675 m_wfsVals[next].vals[n] = reinterpret_cast<float *>( curr_src )[n];
676 }
677
678 m_wfsVals[next].t = wfsModesSMT::m_imageStream.md->writetime.tv_sec +
679 wfsModesSMT::m_imageStream.md->writetime.tv_nsec / 1e9 - m_invFps + m_wfsOffset;
680 m_wfsVals[next].reconstructed = false;
681
683
684 return 0;
685}
686
687#define decst \
688 if( st == 0 ) \
689 { \
690 st = m_wfsVals.size(); \
691 } \
692 --st;
693
695{
696 if( m_nloaded != 0 )
697 {
698 std::cerr << "we're behind!\n";
699 }
700
701 size_t st = m_lastWfsVal;
702
703 size_t wst = m_lastWooferVal;
704
705 size_t tst = m_lastTweeterVal;
706
707 while( m_wfsVals[st].reconstructed == false && m_wfsVals[st].t > 0 )
708 {
709 // Find starting woofer value
710 if( m_wooferVals[wst].t < m_wfsVals[st].t )
711 {
712 // Starting woofer value is not later than current WFS val
713 decst;
714 continue;
715 }
716
717 while( m_wooferVals[wst].t > m_wfsVals[st].t && m_wooferVals[wst].t > 0 )
718 {
719 if( wst == 0 )
720 {
721 wst = m_wooferVals.size();
722 }
723 --wst;
724
725 if( wst == m_lastWooferVal || m_wooferVals[wst].t == 0 )
726 {
727 // Starting woofer value is not later than current WFS val
728 break;
729 }
730 }
731
732 // Have to check this again so we continue the right loop
733 if( wst == m_lastWooferVal || m_wooferVals[wst].t == 0 )
734 {
735 // Starting woofer value is not later than current WFS val
736 decst;
737 continue;
738 }
739
740 size_t wnxt = wst + 1;
741 if( wnxt >= m_wooferVals.size() )
742 {
743 wnxt = 0;
744 }
745
746 if( m_wooferVals[wnxt].t == 0 )
747 {
748 decst;
749 continue;
750 }
751
752 if( !( m_wooferVals[wst].t <= m_wfsVals[st].t && m_wooferVals[wnxt].t >= m_wfsVals[st].t ) )
753 {
754 std::cerr << __LINE__ << '\n';
755 // an error!
756 return -1;
757 }
758
759 // std::cerr << "Found woofer: " << m_wfsVals[st].t - m_wooferVals[wst].t << ' '
760 // << m_wooferVals[wnxt].t - m_wfsVals[st].t << '\n';
761
762 // Find starting tweeter value
763 if( m_tweeterVals[tst].t < m_wfsVals[st].t )
764 {
765 // Starting tweeter value is not later than current WFS val
766 decst;
767 continue;
768 }
769
770 while( m_tweeterVals[tst].t > m_wfsVals[st].t && m_tweeterVals[tst].t > 0 )
771 {
772 if( tst == 0 )
773 {
774 tst = m_tweeterVals.size();
775 }
776 --tst;
777
778 if( tst == m_lastTweeterVal || m_tweeterVals[tst].t == 0 )
779 {
780 // Starting tweeter value is not later than current WFS val
781 break;
782 }
783 }
784
785 // Have to check this again so we continue the right loop
786 if( tst == m_lastTweeterVal || m_tweeterVals[tst].t == 0 )
787 {
788 // Starting tweeter value is not later than current WFS val
789 decst;
790 continue;
791 }
792
793 size_t tnxt = tst + 1;
794 if( tnxt >= m_tweeterVals.size() )
795 {
796 tnxt = 0;
797 }
798
799 if( m_tweeterVals[tnxt].t == 0 )
800 {
801 decst;
802 continue;
803 }
804
805 if( !( m_tweeterVals[tst].t <= m_wfsVals[st].t && m_tweeterVals[tnxt].t >= m_wfsVals[st].t ) )
806 {
807 std::cerr << __LINE__ << '\n';
808 // an error!
809 return -1;
810 }
811
812 // std::cerr << "\tFound tweeter: " << m_wfsVals[st].t - m_tweeterVals[tst].t << ' '
813 // << m_tweeterVals[tnxt].t - m_wfsVals[st].t << '\n';
814
815 double wdt = ( m_wfsVals[st].t - m_wooferVals[wst].t ) / ( m_wooferVals[wnxt].t - m_wooferVals[wst].t );
816 double tdt = ( m_wfsVals[st].t - m_tweeterVals[tst].t ) / ( m_tweeterVals[tnxt].t - m_tweeterVals[tst].t );
817
818 float s2 = 0;
819 for( size_t n = 0; n < m_wfsVals[st].vals.size(); ++n )
820 {
821 float wval = m_wooferVals[wst].vals[n] + ( m_wooferVals[wnxt].vals[n] - m_wooferVals[wst].vals[n] ) * wdt;
822 float tval =
823 m_tweeterVals[tst].vals[n] + ( m_tweeterVals[tnxt].vals[n] - m_tweeterVals[tst].vals[n] ) * tdt;
824 float wfsval = m_wfsVals[st].vals[n] / m_opticalGain;
825
826 s2 += wfsval * wfsval;
827
828 m_outputVal( n, m_nloaded ) = 0.04 * wval + tval + wfsval; // wval;// + tval + wfsval;
829 }
830
831 float var = m_outputVal.col( m_nloaded ).square().sum();
832
833 float r0 = pow( 1.0299 * pow( 6.5, 5. / 3. ) / ( 4 * var * pow( 2 * 3.14159 / 0.5, 2 ) ), 3. / 5. );
834
835 size_t nr0 = m_lastr0 + 1;
836 if( nr0 >= m_r0.size() )
837 {
838 nr0 = 0;
839 }
840
841 m_r0[nr0] = r0;
842 m_sig[nr0] = s2;
843
844 m_lastr0 = nr0;
845
846 m_wfsVals[st].reconstructed = true;
847
848 ++m_nloaded;
849
850 if( m_nloaded >= m_outputVal.cols() )
851 {
852 std::cerr << "we're behind more\n";
853 break;
854 }
855
856 decst;
857 }
858
859 m_nloaded = 0; // resetting until fg implemented
860 // the fg will load the last m_nloaded into the c-buff shmim, from which PSDs will be calculated
861
862 return 0;
863}
864
865INDI_SETCALLBACK_DEFN( wooferTweeterRecon, m_indiP_fpsSource )( const pcf::IndiProperty &ipRecv )
866{
867 if( ipRecv.getName() != m_indiP_fpsSource.getName() )
868 {
869 log<software_error>( { __FILE__, __LINE__, "Invalid INDI property." } );
870 return -1;
871 }
872
873 if( ipRecv.find( "current" ) != true ) // this isn't valie
874 {
875 return 0;
876 }
877
878 std::lock_guard<std::mutex> guard( m_indiMutex );
879
880 realT fps = ipRecv["current"].get<float>();
881
882 if( fps != m_fps )
883 {
884 m_fps = fps;
885 if( m_fps <= 0 )
886 {
887 m_invFps = 0;
888 }
889 else
890 {
891 m_invFps = 1.0 / m_fps;
892 }
893
894 updateIfChanged( m_indiP_fps, "current", m_fps );
895 }
896
897 return 0;
898}
899
900INDI_SETCALLBACK_DEFN( wooferTweeterRecon, m_indiP_elSource )( const pcf::IndiProperty &ipRecv )
901{
902 if( ipRecv.getName() != m_indiP_elSource.getName() )
903 {
904 log<software_error>( { __FILE__, __LINE__, "Invalid INDI property." } );
905 return -1;
906 }
907
908 if( ipRecv.find( "el" ) != true ) // this isn't valid
909 {
910 return 0;
911 }
912
913 std::lock_guard<std::mutex> guard( m_indiMutex );
914
915 m_el = ipRecv["el"].get<float>();
916
917 return 0;
918}
919
920/*
921int wooferTweeterRecon::checkRecordTimes()
922{
923 return telemeterT::checkRecordTimes( telem_loopgain(), telem_offloading() );
924}
925
926int wooferTweeterRecon::recordTelem( const telem_loopgain * )
927{
928 return recordLoopGain( true );
929}
930
931int wooferTweeterRecon::recordLoopGain( bool force )
932{
933 static uint8_t state{ 0 };
934 static float gain{ -1000 };
935 static float leak{ 0 };
936 static float limit{ 0 };
937
938 if( state != m_offloading || gain != m_gain || leak != m_leak || limit != m_actLim || force )
939 {
940 state = m_offloading;
941 gain = m_gain;
942 leak = m_leak;
943 limit = m_actLim;
944
945 telem<telem_loopgain>( { state, m_gain, 1 - leak, limit } );
946 }
947
948 return 0;
949}
950
951int wooferTweeterRecon::recordTelem( const telem_offloading * )
952{
953 return recordOffloading( true );
954}
955
956int wooferTweeterRecon::recordOffloading( bool force )
957{
958 static uint32_t num_modes{ 0 };
959 static uint32_t num_average{ 0 };
960 float fps{ 0 };
961
962 if( num_modes != m_numModes || num_average != m_navg || fps != m_effFPS || force )
963 {
964 num_modes = m_numModes;
965 num_average = m_navg;
966 fps = m_effFPS;
967
968 telem<telem_offloading>( { num_modes, num_average, fps } );
969 }
970
971 return 0;
972}
973*/
974
975} // namespace app
976} // namespace MagAOX
977
978#endif // wooferTweeterRecon_hpp
The base-class for XWCTk applications.
stateCodes::stateCodeT state()
Get the current state code.
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
int createROIndiNumber(pcf::IndiProperty &prop, const std::string &propName, const std::string &propLabel="", const std::string &propGroup="")
Create a ReadOnly INDI Number property.
int registerIndiPropertyReadOnly(pcf::IndiProperty &prop)
Register an INDI property which is read only.
std::mutex m_indiMutex
Mutex for locking INDI communications.
bool m_restart
Flag indicating tha the shared memory should be reinitialized.
~wooferTweeterRecon() noexcept
D'tor, declared and defined for noexcept.
int recordOffloading(bool force=false)
int recordTelem(const telem_offloading *)
dev::shmimMonitor< wooferTweeterRecon, tweeterModesShmimT > tweeterModesSMT
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
virtual int appStartup()
Startup function.
INDI_SETCALLBACK_DECL(wooferTweeterRecon, m_indiP_fpsSource)
virtual int appLogic()
Implementation of the FSM for wooferTweeterRecon.
dev::shmimMonitor< wooferTweeterRecon, wooferModesShmimT > wooferModesSMT
std::vector< modevals > m_tweeterVals
float realT
Floating point type in which to do all calculations.
dev::shmimMonitor< wooferTweeterRecon, wfsModesShmimT > wfsModesSMT
virtual int appShutdown()
Shutdown the app.
int recordTelem(const telem_loopgain *)
float m_el
The current elevation.
int allocate(const wooferModesShmimT &)
Allocate method for the woofer command shmimMonitor.
mx::improc::eigenImage< float > m_outputVal
Mutex for locking shared memory access.
int recordLoopGain(bool force=false)
float m_fps
Current FPS from the FPS source.
int processImage(void *curr_src, const wooferModesShmimT &)
Process images for the woofer command shmimMonitor.
INDI_SETCALLBACK_DECL(wooferTweeterRecon, m_indiP_elSource)
#define INDI_SETCALLBACK_DEFN(class, prop)
Define the callback for a set property request.
#define REG_INDI_SETPROP(prop, devName, propName)
Register a SET INDI property with the class, using the standard callback name.
@ OPERATING
The device is operating, other than homing.
const pcf::IndiProperty & ipRecv
updateIfChanged(m_indiP_angle, "target", m_angle)
std::unique_lock< std::mutex > lock(m_indiMutex)
Definition dm.hpp:19
#define SHMIMMONITORT_APP_STARTUP(SHMIMMONITORT)
Call shmimMonitorT::appStartup with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITORT_UPDATE_INDI(SHMIMMONITORT)
Call shmimMonitorT::updateINDI with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITORT_SETUP_CONFIG(SHMIMMONITORT, cfig)
Call shmimMonitorT::setupConfig with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITORT_APP_LOGIC(SHMIMMONITORT)
Call shmimMonitorT::appLogic with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITORT_APP_SHUTDOWN(SHMIMMONITORT)
Call shmimMonitorT::appShutodwn with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITORT_LOAD_CONFIG(SHMIMMONITORT, cfig)
Call shmimMonitorT::loadConfig with error checking for a typedef-ed shmimMonitor.
static std::string configSection()
Log entry recording the build-time git state.
Log entry recording the build-time git state.
#define decst