API
 
Loading...
Searching...
No Matches
modalGainOpt.hpp
Go to the documentation of this file.
1/** \file modalGainOpt.hpp
2 * \brief The MagAO-X PSD-based gain optimizer header file
3 *
4 * \ingroup modalGainOpt_files
5 */
6
7#ifndef modalGainOpt_hpp
8#define modalGainOpt_hpp
9
10#include <algorithm>
11#include <atomic>
12#include <cctype>
13
14#include <mx/ao/analysis/clAOLinearPredictor.hpp>
15#include <mx/ao/analysis/clGainOpt.hpp>
16#include <mx/mxException.hpp>
17
18#include "modalPsdProcessor.hpp"
19
20#include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
21#include "../../magaox_git_version.h"
22
23/** \defgroup modalGainOpt
24 * \brief The MagAO-X application to perform PSD-based gain optimization
25 *
26 * <a href="../handbook/operating/software/apps/modalGainOpt.html">Application
27 * Documentation</a>
28 *
29 * \ingroup apps
30 *
31 */
32
33/** \defgroup modalGainOpt_files
34 * \ingroup modalGainOpt
35 */
36
37namespace MagAOX
38{
39namespace app
40{
41
42#define MGO_BREADCRUMB
43
44// #define MGO_BREADCRUMB std::cerr << __FILE__ << ' ' << __LINE__ << '\n';
45
47
48static constexpr int c_olProcessNone = 0;
49static constexpr int c_olProcessLegacy = 1;
50static constexpr int c_olProcessPowerLawOnly = 2;
51static constexpr int c_olProcessMoffatPeaks = 3;
52
53static constexpr int c_extrapNoiseEstimateOpenLoop = 0;
55static constexpr int c_extrapNoiseEstimateHighFreq = 0;
56static constexpr int c_extrapNoiseEstimateLowFreq = 1;
57static constexpr int c_extrapNoiseEstimatePercentile = 0;
58static constexpr int c_extrapNoiseEstimateMinimum = 1;
59static constexpr int c_extrapClosedLoopOlEstimateEtfOnly = 0;
60static constexpr int c_extrapClosedLoopOlEstimateNtfAware = 1;
61static constexpr int c_extrapPowerLawCrossoverManual = 0;
63
64inline std::string olProcessMethodElement( int method )
65{
66 switch( method )
67 {
69 return "legacy";
71 return "power_law_only";
73 return "moffat_peaks";
74 case c_olProcessNone:
75 default:
76 return "none";
77 }
78}
79
80inline std::string olProcessMethodLabel( int method )
81{
82 switch( method )
83 {
85 return "Legacy";
87 return "Power Law Only";
89 return "Moffat Peaks";
90 case c_olProcessNone:
91 default:
92 return "None";
93 }
94}
95
96inline std::string olProcessMethodName( int method )
97{
98 switch( method )
99 {
101 return "legacy";
103 return "power-law-only";
105 return "moffat-peaks";
106 case c_olProcessNone:
107 default:
108 return "none";
109 }
110}
111
112inline int olProcessMethodFromElement( const std::string &element )
113{
114 if( element == "legacy" )
115 {
116 return c_olProcessLegacy;
117 }
118
119 if( element == "power_law_only" )
120 {
122 }
123
124 if( element == "moffat_peaks" )
125 {
127 }
128
129 return c_olProcessNone;
130}
131
132inline int olProcessMethodFromName( std::string method )
133{
134 std::transform( method.begin(),
135 method.end(),
136 method.begin(),
137 []( unsigned char c )
138 {
139 if( c == '_' )
140 {
141 return static_cast<char>( '-' );
142 }
143
144 return static_cast<char>( std::tolower( c ) );
145 } );
146
147 if( method == "legacy" )
148 {
149 return c_olProcessLegacy;
150 }
151
152 if( method == "power-law-only" )
153 {
155 }
156
157 if( method == "moffat-peaks" )
158 {
160 }
161
162 return c_olProcessNone;
163}
164
165inline std::string extrapBoolString( bool value )
166{
167 return value ? "true" : "false";
168}
169
170inline std::string extrapNoiseEstimateDomainElement( int domain )
171{
172 switch( domain )
173 {
175 return "closed_loop_pre_xfer";
177 default:
178 return "open_loop";
179 }
180}
181
182inline std::string extrapNoiseEstimateDomainLabel( int domain )
183{
184 switch( domain )
185 {
187 return "Closed Loop Pre-Xfer";
189 default:
190 return "Open Loop";
191 }
192}
193
194inline std::string extrapNoiseEstimateDomainName( int domain )
195{
196 switch( domain )
197 {
199 return "closed-loop-pre-xfer";
201 default:
202 return "open-loop";
203 }
204}
205
206inline int extrapNoiseEstimateDomainFromElement( const std::string &element )
207{
208 if( element == "closed_loop_pre_xfer" )
209 {
211 }
212
214}
215
216inline int extrapNoiseEstimateDomainFromName( std::string domain )
217{
218 std::transform( domain.begin(),
219 domain.end(),
220 domain.begin(),
221 []( unsigned char c )
222 {
223 if( c == '_' )
224 {
225 return static_cast<char>( '-' );
226 }
227
228 return static_cast<char>( std::tolower( c ) );
229 } );
230
231 if( domain == "closed-loop-pre-xfer" )
232 {
233 return c_extrapNoiseEstimateClosedLoopPreXfer;
234 }
235
236 return c_extrapNoiseEstimateOpenLoop;
237}
238
239inline std::string extrapNoiseEstimateRangeElement( int range )
240{
241 switch( range )
242 {
244 return "low_freq";
246 default:
247 return "high_freq";
248 }
249}
250
251inline std::string extrapNoiseEstimateRangeLabel( int range )
252{
253 switch( range )
254 {
256 return "Low Frequency";
258 default:
259 return "High Frequency";
260 }
261}
262
263inline std::string extrapNoiseEstimateRangeName( int range )
264{
265 switch( range )
266 {
268 return "low-freq";
270 default:
271 return "high-freq";
272 }
273}
274
275inline int extrapNoiseEstimateRangeFromElement( const std::string &element )
276{
277 if( element == "low_freq" )
278 {
280 }
281
283}
284
285inline int extrapNoiseEstimateRangeFromName( std::string range )
286{
287 std::transform( range.begin(),
288 range.end(),
289 range.begin(),
290 []( unsigned char c )
291 {
292 if( c == '_' )
293 {
294 return static_cast<char>( '-' );
295 }
296
297 return static_cast<char>( std::tolower( c ) );
298 } );
299
300 if( range == "low-freq" )
301 {
302 return c_extrapNoiseEstimateLowFreq;
303 }
304
305 return c_extrapNoiseEstimateHighFreq;
306}
307
308inline std::string extrapNoiseEstimateStatisticElement( int statistic )
309{
310 switch( statistic )
311 {
313 return "minimum";
315 default:
316 return "percentile";
317 }
318}
319
320inline std::string extrapNoiseEstimateStatisticLabel( int statistic )
321{
322 switch( statistic )
323 {
325 return "Minimum";
327 default:
328 return "Percentile";
329 }
330}
331
332inline std::string extrapNoiseEstimateStatisticName( int statistic )
333{
334 switch( statistic )
335 {
337 return "minimum";
339 default:
340 return "percentile";
341 }
342}
343
344inline int extrapNoiseEstimateStatisticFromElement( const std::string &element )
345{
346 if( element == "minimum" )
347 {
349 }
350
352}
353
354inline int extrapNoiseEstimateStatisticFromName( std::string statistic )
355{
356 std::transform( statistic.begin(),
357 statistic.end(),
358 statistic.begin(),
359 []( unsigned char c )
360 {
361 if( c == '_' )
362 {
363 return static_cast<char>( '-' );
364 }
365
366 return static_cast<char>( std::tolower( c ) );
367 } );
368
369 if( statistic == "minimum" )
370 {
371 return c_extrapNoiseEstimateMinimum;
372 }
373
374 return c_extrapNoiseEstimatePercentile;
375}
376
377inline std::string extrapClosedLoopOlEstimateMethodElement( int method )
378{
379 switch( method )
380 {
382 return "ntf_aware";
384 default:
385 return "etf_only";
386 }
387}
388
389inline std::string extrapClosedLoopOlEstimateMethodLabel( int method )
390{
391 switch( method )
392 {
394 return "NTF Aware";
396 default:
397 return "ETF Only";
398 }
399}
400
401inline std::string extrapClosedLoopOlEstimateMethodName( int method )
402{
403 switch( method )
404 {
406 return "ntf-aware";
408 default:
409 return "etf-only";
410 }
411}
412
413inline int extrapClosedLoopOlEstimateMethodFromElement( const std::string &element )
414{
415 if( element == "ntf_aware" )
416 {
418 }
419
421}
422
423inline int extrapClosedLoopOlEstimateMethodFromName( std::string method )
424{
425 std::transform( method.begin(),
426 method.end(),
427 method.begin(),
428 []( unsigned char c )
429 {
430 if( c == '_' )
431 {
432 return static_cast<char>( '-' );
433 }
434
435 return static_cast<char>( std::tolower( c ) );
436 } );
437
438 if( method == "ntf-aware" )
439 {
440 return c_extrapClosedLoopOlEstimateNtfAware;
441 }
442
443 return c_extrapClosedLoopOlEstimateEtfOnly;
444}
445
446inline std::string extrapPowerLawCrossoverModeElement( int mode )
447{
448 switch( mode )
449 {
451 return "auto_smoothed_crossing";
453 default:
454 return "manual";
455 }
456}
457
458inline std::string extrapPowerLawCrossoverModeLabel( int mode )
459{
460 switch( mode )
461 {
463 return "Auto Smoothed Crossing";
465 default:
466 return "Manual";
467 }
468}
469
470inline std::string extrapPowerLawCrossoverModeName( int mode )
471{
472 switch( mode )
473 {
475 return "auto-smoothed-crossing";
477 default:
478 return "manual";
479 }
480}
481
482inline int extrapPowerLawCrossoverModeFromElement( const std::string &element )
483{
484 if( element == "auto_smoothed_crossing" )
485 {
487 }
488
490}
491
492inline int extrapPowerLawCrossoverModeFromName( std::string mode )
493{
494 std::transform( mode.begin(),
495 mode.end(),
496 mode.begin(),
497 []( unsigned char c )
498 {
499 if( c == '_' )
500 {
501 return static_cast<char>( '-' );
502 }
503
504 return static_cast<char>( std::tolower( c ) );
505 } );
506
507 if( mode == "auto" || mode == "automatic" || mode == "auto-crossing" || mode == "auto-smoothed-crossing" )
508 {
509 return c_extrapPowerLawCrossoverAutoSmoothedCrossing;
510 }
511
512 return c_extrapPowerLawCrossoverManual;
513}
514
516{
517 static std::string configSection()
518 {
519 return "psdShmim";
520 };
521
522 static std::string indiPrefix()
523 {
524 return "psd";
525 };
526};
527
529{
530 static std::string configSection()
531 {
532 return "freqShmim";
533 };
534
535 static std::string indiPrefix()
536 {
537 return "freq";
538 };
539};
540
541struct gainFactShmimT
542{
543 static std::string configSection()
544 {
545 return "gainFactShmim";
546 };
547
548 static std::string indiPrefix()
549 {
550 return "gainFact";
551 };
552};
553
554struct multFactShmimT
555{
556 static std::string configSection()
557 {
558 return "multFactShmim";
559 };
560
561 static std::string indiPrefix()
562 {
563 return "multFact";
564 };
565};
566
567struct pcGainFactShmimT
568{
569 static std::string configSection()
570 {
571 return "pcGainFactShmim";
572 };
573
574 static std::string indiPrefix()
575 {
576 return "pcGainFact";
577 };
578};
579
580struct pcMultFactShmimT
581{
582 static std::string configSection()
583 {
584 return "pcMultFactShmim";
585 };
586
587 static std::string indiPrefix()
588 {
589 return "pcMultFact";
590 };
591};
592
594{
595 static std::string configSection()
596 {
597 return "numpccoeffShmim";
598 };
599
600 static std::string indiPrefix()
601 {
602 return "numpccoeff";
603 };
604};
605
606struct acoeffShmimT
607{
608 static std::string configSection()
609 {
610 return "acoeffShmim";
611 };
612
613 static std::string indiPrefix()
614 {
615 return "acoeff";
616 };
617};
618
619struct bcoeffShmimT
620{
621 static std::string configSection()
622 {
623 return "bcoeffShmim";
624 };
625
626 static std::string indiPrefix()
627 {
628 return "bcoeff";
629 };
630};
631
633{
634 static std::string configSection()
635 {
636 return "gainCalShmim";
637 };
638
639 static std::string indiPrefix()
640 {
641 return "gainCal";
642 };
643};
644
646{
647 static std::string configSection()
648 {
649 return "gainCalFactShmim";
650 };
651
652 static std::string indiPrefix()
653 {
654 return "gainCalFact";
655 };
656};
657
659{
660 static std::string configSection()
661 {
662 return "tauShmim";
663 };
664
665 static std::string indiPrefix()
666 {
667 return "tau";
668 };
669};
670
672{
673 static std::string configSection()
674 {
675 return "noiseShmim";
676 };
677
678 static std::string indiPrefix()
679 {
680 return "noise";
681 };
682};
683
685{
686 static std::string configSection()
687 {
688 return "wfsavgShmim";
689 };
690
691 static std::string indiPrefix()
692 {
693 return "wfsavg";
694 };
695};
696
698{
699 static std::string configSection()
700 {
701 return "wfsmaskShmim";
702 };
703
704 static std::string indiPrefix()
705 {
706 return "wfsmask";
707 };
708};
709
710/// The MagAO-X PSD-based gain optimizer
711/**
712 * \ingroup modalGainOpt
713 */
714class modalGainOpt : public MagAOXApp<true>,
715 public dev::telemeter<modalGainOpt>,
716 dev::shmimMonitor<modalGainOpt, psdShmimT>,
717 dev::shmimMonitor<modalGainOpt, freqShmimT>,
718 dev::shmimMonitor<modalGainOpt, gainFactShmimT>,
719 dev::shmimMonitor<modalGainOpt, multFactShmimT>,
720 dev::shmimMonitor<modalGainOpt, pcGainFactShmimT>,
721 dev::shmimMonitor<modalGainOpt, pcMultFactShmimT>,
722 dev::shmimMonitor<modalGainOpt, numpccoeffShmimT>,
723 dev::shmimMonitor<modalGainOpt, acoeffShmimT>,
724 dev::shmimMonitor<modalGainOpt, bcoeffShmimT>,
725 dev::shmimMonitor<modalGainOpt, gainCalShmimT>,
726 dev::shmimMonitor<modalGainOpt, gainCalFactShmimT>,
727 dev::shmimMonitor<modalGainOpt, tauShmimT>,
728 dev::shmimMonitor<modalGainOpt, noiseShmimT>,
729 dev::shmimMonitor<modalGainOpt, wfsavgShmimT>,
730 dev::shmimMonitor<modalGainOpt, wfsmaskShmimT>
731
732{
733
734 // Give the test harness access.
735 friend class modalGainOpt_test;
737
738 friend class dev::telemeter<modalGainOpt>;
739
755
756 public:
772
773 typedef std::chrono::time_point<std::chrono::steady_clock> timePointT;
774 typedef std::chrono::duration<double> durationT;
775
776 protected:
777 /** \name Configurable Parameters
778 *@{
779 */
780
781 int m_loopNum{ 1 }; ///< The number of the loop. Used to set shmim names, as in
782 ///< aolN_mgainfact.
783
784 std::string m_loopName; ///< The name of the loop control INDI device name.
785
786 std::string m_wfsDevice{ "camwfs" };
787
788 std::string m_psdDevice{ "hopsds" }; /**< The INDI device name of the PSD calculator. Defaults to
789 aolN_modevalPSDs where N is m_loopNum.*/
790
791 std::string m_opticalGainDevice{ "strehl" };
792 std::string m_opticalGainProperty{ "strehl_optimal" };
793 std::string m_opticalGainElement{ "pyramid" };
794
795 bool m_autoUpdate{ false }; ///< Flag controlling whether gains are automatically updated
796 bool m_opticalGainUpdate{ false }; ///< Flag controlling whether optical gain is
797 ///< automatically updated;
798
799 float m_gainGain{ 0.1 }; ///< The gain to use for SI gain correction updates. Default is 0.1.
800 float m_gainLeak{ 0.9 }; ///< The leak factor used for SI gain integration. Default is 0.9.
801 processPsdProcessorT::processModelConfig m_extrapConfig; ///< Configuration of the OL PSD extrapolation model.
802
803 uint32_t m_maxNCoeff{ 1000 };
804
805 uint32_t m_defaultNCoeff{ 25 };
806
807 int m_extrapOL{ c_olProcessNone }; ///< Which extrapolation method to use for the OL PSD.
808 int m_extrapNoiseEstimateDomain{ c_extrapNoiseEstimateOpenLoop }; ///< Where to estimate the modal noise
809 ///< floor.
810 int m_extrapNoiseEstimateRange{ c_extrapNoiseEstimateHighFreq }; ///< Which PSD end to use for the noise
811 ///< fit.
812 int m_extrapNoiseEstimateStatistic{ c_extrapNoiseEstimatePercentile }; ///< How the selected PSD bins are
813 ///< summarized into a noise floor.
814 int m_extrapClosedLoopOlEstimateMethod{ c_extrapClosedLoopOlEstimateEtfOnly }; ///< Which CL-to-OL reconstruction
815 ///< to use.
816 int m_extrapPowerLawCrossoverMode{ c_extrapPowerLawCrossoverManual }; ///< How the power-law match/cutoff
817 ///< frequencies are chosen.
818
819 ///@}
820
821 uint32_t m_nFreq{ 0 };
822 uint32_t m_nModes{ 0 };
823
824 bool m_updateOnce{ false }; ///< Flag to trigger a single update with gain.
825
826 bool m_dump{ false }; ///< Flag to trigger a single update with no gain.
827 bool m_zeroGains{ false }; ///< Flag requesting the SI gain integrator state be zeroed.
828
829 float m_fps{ 0 };
830
831 /// Each mode gets its own gain optimizer
832 std::vector<mx::AO::analysis::clGainOpt<float>> m_goptCurrent;
833 std::vector<mx::AO::analysis::clGainOpt<float>> m_goptSI;
834 std::vector<mx::AO::analysis::clGainOpt<float>> m_goptLP;
835 std::vector<mx::AO::analysis::clAOLinearPredictor<float>> m_linPred;
836
837 bool m_goptUpdated{ true }; ///< Tracks if a parameter has updated requiring
838 ///< updates to the m_gopt entries.
839 bool m_pcgoptUpdated{ true }; ///< Tracks if a parameter has updated requiring
840 ///< updates to the m_gopt entries.
841
842 bool m_freqUpdated{ true }; /**< Tracks if the frequency scale has updated, which necessitates
843 additional calcs. If true, implies m_goptUpdate == true.*/
844 float m_psdTime{ 1 };
845 float m_psdAvgTime{ 10 };
846 float m_psdOverlapFraction{ 0.5 };
847
848 std::vector<float> m_freq;
849
850 mx::improc::eigenImage<float> m_clPSDs;
851 mx::improc::eigenImage<float> m_clXferCurrent; ///< Published current closed-loop error transfer
852 ///< function.
853 mx::improc::eigenImage<float> m_clNtfCurrent; ///< Published current closed-loop noise transfer
854 ///< function.
855 mx::improc::eigenImage<float> m_clXferSI; ///< Published simple-integrator closed-loop error transfer
856 ///< function.
857 mx::improc::eigenImage<float> m_clNtfSI; ///< Published simple-integrator closed-loop noise transfer
858 ///< function.
859 mx::improc::eigenImage<float> m_clXferLP; ///< Published predictive closed-loop error transfer function.
860 mx::improc::eigenImage<float> m_clNtfLP; ///< Published predictive closed-loop noise transfer function.
861
862 std::vector<std::vector<float>> m_olPSDs;
863 std::vector<std::vector<float>> m_rawOlPSDs;
864 std::vector<std::vector<float>> m_smoothOlPSDs;
865 std::vector<std::vector<float>> m_nPSDs;
866 std::vector<float> m_modeVarCL;
867 std::vector<float> m_modeVarOL;
868
870
871 std::vector<float> m_optGainSIRaw; ///< The raw SI optimal gains before leaky integration.
872 std::vector<float> m_optGainSI; ///< The leaky-integrated SI optimal gains.
873 std::vector<float> m_gmaxSI; ///< The previously calculated maximum gains for SI.
874 std::vector<float> m_modeVarSI;
875 std::vector<int> m_timesOnSI;
877 bool m_siGainStateNeedsSync{ true }; ///< Tracks whether the SI gain integrator state should be synced from the
878 ///< applied gain factors.
879
880 std::vector<float> m_optGainLP;
881 std::vector<float> m_gmaxLP; ///< The previously calculated maximum gains for LP.
882 std::vector<float> m_modeVarLP;
883 std::vector<int> m_timesOnLP;
885
886 bool m_loop{ false };
887
888 float m_opticalGain{ 1 };
889
890 float m_opticalGainSource{ 1 };
891
892 float m_gain{ 0 };
893
894 float m_mult{ 1 };
895
896 float m_siGain{ 0 };
897
898 float m_siMult{ 1 };
899
900 bool m_doPCCalcs{ true };
901
902 float m_pcGain{ 0 };
903
904 float m_pcMult{ 0 };
905
906 bool m_pcOn{ false };
907
908 std::vector<float> m_gainFacts;
909
910 std::vector<float> m_multFacts;
911
912 std::vector<float> m_pcGainFacts;
913
914 std::vector<float> m_pcMultFacts;
915
916 std::vector<uint32_t> m_Na; // The latest user specified number of a coefficients
917
918 std::vector<uint32_t> m_NaCurrent; // The current number of a coefficients
919
920 std::vector<uint32_t> m_Nb; // The latest user specified number of b coefficients
921
922 std::vector<uint32_t> m_NbCurrent; // The current number of b coefficients
923
924 eigenImage<float> m_as;
925
926 eigenImage<float> m_bs;
927
928 int m_nRegCycles{ 60 }; ///< How often to regularize each mode
929
930 std::vector<int> m_regCounter; ///< Counters to track when this mode was last regularized
931
932 std::vector<float> m_regScale; ///< The regularization scale factors for each mode
933
934 std::vector<float> m_gainCals;
935
936 std::vector<float> m_gainCalFacts;
937
938 std::vector<float> m_taus;
939
940 eigenImage<float> m_noiseParams;
941
942 eigenImage<float> m_wfsavg;
943 eigenImage<float> m_wfsmask;
944 float m_counts{ 0 };
945 float m_emg{ 1 };
946 int m_npix{ 0 };
947
948 int m_sinceChange{ -1 };
949
950 std::string m_olPSDShmimName;
960
965
968
970
971 IMAGE *m_olPSDStream{ nullptr }; ///< The ImageStreamIO shared memory buffer to
972 ///< publish the open loop PSDs
973 IMAGE *m_rawOlPSDStream{ nullptr }; ///< The ImageStreamIO shared memory buffer
974 ///< to publish the raw OL PSDs
975 IMAGE *m_smoothOlPSDStream{ nullptr }; ///< The ImageStreamIO shared memory buffer to publish the
976 ///< smoothed OL PSDs
977 IMAGE *m_noisePSDStream{ nullptr }; ///< The ImageStreamIO shared memory buffer
978 ///< to publish the noise PSDs
979 IMAGE *m_clXferCurrentStream{ nullptr }; ///< The ImageStreamIO shared memory
980 ///< buffer to publish the current ETF
981 IMAGE *m_clNtfCurrentStream{ nullptr }; ///< The ImageStreamIO shared memory
982 ///< buffer to publish the current NTF
983 IMAGE *m_clXferSIStream{ nullptr }; ///< The ImageStreamIO shared memory buffer
984 ///< to publish the SI ETF
985 IMAGE *m_clNtfSIStream{ nullptr }; ///< The ImageStreamIO shared memory buffer
986 ///< to publish the SI NTF
987 IMAGE *m_clXferLPStream{ nullptr }; ///< The ImageStreamIO shared memory buffer
988 ///< to publish the LP ETF
989 IMAGE *m_clNtfLPStream{ nullptr }; ///< The ImageStreamIO shared memory buffer
990 ///< to publish the LP NTF
991
992 IMAGE *m_optGainStream{ nullptr }; ///< The ImageStreamIO shared memory buffer
993 ///< to publish the current optimal gains
994
995 IMAGE *m_optGainSIRawStream{ nullptr }; ///< The ImageStreamIO shared memory buffer
996 ///< to publish the raw SI optimal gains
997 IMAGE *m_optGainSIStream{ nullptr }; ///< The ImageStreamIO shared memory buffer
998 ///< to publish the integrated SI optimal gains
999 IMAGE *m_maxGainSIStream{ nullptr }; ///< The ImageStreamIO shared memory buffer
1000 ///< to publish the SI max gains
1001
1002 IMAGE *m_optGainLPStream{ nullptr }; ///< The ImageStreamIO shared memory buffer
1003 ///< to publish the LP optimal gains
1004 IMAGE *m_maxGainLPStream{ nullptr }; ///< The ImageStreamIO shared memory buffer
1005 ///< to publish the LP max gains
1006
1007 IMAGE *m_modevarStream{ nullptr }; ///< The ImageStreamIO shared memory buffer
1008 ///< to publish the mode variances
1009
1010 /// Destroy an owned ImageStreamIO output stream and clear its pointer.
1011 void destroyImageStream( IMAGE *&stream /**< [in.out] stream pointer to destroy and clear */ );
1012
1013 /// Allocate and create an owned ImageStreamIO output stream.
1014 int createImageStream( IMAGE *&stream, /**< [in.out] stream pointer to allocate and create */
1015 const std::string &name, /**< [in] shmim name for the output stream */
1016 uint32_t size0, /**< [in] first axis size */
1017 uint32_t size1, /**< [in] second axis size */
1018 uint32_t size2, /**< [in] third axis size */
1019 uint8_t dataType /**< [in] ImageStreamIO datatype for the stream */
1020 );
1021
1022 /// Populate the published gain and variance arrays from the current
1023 /// optimization state.
1024 void writePublishedGainArrays( float *currentData, /**< [out] current optimal-gain stream buffer */
1025 float *siRawData, /**< [out] raw SI optimal-gain stream buffer */
1026 float *siData, /**< [out] integrated SI optimal-gain stream buffer */
1027 float *maxSiData, /**< [out] SI max-gain stream buffer */
1028 float *lpData, /**< [out] LP optimal-gain stream buffer */
1029 float *maxLpData, /**< [out] LP max-gain stream buffer */
1030 float *modeVarData /**< [out] mode-variance buffer, laid out as 3 x N */
1031 );
1032
1033 /// Populate the published predictive-control gain and coefficient arrays.
1034 void writePublishedPredictorArrays( float *pcGainData, /**< [in.out] PC gain-factor stream buffer */
1035 float *aCoeffData, /**< [in.out] predictor a-coefficient stream buffer */
1036 uint32_t aWidth, /**< [in] entries stored per mode in aCoeffData */
1037 float *bCoeffData, /**< [in.out] predictor b-coefficient stream buffer */
1038 uint32_t bWidth, /**< [in] entries stored per mode in bCoeffData */
1039 bool blend /**< [in] when true, blend against existing values */
1040 );
1041
1042 /// Count how many modes are enabled by a gain-factor vector.
1043 int countEnabledGainFactors( const std::vector<float> &gainFacts /**< [in] gain factors to inspect */ ) const;
1044
1045 /// Update `m_modesOn` when a changed gain-factor stream matches the active
1046 /// control path.
1047 void updateAppliedModeCount( const std::vector<float> &gainFacts, /**< [in] gain factors from the changed stream */
1048 bool predictorPath /**< [in] true when the values came from the predictor
1049 path */
1050 );
1051
1052 /// Apply an incoming gain-factor frame to one of the stored gain vectors.
1053 bool applyGainFactorUpdate( std::vector<float> &gainFacts, /**< [in.out] stored gain factors to resize and update */
1054 const float *incoming, /**< [in] incoming gain-factor frame */
1055 uint32_t width, /**< [in] number of gain factors in `incoming` */
1056 bool predictorPath /**< [in] true when the values came from the predictor
1057 path */
1058 );
1059
1060 /// Apply an incoming multiplier frame to one of the stored multiplier
1061 /// vectors.
1062 bool applyMultiplierUpdate( std::vector<float> &multFacts, /**< [in.out] stored multiplier factors to
1063 resize and update */
1064 const float *incoming, /**< [in] incoming multiplier frame */
1065 uint32_t width, /**< [in] number of multiplier factors in `incoming` */
1066 bool predictorPath /**< [in] true when the values came from the predictor
1067 path */
1068 );
1069
1070 /// Apply an incoming frequency frame to the stored frequency scale.
1071 bool applyFrequencyUpdate( const float *incoming, /**< [in] incoming frequency frame */
1072 size_t size /**< [in] number of frequency samples in `incoming` */
1073 );
1074
1075 /// Refresh gain-optimization structures after coefficient, multiplier, or
1076 /// frequency changes.
1077 /** The gain-optimization mutex must be locked before calling this helper.
1078 *
1079 * \returns true when a structure refresh was performed
1080 * \returns false when no refresh was needed
1081 */
1082 bool refreshGoptStructures();
1083
1084 /// Synchronize the integrated SI gain state from the applied gain-factor stream.
1085 void syncSiGainStateFromAppliedGains();
1086
1087 /// Apply one SI leaky-integrator update from the raw optimal gain.
1088 void updateIntegratedSiGain( size_t modeIndex );
1089
1090 /// Handle a standard target/current numeric extrapolation property update.
1091 template <typename valueT>
1092 int handleExtrapNumberProperty( pcf::IndiProperty &localProperty,
1093 valueT &localTarget,
1094 const pcf::IndiProperty &ipRecv,
1095 const std::string &label );
1096
1097 /// Handle a boolean extrapolation toggle property update.
1098 int handleExtrapToggleProperty( pcf::IndiProperty &localProperty,
1099 bool &localTarget,
1100 const pcf::IndiProperty &ipRecv,
1101 const std::string &label );
1102
1103 /// Handle the extrapolation-method selection switch property.
1104 int handleExtrapMethodProperty( const pcf::IndiProperty &ipRecv );
1105
1106 /// Handle the noise-estimation-domain selection switch property.
1107 int handleExtrapNoiseEstimateDomainProperty( const pcf::IndiProperty &ipRecv );
1108
1109 /// Handle the noise-estimation-range selection switch property.
1110 int handleExtrapNoiseEstimateRangeProperty( const pcf::IndiProperty &ipRecv );
1111
1112 /// Handle the noise-estimation-statistic selection switch property.
1113 int handleExtrapNoiseEstimateStatisticProperty( const pcf::IndiProperty &ipRecv );
1114
1115 /// Handle the closed-loop OL-estimation-method selection switch property.
1116 int handleExtrapClosedLoopOlEstimateMethodProperty( const pcf::IndiProperty &ipRecv );
1117
1118 /// Handle the power-law crossover-mode selection switch property.
1119 int handleExtrapPowerLawCrossoverModeProperty( const pcf::IndiProperty &ipRecv );
1120
1121 public:
1122 /// Default c'tor.
1123 modalGainOpt();
1124
1125 /// D'tor, declared and defined for noexcept.
1126 ~modalGainOpt() noexcept
1127 {
1128 }
1129
1130 virtual void setupConfig();
1131
1132 /// Implementation of loadConfig logic, separated for testing.
1133 /** This is called by loadConfig().
1134 */
1135 int loadConfigImpl( mx::app::appConfigurator &_config /**< [in] an application configuration
1136 from which to load values*/ );
1137
1138 virtual void loadConfig();
1139
1140 /// Startup function
1141 /**
1142 *
1143 */
1144 virtual int appStartup();
1145
1146 /// Implementation of the FSM for modalGainOpt.
1147 /**
1148 * \returns 0 on no critical error
1149 * \returns -1 on an error requiring shutdown
1150 */
1151 virtual int appLogic();
1152
1153 /// Shutdown the app.
1154 /**
1155 *
1156 */
1157 virtual int appShutdown();
1158
1159 int allocatePCShmims();
1160
1161 int allocate( const psdShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1162 );
1163
1164 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
1165 const psdShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1166 );
1167
1168 int allocate( const freqShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1169 );
1170
1171 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
1172 const freqShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1173 );
1174
1175 int allocate( const gainFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1176 );
1177
1178 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
1179 const gainFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1180 );
1181
1182 int allocate( const multFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1183 );
1184
1185 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
1186 const multFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1187 );
1188
1189 int allocate( const pcGainFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1190 );
1191
1192 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
1193 const pcGainFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1194 );
1195
1196 int allocate( const pcMultFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1197 );
1198
1199 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
1200 const pcMultFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1201 );
1202
1203 int allocate( const numpccoeffShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1204 );
1205
1206 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
1207 const numpccoeffShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1208 );
1209
1210 int allocate( const acoeffShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1211 );
1212
1213 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
1214 const acoeffShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1215 );
1216
1217 int allocate( const bcoeffShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1218 );
1219
1220 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
1221 const bcoeffShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1222 );
1223
1224 int allocate( const gainCalShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1225 );
1226
1227 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
1228 const gainCalShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1229 );
1230
1231 int allocate( const gainCalFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1232 );
1233
1234 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
1235 const gainCalFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1236 );
1237
1238 int allocate( const tauShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1239 );
1240
1241 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
1242 const tauShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1243 );
1244
1245 int allocate( const noiseShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1246 );
1247
1248 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
1249 const noiseShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1250 );
1251
1252 int allocate( const wfsavgShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1253 );
1254
1255 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
1256 const wfsavgShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1257 );
1258
1259 int allocate( const wfsmaskShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1260 );
1261
1262 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
1263 const wfsmaskShmimT & ///< [in] tag to differentiate shmimMonitor parents.
1264 );
1265
1266 /// Check that all sizes and allocations have occurred
1267 int checkSizes();
1268
1269 protected:
1270 /// Mutex for synchronizing updates.
1271 std::mutex m_goptMutex;
1272
1273 /// Flag used to indicate to the goptThread that it should stop calculations
1274 /// ASAP
1275 std::atomic<bool> m_updating{ false };
1276
1277 /** \name Gain Optimization Thread
1278 *
1279 * @{
1280 */
1281 int m_goptThreadPrio{ 0 }; ///< Priority of the gain optimization thread.
1282
1283 std::string m_goptThreadCpuset; ///< The cpuset to use for the gain
1284 ///< optimization thread.
1285
1286 std::thread m_goptThread; ///< The gain optimization thread.
1287
1288 bool m_goptThreadInit{ true }; ///< Initialization flag for the gain optimization thread.
1289
1290 pid_t m_goptThreadID{ 0 }; ///< gain optimization thread PID.
1291
1292 pcf::IndiProperty m_goptThreadProp; ///< The property to hold the gain
1293 ///< optimization thread details.
1294
1295 sem_t m_goptSemaphore; ///< Semaphore used to synchronize the psdShmim thread
1296 ///< and the gopt thread.
1297 bool m_goptSemaphoreInit{ false }; ///< Tracks whether the gain optimization semaphore needs cleanup.
1298
1299 float noisePSD( int n );
1300
1301 /// Gain Optimization thread starter function
1302 static void goptThreadStart( modalGainOpt *p /**< [in] pointer to this */ );
1303
1304 /// Gain optimization thread function
1305 /** Runs until m_shutdown is true.
1306 */
1307 void goptThreadExec();
1308
1309 ///@}
1310
1311 public:
1312 /** \name INDI
1313 * @{
1314 */
1315
1316 pcf::IndiProperty m_indiP_autoUpdate;
1317 pcf::IndiProperty m_indiP_updateOnce;
1318 pcf::IndiProperty m_indiP_dump;
1319
1320 pcf::IndiProperty m_indiP_opticalGain;
1321
1322 pcf::IndiProperty m_indiP_gainGain;
1323 pcf::IndiProperty m_indiP_gainLeak;
1324 pcf::IndiProperty m_indiP_zeroGains;
1325 pcf::IndiProperty m_indiP_extrapMethod;
1350
1351 pcf::IndiProperty m_indiP_emg;
1352 pcf::IndiProperty m_indiP_psdTime;
1353 pcf::IndiProperty m_indiP_psdAvgTime;
1354 pcf::IndiProperty m_indiP_loop;
1355 pcf::IndiProperty m_indiP_siGain;
1356 pcf::IndiProperty m_indiP_siMult;
1357 pcf::IndiProperty m_indiP_pcGain;
1358 pcf::IndiProperty m_indiP_pcMult;
1359 pcf::IndiProperty m_indiP_pcOn;
1360
1361 pcf::IndiProperty m_indiP_modesOn;
1362
1363 pcf::IndiProperty m_indiP_opticalGainSource;
1364 pcf::IndiProperty m_indiP_opticalGainUpdate;
1365
1366 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_autoUpdate );
1367 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_updateOnce );
1369 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_opticalGain );
1373 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapMethod );
1374 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapNoiseEstimateDomain );
1375 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapNoiseEstimateRange );
1376 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapNoiseEstimateStatistic );
1377 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapNoiseEstimateLowFreqMaxHz );
1378 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapClosedLoopOlEstimateMethod );
1379 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapPowerLawIndex );
1380 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapPowerLawNormFreq );
1381 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapPowerLawMatchFreq );
1382 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapPowerLawMatchFallbackWindowHz );
1383 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapPowerLawCrossoverMode );
1384 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapPowerLawAutoSmoothWidthHz );
1385 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapPowerLawAutoMaxFreqFraction );
1386 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapFitPowerLawIndex );
1387 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapPowerLawOnlyAboveFreq );
1388 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapPowerLawFitIncludesMatchPoint );
1389 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapPowerLawFitMinFreqHz );
1390 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapPowerLawFitMaxFreqHz );
1391 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapPowerLawFitBinWidthHz );
1392 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapPowerLawBlendBins );
1393 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapDropoutGapFactor );
1394 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapDropoutTinyFactor );
1395 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapDropoutMaxBins );
1396 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapClSignificanceThreshold );
1397 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_extrapClMinSignificantFraction );
1400 INDI_SETCALLBACK_DECL( modalGainOpt, m_indiP_psdAvgTime );
1407
1408 INDI_SETCALLBACK_DECL( modalGainOpt, m_indiP_opticalGainSource );
1409 INDI_NEWCALLBACK_DECL( modalGainOpt, m_indiP_opticalGainUpdate );
1410
1411 /** \name Telemeter Interface
1412 *
1413 * @{
1414 */
1415 int checkRecordTimes();
1416
1417 int recordTelem( const telem_modalgainopt * );
1418
1419 int recordModalGainOpt( bool force = false );
1420
1421 ///@}
1422
1423 ///@}
1424};
1425
1446
1448{
1449 config.add( "loop.number",
1450 "",
1451 "loop.number",
1452 argType::Required,
1453 "loop",
1454 "number",
1455 false,
1456 "int",
1457 "The number of the loop. Used to set shmim names, as in aolN_mgainfact." );
1458
1459 config.add( "loop.name",
1460 "",
1461 "loop.name",
1462 argType::Required,
1463 "loop",
1464 "name",
1465 false,
1466 "string",
1467 "The name of the loop control INDI device name." );
1468
1469 config.add( "loop.psdDev",
1470 "",
1471 "loop.psdDev",
1472 argType::Required,
1473 "loop",
1474 "psdDev",
1475 false,
1476 "string",
1477 "The INDI device name of the PSD calculator. Defaults to "
1478 "aolN_modevalPSDs where N is loop.number." );
1479
1480 config.add( "loop.autoUpdate",
1481 "",
1482 "loop.autoUpdate",
1483 argType::Required,
1484 "loop",
1485 "autoUpdate",
1486 false,
1487 "bool",
1488 "Flag controlling whether the gains are auto updated. Also "
1489 "settable via INDI." );
1490
1491 config.add( "loop.gainGain",
1492 "",
1493 "loop.gainGain",
1494 argType::Required,
1495 "loop",
1496 "gainGain",
1497 false,
1498 "float",
1499 "The gain to use for closed-loop gain updates. Default is 0.1" );
1500
1501 config.add( "loop.gainLeak",
1502 "",
1503 "loop.gainLeak",
1504 argType::Required,
1505 "loop",
1506 "gainLeak",
1507 false,
1508 "float",
1509 "The leak factor to use for SI optimal-gain integration. Default is 0.9" );
1510
1511 config.add( "extrapolation.method",
1512 "",
1513 "extrapolation.method",
1514 argType::Required,
1515 "extrapolation",
1516 "method",
1517 false,
1518 "string",
1519 "The OL PSD extrapolation method: none, legacy, power_law_only, "
1520 "or moffat_peaks." );
1521
1522 config.add( "extrapolation.noiseEstimateDomain",
1523 "",
1524 "extrapolation.noiseEstimateDomain",
1525 argType::Required,
1526 "extrapolation",
1527 "noiseEstimateDomain",
1528 false,
1529 "string",
1530 "Where to estimate the flat noise floor: open_loop or "
1531 "closed_loop_pre_xfer." );
1532
1533 config.add( "extrapolation.noiseEstimateRange",
1534 "",
1535 "extrapolation.noiseEstimateRange",
1536 argType::Required,
1537 "extrapolation",
1538 "noiseEstimateRange",
1539 false,
1540 "string",
1541 "Which end of the PSD is used for noise estimation: high_freq or "
1542 "low_freq." );
1543
1544 config.add( "extrapolation.noiseEstimateStatistic",
1545 "",
1546 "extrapolation.noiseEstimateStatistic",
1547 argType::Required,
1548 "extrapolation",
1549 "noiseEstimateStatistic",
1550 false,
1551 "string",
1552 "How to summarize the selected noise-estimation bins: percentile "
1553 "or minimum." );
1554
1555 config.add( "extrapolation.noiseEstimateLowFreqMaxHz",
1556 "",
1557 "extrapolation.noiseEstimateLowFreqMaxHz",
1558 argType::Required,
1559 "extrapolation",
1560 "noiseEstimateLowFreqMaxHz",
1561 false,
1562 "float",
1563 "For low_freq noise estimation, the maximum frequency in Hz to "
1564 "include. Set to 0 to disable." );
1565
1566 config.add( "extrapolation.closedLoopOlEstimateMethod",
1567 "",
1568 "extrapolation.closedLoopOlEstimateMethod",
1569 argType::Required,
1570 "extrapolation",
1571 "closedLoopOlEstimateMethod",
1572 false,
1573 "string",
1574 "How to reconstruct OL PSD from CL PSD: etf_only or ntf_aware." );
1575
1576 config.add( "extrapolation.powerLawIndex",
1577 "",
1578 "extrapolation.powerLawIndex",
1579 argType::Required,
1580 "extrapolation",
1581 "powerLawIndex",
1582 false,
1583 "float",
1584 "The power-law exponent a in the 1/f^a continuum model." );
1585
1586 config.add( "extrapolation.powerLawNormFreq",
1587 "",
1588 "extrapolation.powerLawNormFreq",
1589 argType::Required,
1590 "extrapolation",
1591 "powerLawNormFreq",
1592 false,
1593 "float",
1594 "The power-law normalization frequency in Hz. Set to 0 to use the "
1595 "first positive bin." );
1596
1597 config.add( "extrapolation.powerLawMatchFreq",
1598 "",
1599 "extrapolation.powerLawMatchFreq",
1600 argType::Required,
1601 "extrapolation",
1602 "powerLawMatchFreq",
1603 false,
1604 "float",
1605 "The frequency in Hz where the extrapolated power law is forced "
1606 "to match the measured PSD." );
1607
1608 config.add( "extrapolation.powerLawMatchFallbackWindowHz",
1609 "",
1610 "extrapolation.powerLawMatchFallbackWindowHz",
1611 argType::Required,
1612 "extrapolation",
1613 "powerLawMatchFallbackWindowHz",
1614 false,
1615 "float",
1616 "Half-width in Hz of the local fallback window used when the "
1617 "match bin falls in a trough." );
1618
1619 config.add( "extrapolation.powerLawCrossoverMode",
1620 "",
1621 "extrapolation.powerLawCrossoverMode",
1622 argType::Required,
1623 "extrapolation",
1624 "powerLawCrossoverMode",
1625 false,
1626 "string",
1627 "How the power-law match/cutoff frequencies are chosen: manual or "
1628 "auto_smoothed_crossing." );
1629
1630 config.add( "extrapolation.powerLawAutoSmoothWidthHz",
1631 "",
1632 "extrapolation.powerLawAutoSmoothWidthHz",
1633 argType::Required,
1634 "extrapolation",
1635 "powerLawAutoSmoothWidthHz",
1636 false,
1637 "float",
1638 "Median-smoothing width in Hz used when auto power-law crossover "
1639 "selection is enabled." );
1640
1641 config.add( "extrapolation.powerLawAutoMaxFreqFraction",
1642 "",
1643 "extrapolation.powerLawAutoMaxFreqFraction",
1644 argType::Required,
1645 "extrapolation",
1646 "powerLawAutoMaxFreqFraction",
1647 false,
1648 "float",
1649 "Maximum searched frequency for auto power-law crossover as a "
1650 "fraction of the sampled maximum frequency. Set to 0 to disable "
1651 "the cap." );
1652
1653 config.add( "extrapolation.fitPowerLawIndex",
1654 "",
1655 "extrapolation.fitPowerLawIndex",
1656 argType::Required,
1657 "extrapolation",
1658 "fitPowerLawIndex",
1659 false,
1660 "bool",
1661 "Whether to fit the power-law index from the high-frequency "
1662 "disturbance PSD bins." );
1663
1664 config.add( "extrapolation.powerLawOnlyAboveFreq",
1665 "",
1666 "extrapolation.powerLawOnlyAboveFreq",
1667 argType::Required,
1668 "extrapolation",
1669 "powerLawOnlyAboveFreq",
1670 false,
1671 "float",
1672 "Above this frequency in Hz, force the extrapolation to be "
1673 "power-law only." );
1674
1675 config.add( "extrapolation.powerLawFitIncludesMatchPoint",
1676 "",
1677 "extrapolation.powerLawFitIncludesMatchPoint",
1678 argType::Required,
1679 "extrapolation",
1680 "powerLawFitIncludesMatchPoint",
1681 false,
1682 "bool",
1683 "Whether to include the explicit match point directly in the "
1684 "power-law exponent fit." );
1685
1686 config.add( "extrapolation.powerLawFitMinFreqHz",
1687 "",
1688 "extrapolation.powerLawFitMinFreqHz",
1689 argType::Required,
1690 "extrapolation",
1691 "powerLawFitMinFreqHz",
1692 false,
1693 "float",
1694 "The low edge in Hz of the power-law exponent fit range." );
1695
1696 config.add( "extrapolation.powerLawFitMaxFreqHz",
1697 "",
1698 "extrapolation.powerLawFitMaxFreqHz",
1699 argType::Required,
1700 "extrapolation",
1701 "powerLawFitMaxFreqHz",
1702 false,
1703 "float",
1704 "The high edge in Hz of the power-law exponent fit range." );
1705
1706 config.add( "extrapolation.powerLawFitBinWidthHz",
1707 "",
1708 "extrapolation.powerLawFitBinWidthHz",
1709 argType::Required,
1710 "extrapolation",
1711 "powerLawFitBinWidthHz",
1712 false,
1713 "float",
1714 "The width in Hz of the median bins used in the power-law exponent fit." );
1715
1716 config.add( "extrapolation.powerLawBlendBins",
1717 "",
1718 "extrapolation.powerLawBlendBins",
1719 argType::Required,
1720 "extrapolation",
1721 "powerLawBlendBins",
1722 false,
1723 "int",
1724 "The number of bins used to blend between the measured PSD and "
1725 "the extrapolated continuum." );
1726
1727 config.add( "extrapolation.peakDetectWidthHz",
1728 "",
1729 "extrapolation.peakDetectWidthHz",
1730 argType::Required,
1731 "extrapolation",
1732 "peakDetectWidthHz",
1733 false,
1734 "float",
1735 "The wide smoothing width in Hz used for peak detection." );
1736
1737 config.add( "extrapolation.peakDetectFactor",
1738 "",
1739 "extrapolation.peakDetectFactor",
1740 argType::Required,
1741 "extrapolation",
1742 "peakDetectFactor",
1743 false,
1744 "float",
1745 "The factor above the smoothed PSD required for a strong peak "
1746 "detection." );
1747
1748 config.add( "extrapolation.peakDetectBroadFactor",
1749 "",
1750 "extrapolation.peakDetectBroadFactor",
1751 argType::Required,
1752 "extrapolation",
1753 "peakDetectBroadFactor",
1754 false,
1755 "float",
1756 "The lower factor above the smoothed PSD used for broad-peak "
1757 "candidates." );
1758
1759 config.add( "extrapolation.peakDetectMinWidthLog",
1760 "",
1761 "extrapolation.peakDetectMinWidthLog",
1762 argType::Required,
1763 "extrapolation",
1764 "peakDetectMinWidthLog",
1765 false,
1766 "float",
1767 "The minimum accepted broad-peak width in log-frequency." );
1768
1769 config.add( "extrapolation.peakDetectPasses",
1770 "",
1771 "extrapolation.peakDetectPasses",
1772 argType::Required,
1773 "extrapolation",
1774 "peakDetectPasses",
1775 false,
1776 "int",
1777 "The number of iterative subtract-and-redetect peak-detection passes." );
1778
1779 config.add( "extrapolation.peakMoffatBeta",
1780 "",
1781 "extrapolation.peakMoffatBeta",
1782 argType::Required,
1783 "extrapolation",
1784 "peakMoffatBeta",
1785 false,
1786 "float",
1787 "The minimum Moffat beta used when synthesizing extrapolated peaks." );
1788
1789 config.add( "extrapolation.dropoutGapFactor",
1790 "",
1791 "extrapolation.dropoutGapFactor",
1792 argType::Required,
1793 "extrapolation",
1794 "dropoutGapFactor",
1795 false,
1796 "float",
1797 "The relative depth threshold used to identify PSD dropouts for repair." );
1798
1799 config.add( "extrapolation.dropoutTinyFactor",
1800 "",
1801 "extrapolation.dropoutTinyFactor",
1802 argType::Required,
1803 "extrapolation",
1804 "dropoutTinyFactor",
1805 false,
1806 "float",
1807 "The maximum fraction of the local good-bin scale allowed for a "
1808 "candidate dropout run to be considered truly tiny." );
1809
1810 config.add( "extrapolation.dropoutMaxBins",
1811 "",
1812 "extrapolation.dropoutMaxBins",
1813 argType::Required,
1814 "extrapolation",
1815 "dropoutMaxBins",
1816 false,
1817 "int",
1818 "The maximum consecutive dropout-run length that will be repaired." );
1819
1820 config.add( "extrapolation.clSignificanceThreshold",
1821 "",
1822 "extrapolation.clSignificanceThreshold",
1823 argType::Required,
1824 "extrapolation",
1825 "clSignificanceThreshold",
1826 false,
1827 "float",
1828 "The multiplier above the fitted raw CL noise floor required "
1829 "for a PSD bin to be considered significant." );
1830
1831 config.add( "extrapolation.clMinSignificantFraction",
1832 "",
1833 "extrapolation.clMinSignificantFraction",
1834 argType::Required,
1835 "extrapolation",
1836 "clMinSignificantFraction",
1837 false,
1838 "float",
1839 "The minimum fraction of raw CL PSD bins that must exceed the "
1840 "significance threshold for a mode to remain active." );
1841
1857
1858 telemeterT::setupConfig( config );
1859}
1860
1861int modalGainOpt::loadConfigImpl( mx::app::appConfigurator &_config )
1862{
1863 _config( m_loopNum, "loop.number" );
1864 _config( m_loopName, "loop.name" );
1865 _config( m_autoUpdate, "loop.autoUpdate" );
1866 _config( m_gainGain, "loop.gainGain" );
1867 _config( m_gainLeak, "loop.gainLeak" );
1868
1870 _config( extrapMethod, "extrapolation.method" );
1873 _config( noiseEstimateDomain, "extrapolation.noiseEstimateDomain" );
1877 _config( noiseEstimateRange, "extrapolation.noiseEstimateRange" );
1881 _config( noiseEstimateStatistic, "extrapolation.noiseEstimateStatistic" );
1884 _config( m_extrapConfig.m_noiseEstimateLowFreqMaxHz, "extrapolation.noiseEstimateLowFreqMaxHz" );
1886 _config( closedLoopOlEstimateMethod, "extrapolation.closedLoopOlEstimateMethod" );
1890
1891 _config( m_extrapConfig.m_powerLawIndex, "extrapolation.powerLawIndex" );
1892 _config( m_extrapConfig.m_powerLawNormFreq, "extrapolation.powerLawNormFreq" );
1893 _config( m_extrapConfig.m_powerLawMatchFreq, "extrapolation.powerLawMatchFreq" );
1894 _config( m_extrapConfig.m_powerLawMatchFallbackWindowHz, "extrapolation.powerLawMatchFallbackWindowHz" );
1896 _config( powerLawCrossoverMode, "extrapolation.powerLawCrossoverMode" );
1899 _config( m_extrapConfig.m_powerLawAutoSmoothWidthHz, "extrapolation.powerLawAutoSmoothWidthHz" );
1900 _config( m_extrapConfig.m_powerLawAutoMaxFreqFraction, "extrapolation.powerLawAutoMaxFreqFraction" );
1901 _config( m_extrapConfig.m_fitPowerLawIndex, "extrapolation.fitPowerLawIndex" );
1902 _config( m_extrapConfig.m_powerLawOnlyAboveFreq, "extrapolation.powerLawOnlyAboveFreq" );
1903 _config( m_extrapConfig.m_powerLawFitIncludesMatchPoint, "extrapolation.powerLawFitIncludesMatchPoint" );
1904 _config( m_extrapConfig.m_powerLawFitMinFreqHz, "extrapolation.powerLawFitMinFreqHz" );
1905 _config( m_extrapConfig.m_powerLawFitMaxFreqHz, "extrapolation.powerLawFitMaxFreqHz" );
1906 _config( m_extrapConfig.m_powerLawFitBinWidthHz, "extrapolation.powerLawFitBinWidthHz" );
1907 _config( m_extrapConfig.m_powerLawBlendBins, "extrapolation.powerLawBlendBins" );
1908 _config( m_extrapConfig.m_peakDetectWidthHz, "extrapolation.peakDetectWidthHz" );
1909 _config( m_extrapConfig.m_peakDetectFactor, "extrapolation.peakDetectFactor" );
1910 _config( m_extrapConfig.m_peakDetectBroadFactor, "extrapolation.peakDetectBroadFactor" );
1911 _config( m_extrapConfig.m_peakDetectMinWidthLog, "extrapolation.peakDetectMinWidthLog" );
1912 _config( m_extrapConfig.m_peakDetectPasses, "extrapolation.peakDetectPasses" );
1913 _config( m_extrapConfig.m_peakMoffatBeta, "extrapolation.peakMoffatBeta" );
1914 _config( m_extrapConfig.m_dropoutGapFactor, "extrapolation.dropoutGapFactor" );
1915 _config( m_extrapConfig.m_dropoutTinyFactor, "extrapolation.dropoutTinyFactor" );
1916 _config( m_extrapConfig.m_dropoutMaxBins, "extrapolation.dropoutMaxBins" );
1917 _config( m_extrapConfig.m_clSignificanceThreshold, "extrapolation.clSignificanceThreshold" );
1918 _config( m_extrapConfig.m_clMinSignificantFraction, "extrapolation.clMinSignificantFraction" );
1919
1920 char shmim[1024];
1921
1922 _config( m_psdDevice, "loop.psdDev" );
1923
1924 snprintf( shmim, sizeof( shmim ), "aol%d_clpsds", m_loopNum );
1927
1928 snprintf( shmim, sizeof( shmim ), "aol%d_freq", m_loopNum );
1931
1932 snprintf( shmim, sizeof( shmim ), "aol%d_mgainfact", m_loopNum );
1935
1936 snprintf( shmim, sizeof( shmim ), "aol%d_mmultfact", m_loopNum );
1939
1940 snprintf( shmim, sizeof( shmim ), "aol%d_mpcgainfact", m_loopNum );
1943
1944 snprintf( shmim, sizeof( shmim ), "aol%d_mpcmultfact", m_loopNum );
1947
1948 snprintf( shmim, sizeof( shmim ), "aol%d_numpccoeff", m_loopNum );
1951
1952 snprintf( shmim, sizeof( shmim ), "aol%d_acoeff", m_loopNum );
1955
1956 snprintf( shmim, sizeof( shmim ), "aol%d_bcoeff", m_loopNum );
1959
1960 snprintf( shmim, sizeof( shmim ), "aol%d_mgaincal", m_loopNum );
1963
1964 snprintf( shmim, sizeof( shmim ), "aol%d_mgaincalfact", m_loopNum );
1967
1968 snprintf( shmim, sizeof( shmim ), "aol%d_looptau", m_loopNum );
1971
1972 snprintf( shmim, sizeof( shmim ), "aol%d_mnoiseparam", m_loopNum );
1975
1976 snprintf( shmim, sizeof( shmim ), "aol%d_wfsavg", m_loopNum );
1979
1980 snprintf( shmim, sizeof( shmim ), "aol%d_wfsmask", m_loopNum );
1983
1984 snprintf( shmim, sizeof( shmim ), "aol%d_olpsds", m_loopNum );
1985 m_olPSDShmimName = shmim;
1986
1987 snprintf( shmim, sizeof( shmim ), "aol%d_olpsds_raw", m_loopNum );
1988 m_rawOlPSDShmimName = shmim;
1989
1990 snprintf( shmim, sizeof( shmim ), "aol%d_olpsds_smooth", m_loopNum );
1991 m_smoothOlPSDShmimName = shmim;
1992
1993 snprintf( shmim, sizeof( shmim ), "aol%d_noisepsds", m_loopNum );
1994 m_noisePSDShmimName = shmim;
1995
1996 snprintf( shmim, sizeof( shmim ), "aol%d_clxferCurrent", m_loopNum );
1998
1999 snprintf( shmim, sizeof( shmim ), "aol%d_clntfCurrent", m_loopNum );
2001
2002 snprintf( shmim, sizeof( shmim ), "aol%d_clxferSI", m_loopNum );
2003 m_clXferSIShmimName = shmim;
2004
2005 snprintf( shmim, sizeof( shmim ), "aol%d_clntfSI", m_loopNum );
2006 m_clNtfSIShmimName = shmim;
2007
2008 snprintf( shmim, sizeof( shmim ), "aol%d_clxferLP", m_loopNum );
2009 m_clXferLPShmimName = shmim;
2010
2011 snprintf( shmim, sizeof( shmim ), "aol%d_clntfLP", m_loopNum );
2012 m_clNtfLPShmimName = shmim;
2013
2014 snprintf( shmim, sizeof( shmim ), "aol%d_mgainoptimal", m_loopNum );
2015 m_optGainShmimName = shmim;
2016
2017 snprintf( shmim, sizeof( shmim ), "aol%d_mgainoptimalSI_raw", m_loopNum );
2019
2020 snprintf( shmim, sizeof( shmim ), "aol%d_mgainoptimalSI", m_loopNum );
2021 m_optGainSIShmimName = shmim;
2022
2023 snprintf( shmim, sizeof( shmim ), "aol%d_mgainmaxSI", m_loopNum );
2024 m_maxGainSIShmimName = shmim;
2025
2026 snprintf( shmim, sizeof( shmim ), "aol%d_mgainoptimalLP", m_loopNum );
2027 m_optGainLPShmimName = shmim;
2028
2029 snprintf( shmim, sizeof( shmim ), "aol%d_mgainmaxLP", m_loopNum );
2030 m_maxGainLPShmimName = shmim;
2031
2032 snprintf( shmim, sizeof( shmim ), "aol%d_mmodevar", m_loopNum );
2033 m_modevarShmimName = shmim;
2034
2035 if( telemeterT::loadConfig( _config ) < 0 )
2036 {
2037 log<text_log>( "Error during telemeter config", logPrio::LOG_CRITICAL );
2038 m_shutdown = true;
2039 }
2040
2041 return 0;
2042}
2043
2045{
2046 loadConfigImpl( config );
2047}
2048
2050{
2051 if( telemeterT::appStartup() < 0 )
2052 {
2053 return log<software_error, -1>( { "error from telemeter appStartup" } );
2054 }
2055
2071
2076
2078 "opticalGain",
2079 0,
2080 1,
2081 0.01,
2082 "%0.01f",
2083 "Optical Gain",
2084 "Gain Opt." );
2085 CREATE_REG_INDI_NEW_NUMBERF( m_indiP_gainGain, "gainGain", 0, 1, 0.01, "%0.01f", "Gain Gain", "Gain Opt." );
2086 CREATE_REG_INDI_NEW_NUMBERF( m_indiP_gainLeak, "gainLeak", 0, 1, 0.01, "%0.02f", "Gain Leak", "Gain Opt." );
2088 "extrap_method",
2097 "Extrapolation Method",
2098 "Extrapolation" ) < 0 )
2099 {
2100 log<software_error>( { "error from createStandardIndiSelectionSw" } );
2101 return -1;
2102 }
2104 {
2105 log<software_error>( { "error from registerIndiPropertyNew" } );
2106 return -1;
2107 }
2109 "extrap_noiseEstimateDomain",
2114 "Noise Estimate Domain",
2115 "Extrapolation" ) < 0 )
2116 {
2117 log<software_error>( { "error from createStandardIndiSelectionSw" } );
2118 return -1;
2119 }
2122 {
2123 log<software_error>( { "error from registerIndiPropertyNew" } );
2124 return -1;
2125 }
2127 "extrap_noiseEstimateRange",
2132 "Noise Estimate Range",
2133 "Extrapolation" ) < 0 )
2134 {
2135 log<software_error>( { "error from createStandardIndiSelectionSw" } );
2136 return -1;
2137 }
2140 {
2141 log<software_error>( { "error from registerIndiPropertyNew" } );
2142 return -1;
2143 }
2145 "extrap_noiseEstimateStatistic",
2150 "Noise Estimate Statistic",
2151 "Extrapolation" ) < 0 )
2152 {
2153 log<software_error>( { "error from createStandardIndiSelectionSw" } );
2154 return -1;
2155 }
2158 {
2159 log<software_error>( { "error from registerIndiPropertyNew" } );
2160 return -1;
2161 }
2163 "extrap_noiseEstimateLowFreqMaxHz",
2164 0,
2165 10000,
2166 0.1,
2167 "%0.2f",
2168 "Noise Estimate Low-Freq Max",
2169 "Extrapolation" );
2172 "extrap_closedLoopOlEstimateMethod",
2177 "Closed Loop OL Estimate Method",
2178 "Extrapolation" ) < 0 )
2179 {
2180 log<software_error>( { "error from createStandardIndiSelectionSw" } );
2181 return -1;
2182 }
2185 {
2186 log<software_error>( { "error from registerIndiPropertyNew" } );
2187 return -1;
2188 }
2190 "extrap_powerLawIndex",
2191 0,
2192 10,
2193 0.01,
2194 "%0.3f",
2195 "Power-Law Index",
2196 "Extrapolation" );
2198 "extrap_powerLawNormFreq",
2199 0,
2200 10000,
2201 0.1,
2202 "%0.2f",
2203 "Power-Law Norm Freq",
2204 "Extrapolation" );
2206 "extrap_powerLawMatchFreq",
2207 0,
2208 10000,
2209 0.1,
2210 "%0.2f",
2211 "Power-Law Match Freq",
2212 "Extrapolation" );
2214 "extrap_powerLawMatchFallbackWindowHz",
2215 0,
2216 1000,
2217 0.1,
2218 "%0.2f",
2219 "Power-Law Match Window",
2220 "Extrapolation" );
2223 "extrap_powerLawCrossoverMode",
2228 "Power-Law Crossover Mode",
2229 "Extrapolation" ) < 0 )
2230 {
2231 log<software_error>( { "error from createStandardIndiSelectionSw" } );
2232 return -1;
2233 }
2236 {
2237 log<software_error>( { "error from registerIndiPropertyNew" } );
2238 return -1;
2239 }
2241 "extrap_powerLawAutoSmoothWidthHz",
2242 0,
2243 10000,
2244 0.1,
2245 "%0.2f",
2246 "Power-Law Auto Smooth Width",
2247 "Extrapolation" );
2249 "extrap_powerLawAutoMaxFreqFraction",
2250 0,
2251 1,
2252 0.01,
2253 "%0.3f",
2254 "Power-Law Auto Max Freq Fraction",
2255 "Extrapolation" );
2257 "extrap_fitPowerLawIndex",
2258 "Fit Power-Law Index",
2259 "Extrapolation" ) < 0 )
2260 {
2261 log<software_error>( { "error from createStandardIndiToggleSw" } );
2262 return -1;
2263 }
2265 0 )
2266 {
2267 log<software_error>( { "error from registerIndiPropertyNew" } );
2268 return -1;
2269 }
2271 "extrap_powerLawOnlyAboveFreq",
2272 0,
2273 10000,
2274 0.1,
2275 "%0.2f",
2276 "Power-Law Only Above",
2277 "Extrapolation" );
2279 "extrap_powerLawFitIncludesMatchPoint",
2280 "Fit Includes Match Point",
2281 "Extrapolation" ) < 0 )
2282 {
2283 log<software_error>( { "error from createStandardIndiToggleSw" } );
2284 return -1;
2285 }
2288 {
2289 log<software_error>( { "error from registerIndiPropertyNew" } );
2290 return -1;
2291 }
2293 "extrap_powerLawFitMinFreqHz",
2294 0,
2295 10000,
2296 0.1,
2297 "%0.2f",
2298 "Fit Min Freq",
2299 "Extrapolation" );
2301 "extrap_powerLawFitMaxFreqHz",
2302 0,
2303 10000,
2304 0.1,
2305 "%0.2f",
2306 "Fit Max Freq",
2307 "Extrapolation" );
2309 "extrap_powerLawFitBinWidthHz",
2310 0,
2311 10000,
2312 0.1,
2313 "%0.2f",
2314 "Fit Bin Width",
2315 "Extrapolation" );
2317 "extrap_powerLawBlendBins",
2318 0,
2319 100,
2320 1,
2321 "%d",
2322 "Blend Bins",
2323 "Extrapolation" );
2325 "extrap_dropoutGapFactor",
2326 0,
2327 1,
2328 0.01,
2329 "%0.3f",
2330 "Dropout Gap Factor",
2331 "Extrapolation" );
2333 "extrap_dropoutTinyFactor",
2334 0,
2335 1,
2336 1e-7,
2337 "%0.3e",
2338 "Dropout Tiny Factor",
2339 "Extrapolation" );
2341 "extrap_dropoutMaxBins",
2342 1,
2343 1000,
2344 1,
2345 "%d",
2346 "Dropout Max Bins",
2347 "Extrapolation" );
2349 "extrap_clSignificanceThreshold",
2350 0,
2351 1000,
2352 0.01,
2353 "%0.3f",
2354 "CL Significance Threshold",
2355 "Extrapolation" );
2357 "extrap_clMinSignificantFraction",
2358 0,
2359 1,
2360 0.01,
2361 "%0.3f",
2362 "CL Min Significant Fraction",
2363 "Extrapolation" );
2364
2368 REG_INDI_SETPROP( m_indiP_loop, m_loopName, "loop_state" );
2370 REG_INDI_SETPROP( m_indiP_siMult, m_loopName, "loop_multcoeff" );
2371 REG_INDI_SETPROP( m_indiP_pcGain, m_loopName, "loop_pcgain" );
2372 REG_INDI_SETPROP( m_indiP_pcMult, m_loopName, "loop_pcmultcoeff" );
2373 REG_INDI_SETPROP( m_indiP_pcOn, m_loopName, "loop_pcOn" );
2374
2375 CREATE_REG_INDI_RO_NUMBER( m_indiP_modesOn, "num_modes", "number of modes", "Gain Opt." );
2376 indi::addNumberElement( m_indiP_modesOn, "current", 0, 2400, 1, "%d", "Applied Modes" );
2377 indi::addNumberElement( m_indiP_modesOn, "integrator", 0, 2400, 1, "%d", "SI optimal" );
2378 indi::addNumberElement( m_indiP_modesOn, "predictor", 0, 2400, 1, "%d", "LP optimal" );
2379
2381
2383
2384 if( sem_init( &m_goptSemaphore, 0, 0 ) < 0 )
2385 {
2386 return log<software_critical, -1>( { errno, 0, "Initializing gopt semaphore" } );
2387 }
2388 m_goptSemaphoreInit = true;
2389
2396 "gainopt",
2398
2400 return 0;
2401}
2402
2404{
2405 if( telemeterT::appLogic() < 0 )
2406 {
2407 return log<software_error, -1>( { "error from telemeter appLogic" } );
2408 }
2409
2425
2426 XWCAPP_THREAD_CHECK( m_goptThread, "gainopt" );
2427
2443
2444 bool autoUpdate = false;
2445 bool updateOnce = false;
2446 bool dump = false;
2447 bool zeroGains = false;
2448 bool opticalGainUpdate = false;
2449 float opticalGain = 0;
2450 float gainGain = 0;
2451 float gainLeak = 0;
2453 int extrapOL = 0;
2458 int modesOn = 0;
2459 int modesOnSI = 0;
2460 int modesOnLP = 0;
2461
2462 { // mutex scope
2463 std::lock_guard<std::mutex> lock( m_goptMutex );
2464
2467 dump = m_dump;
2470 opticalGain = m_opticalGain;
2471 gainGain = m_gainGain;
2472 gainLeak = m_gainLeak;
2482 }
2483
2484 if( autoUpdate )
2485 {
2486 updateSwitchIfChanged( m_indiP_autoUpdate, "toggle", pcf::IndiElement::On, INDI_OK );
2487 }
2488 else
2489 {
2490 updateSwitchIfChanged( m_indiP_autoUpdate, "toggle", pcf::IndiElement::Off, INDI_IDLE );
2491 }
2492
2493 if( updateOnce )
2494 {
2495 updateSwitchIfChanged( m_indiP_updateOnce, "request", pcf::IndiElement::On, INDI_OK );
2496 }
2497 else
2498 {
2499 updateSwitchIfChanged( m_indiP_updateOnce, "request", pcf::IndiElement::Off, INDI_IDLE );
2500 }
2501
2502 if( dump )
2503 {
2504 updateSwitchIfChanged( m_indiP_dump, "request", pcf::IndiElement::On, INDI_OK );
2505 }
2506 else
2507 {
2508 updateSwitchIfChanged( m_indiP_dump, "request", pcf::IndiElement::Off, INDI_IDLE );
2509 }
2510
2511 if( zeroGains )
2512 {
2513 updateSwitchIfChanged( m_indiP_zeroGains, "request", pcf::IndiElement::On, INDI_OK );
2514 }
2515 else
2516 {
2517 updateSwitchIfChanged( m_indiP_zeroGains, "request", pcf::IndiElement::Off, INDI_IDLE );
2518 }
2519
2520 if( opticalGainUpdate )
2521 {
2522 updateSwitchIfChanged( m_indiP_opticalGainUpdate, "toggle", pcf::IndiElement::On, INDI_OK );
2523 }
2524 else
2525 {
2526 updateSwitchIfChanged( m_indiP_opticalGainUpdate, "toggle", pcf::IndiElement::Off, INDI_IDLE );
2527 }
2528
2529 updatesIfChanged<float>( m_indiP_opticalGain, { "current", "target" }, { opticalGain, opticalGain } );
2530
2531 updatesIfChanged<float>( m_indiP_gainGain, { "current", "target" }, { gainGain, gainGain } );
2532 updatesIfChanged<float>( m_indiP_gainLeak, { "current", "target" }, { gainLeak, gainLeak } );
2536 INDI_OK );
2540 INDI_OK );
2544 INDI_OK );
2548 INDI_OK );
2550 { "current", "target" },
2551 { extrapConfig.m_noiseEstimateLowFreqMaxHz, extrapConfig.m_noiseEstimateLowFreqMaxHz } );
2555 INDI_OK );
2557 { "current", "target" },
2558 { extrapConfig.m_powerLawIndex, extrapConfig.m_powerLawIndex } );
2560 { "current", "target" },
2561 { extrapConfig.m_powerLawNormFreq, extrapConfig.m_powerLawNormFreq } );
2563 { "current", "target" },
2564 { extrapConfig.m_powerLawMatchFreq, extrapConfig.m_powerLawMatchFreq } );
2567 { "current", "target" },
2568 { extrapConfig.m_powerLawMatchFallbackWindowHz, extrapConfig.m_powerLawMatchFallbackWindowHz } );
2572 INDI_OK );
2574 { "current", "target" },
2575 { extrapConfig.m_powerLawAutoSmoothWidthHz, extrapConfig.m_powerLawAutoSmoothWidthHz } );
2578 { "current", "target" },
2579 { extrapConfig.m_powerLawAutoMaxFreqFraction, extrapConfig.m_powerLawAutoMaxFreqFraction } );
2581 "toggle",
2582 extrapConfig.m_fitPowerLawIndex ? pcf::IndiElement::On : pcf::IndiElement::Off,
2583 INDI_OK );
2585 { "current", "target" },
2586 { extrapConfig.m_powerLawOnlyAboveFreq, extrapConfig.m_powerLawOnlyAboveFreq } );
2588 "toggle",
2589 extrapConfig.m_powerLawFitIncludesMatchPoint ? pcf::IndiElement::On : pcf::IndiElement::Off,
2590 INDI_OK );
2592 { "current", "target" },
2593 { extrapConfig.m_powerLawFitMinFreqHz, extrapConfig.m_powerLawFitMinFreqHz } );
2595 { "current", "target" },
2596 { extrapConfig.m_powerLawFitMaxFreqHz, extrapConfig.m_powerLawFitMaxFreqHz } );
2598 { "current", "target" },
2599 { extrapConfig.m_powerLawFitBinWidthHz, extrapConfig.m_powerLawFitBinWidthHz } );
2601 { "current", "target" },
2602 { extrapConfig.m_powerLawBlendBins, extrapConfig.m_powerLawBlendBins } );
2604 { "current", "target" },
2605 { extrapConfig.m_dropoutGapFactor, extrapConfig.m_dropoutGapFactor } );
2607 { "current", "target" },
2608 { extrapConfig.m_dropoutTinyFactor, extrapConfig.m_dropoutTinyFactor } );
2611 { "current", "target" },
2612 { static_cast<int>( extrapConfig.m_dropoutMaxBins ), static_cast<int>( extrapConfig.m_dropoutMaxBins ) } );
2614 { "current", "target" },
2615 { extrapConfig.m_clSignificanceThreshold, extrapConfig.m_clSignificanceThreshold } );
2617 { "current", "target" },
2618 { extrapConfig.m_clMinSignificantFraction, extrapConfig.m_clMinSignificantFraction } );
2619
2621 { "current", "integrator", "predictor" },
2622 { modesOn, modesOnSI, modesOnLP } );
2623
2624 return 0;
2625}
2626
2628{
2630
2646
2657
2665
2667 {
2669 m_goptSemaphoreInit = false;
2670 }
2671
2673
2674 return 0;
2675}
2676
2681
2683{
2684 return recordModalGainOpt( true );
2685}
2686
2687inline int modalGainOpt::recordModalGainOpt( bool force )
2688{
2689 static bool lastAutoUpdate{ false };
2690 static bool lastOpticalGainUpdate{ false };
2691 static float lastOpticalGain{ -1e6F };
2692 static float lastGainGain{ -1e6F };
2693 static float lastGainLeak{ -1e6F };
2694
2695 bool autoUpdate = false;
2696 bool opticalGainUpdate = false;
2697 float opticalGain = 0;
2698 float gainGain = 0;
2699 float gainLeak = 0;
2700
2701 {
2702 std::lock_guard<std::mutex> lock( m_goptMutex );
2705 opticalGain = m_opticalGain;
2706 gainGain = m_gainGain;
2707 gainLeak = m_gainLeak;
2708 }
2709
2711 opticalGain != lastOpticalGain || gainGain != lastGainGain || gainLeak != lastGainLeak )
2712 {
2715 lastOpticalGain = opticalGain;
2716 lastGainGain = gainGain;
2717 lastGainLeak = gainLeak;
2718
2719 telem<telem_modalgainopt>( { autoUpdate, opticalGainUpdate, opticalGain, gainGain, gainLeak } );
2720 }
2721
2722 return 0;
2723}
2724
2726{
2727 if( stream == nullptr )
2728 {
2729 return;
2730 }
2731
2733 free( stream );
2734 stream = nullptr;
2735}
2736
2738 IMAGE *&stream, const std::string &name, uint32_t size0, uint32_t size1, uint32_t size2, uint8_t dataType )
2739{
2741
2742 stream = static_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
2743 if( stream == nullptr )
2744 {
2745 return log<software_error, -1>( { "error allocating stream for " + name } );
2746 }
2747
2748 uint32_t imsize[3];
2749 imsize[0] = size0;
2750 imsize[1] = size1;
2751 imsize[2] = size2;
2752
2754 name.c_str(),
2755 3,
2756 imsize,
2757 dataType,
2758 -1,
2759 1,
2761 0,
2763 0 ) != 0 )
2764 {
2765 free( stream );
2766 stream = nullptr;
2767 return log<software_error, -1>( { "error creating stream for " + name } );
2768 }
2769
2770 if( stream->md == nullptr )
2771 {
2773 return log<software_error, -1>( { "stream metadata not initialized for " + name } );
2774 }
2775
2776 stream->md->cnt0 = 0;
2777 stream->md->cnt1 = 0;
2778
2779 return 0;
2780}
2781
2783 float *siRawData,
2784 float *siData,
2785 float *maxSiData,
2786 float *lpData,
2787 float *maxLpData,
2788 float *modeVarData )
2789{
2790 mx::improc::eigenMap<float> modeVars( modeVarData, 3, m_modeVarSI.size() );
2791
2792 for( size_t n = 0; n < m_optGainSI.size(); ++n )
2793 {
2796 siData[n] = currentData[n];
2798
2801
2802 modeVars( 0, n ) = m_modeVarOL[n];
2803 modeVars( 1, n ) = m_modeVarSI[n];
2804 modeVars( 2, n ) = m_modeVarLP[n];
2805 }
2806}
2807
2809 float *pcGainData, float *aCoeffData, uint32_t aWidth, float *bCoeffData, uint32_t bWidth, bool blend )
2810{
2811 for( size_t n = 0; n < m_optGainLP.size(); ++n )
2812 {
2813 const float targetGain = ( m_gainCalFacts[n] * m_optGainLP[n] / m_gainCals[n] ) / m_opticalGain;
2814
2815 if( blend )
2816 {
2818 }
2819 else
2820 {
2822 }
2823
2824 const size_t aBase = n * aWidth;
2825 const size_t bBase = n * bWidth;
2826
2827 aCoeffData[aBase] = m_Na[n];
2828 bCoeffData[bBase] = m_Nb[n];
2829
2830 for( uint32_t k = 0; k < m_Na[n]; ++k )
2831 {
2832 if( blend )
2833 {
2834 aCoeffData[aBase + 1 + k] =
2835 aCoeffData[aBase + 1 + k] + m_gainGain * ( m_goptLP[n].a()[k] - aCoeffData[aBase + 1 + k] );
2836 }
2837 else
2838 {
2839 aCoeffData[aBase + 1 + k] = m_goptLP[n].a()[k];
2840 }
2841 }
2842 for( uint32_t k = m_Na[n]; k < aWidth - 1; ++k )
2843 {
2844 aCoeffData[aBase + 1 + k] = 0;
2845 }
2846
2847 for( uint32_t k = 0; k < m_Nb[n]; ++k )
2848 {
2849 if( blend )
2850 {
2851 bCoeffData[bBase + 1 + k] =
2852 bCoeffData[bBase + 1 + k] + m_gainGain * ( m_goptLP[n].b()[k] - bCoeffData[bBase + 1 + k] );
2853 }
2854 else
2855 {
2856 bCoeffData[bBase + 1 + k] = m_goptLP[n].b()[k];
2857 }
2858 }
2859 for( uint32_t k = m_Nb[n]; k < bWidth - 1; ++k )
2860 {
2861 bCoeffData[bBase + 1 + k] = 0;
2862 }
2863 }
2864}
2865
2866int modalGainOpt::countEnabledGainFactors( const std::vector<float> &gainFacts ) const
2867{
2868 int modesOn = 0;
2869
2870 for( size_t n = 0; n < gainFacts.size(); ++n )
2871 {
2872 if( gainFacts[n] > 0 )
2873 {
2874 ++modesOn;
2875 }
2876 }
2877
2878 return modesOn;
2879}
2880
2881void modalGainOpt::updateAppliedModeCount( const std::vector<float> &gainFacts, bool predictorPath )
2882{
2883 if( predictorPath != m_pcOn )
2884 {
2885 return;
2886 }
2887
2889}
2890
2891bool modalGainOpt::applyGainFactorUpdate( std::vector<float> &gainFacts,
2892 const float *incoming,
2893 uint32_t width,
2894 bool predictorPath )
2895{
2896 bool change = false;
2897
2898 if( width != gainFacts.size() )
2899 {
2900 gainFacts.resize( width );
2901 change = true;
2902 }
2903
2904 for( uint32_t n = 0; n < width; ++n )
2905 {
2906 if( change || gainFacts[n] != incoming[n] )
2907 {
2908 gainFacts[n] = incoming[n];
2909 change = true;
2910 }
2911 }
2912
2913 if( !change )
2914 {
2915 return false;
2916 }
2917
2918 if( m_loop )
2919 {
2920 m_sinceChange = -1;
2921 }
2922
2923 if( !predictorPath )
2924 {
2926 }
2927
2929
2930 return true;
2931}
2932
2933bool modalGainOpt::applyMultiplierUpdate( std::vector<float> &multFacts,
2934 const float *incoming,
2935 uint32_t width,
2936 bool predictorPath )
2937{
2938 bool change = false;
2939
2940 if( width != multFacts.size() )
2941 {
2942 multFacts.resize( width );
2943 change = true;
2944 }
2945
2946 for( uint32_t n = 0; n < width; ++n )
2947 {
2948 if( change || multFacts[n] != incoming[n] )
2949 {
2950 multFacts[n] = incoming[n];
2951 change = true;
2952 }
2953 }
2954
2955 if( !change )
2956 {
2957 return false;
2958 }
2959
2960 if( m_loop )
2961 {
2962 m_sinceChange = -1;
2963 }
2964
2965 if( predictorPath )
2966 {
2967 m_pcgoptUpdated = true;
2968 }
2969 else
2970 {
2971 m_goptUpdated = true;
2972 }
2973
2974 return true;
2975}
2976
2977bool modalGainOpt::applyFrequencyUpdate( const float *incoming, size_t size )
2978{
2979 bool change = false;
2980
2981 if( size != m_freq.size() )
2982 {
2983 m_freq.resize( size );
2984 change = true;
2985 }
2986
2987 for( size_t n = 0; n < size; ++n )
2988 {
2989 if( change || m_freq[n] != incoming[n] )
2990 {
2991 m_freq[n] = incoming[n];
2992 change = true;
2993 }
2994 }
2995
2996 if( !change )
2997 {
2998 return false;
2999 }
3000
3001 m_fps = 2 * m_freq.back();
3002
3003 m_sinceChange = -1;
3004 m_goptUpdated = true;
3005 m_freqUpdated = true;
3006
3007 return true;
3008}
3009
3011{
3012 if( !( m_goptUpdated || m_pcgoptUpdated || m_freqUpdated || m_goptCurrent.size() != m_gainFacts.size() ) )
3013 {
3014 return false;
3015 }
3016
3017 if( m_goptCurrent.size() != m_gainFacts.size() )
3018 {
3019 m_freqUpdated = true; // force freq update in this case
3020 }
3021
3022 std::cerr << "updating gopt structures\n";
3023
3024 m_goptCurrent.resize( m_gainFacts.size() );
3025 m_goptSI.resize( m_gainFacts.size() );
3026 m_goptLP.resize( m_gainFacts.size() );
3027 m_linPred.resize( m_gainFacts.size() );
3028
3029 for( size_t n = 0; n < m_goptCurrent.size(); ++n )
3030 {
3031 m_goptCurrent[n].Ti( 1.0 / m_fps );
3032 m_goptCurrent[n].tau( m_taus[n] );
3033
3034 m_goptSI[n].Ti( 1.0 / m_fps );
3035 m_goptSI[n].tau( m_taus[n] );
3036
3037 m_goptLP[n].Ti( 1.0 / m_fps );
3038 m_goptLP[n].tau( m_taus[n] );
3039
3040 if( !m_pcOn )
3041 {
3042 m_goptCurrent[n].setLeakyIntegrator( m_mult * m_multFacts[n] );
3043 }
3044 else
3045 {
3046 std::vector<float> ta( m_NaCurrent[n] );
3047 for( size_t m = 0; m < ta.size(); ++m )
3048 {
3049 ta[m] = m_as( m, n );
3050 }
3051 m_goptCurrent[n].a( ta );
3052
3053 std::vector<float> tb( m_NbCurrent[n] );
3054 for( size_t m = 0; m < tb.size(); ++m )
3055 {
3056 tb[m] = m_bs( m, n );
3057 }
3058 m_goptCurrent[n].b( tb );
3059
3060 m_goptCurrent[n].remember( m_pcMult * m_pcMultFacts[n] );
3061 }
3062
3063 m_goptSI[n].setLeakyIntegrator( m_mult * m_multFacts[n] );
3064
3065 if( m_freqUpdated )
3066 {
3067 m_goptCurrent[n].f( m_freq );
3068 m_goptSI[n].f( m_freq );
3069 m_goptLP[n].f( m_freq );
3070 }
3071
3072 m_gmaxSI[n] = m_goptSI[n].maxStableGain();
3073 }
3074
3075 m_goptUpdated = false;
3076 m_pcgoptUpdated = false;
3077 m_freqUpdated = false;
3078
3079 std::cerr << "done.\n";
3080 return true;
3081}
3082
3084{
3085 const float tiny = std::numeric_limits<float>::min();
3086
3087 if( m_optGainSI.size() != m_gainFacts.size() )
3088 {
3089 m_optGainSI.resize( m_gainFacts.size(), 0.0F );
3090 }
3091
3092 if( m_optGainSIRaw.size() != m_gainFacts.size() )
3093 {
3094 m_optGainSIRaw.resize( m_gainFacts.size(), 0.0F );
3095 }
3096
3097 if( m_gainFacts.size() != m_gainCals.size() || m_gainFacts.size() != m_gainCalFacts.size() ||
3098 std::abs( m_opticalGain ) <= tiny )
3099 {
3100 std::fill( m_optGainSI.begin(), m_optGainSI.end(), 0.0F );
3101 m_siGainStateNeedsSync = false;
3102 return;
3103 }
3104
3105 for( size_t n = 0; n < m_gainFacts.size(); ++n )
3106 {
3107 if( std::abs( m_gainCalFacts[n] ) <= tiny )
3108 {
3109 m_optGainSI[n] = 0.0F;
3110 continue;
3111 }
3112
3114 }
3115
3116 m_siGainStateNeedsSync = false;
3117}
3118
3124
3126{
3127 // mutex should be locked before calling this
3128
3131 {
3132 mx::improc::eigenImage<uint32_t> Npc( m_nModes, 2 );
3133 Npc.setConstant( m_defaultNCoeff );
3134
3136 {
3137 return log<software_error, -1>( { "error creating numpccoeffShmim" } );
3138 }
3139
3141
3142 std::cerr << "created numppccoeff shmim\n";
3143 }
3144
3147 {
3149 {
3150 return log<software_error, -1>( { "error creating acoeffShmim" } );
3151 }
3152
3153 std::cerr << "created acoeff shmim\n";
3154 }
3155
3158 {
3160 {
3161 return log<software_error, -1>( { "error creating bcoeffShmim" } );
3162 }
3163
3164 std::cerr << "created bcoeff shmim\n";
3165 }
3166
3169 {
3171 {
3172 return log<software_error, -1>( { "error creating pcGainFactShmim" } );
3173 }
3174
3175 std::cerr << "created pcGainFact shmim\n";
3176 }
3177
3180 {
3182 {
3183 return log<software_error, -1>( { "error creating pcMultFactShmim" } );
3184 }
3185
3186 std::cerr << "created pcMultFact shmim\n";
3187 }
3188
3189 return 0;
3190}
3191
3193{
3194 static_cast<void>( dummy );
3195
3196 m_updating = true;
3197 std::lock_guard<std::mutex> lock( m_goptMutex );
3198
3199 m_updating = true;
3200
3203
3204 m_clPSDs.resize( m_nFreq, m_nModes );
3205
3206 m_clXferCurrent.resize( m_nFreq, m_nModes );
3207 m_clNtfCurrent.resize( m_nFreq, m_nModes );
3208 m_clXferSI.resize( m_nFreq, m_nModes );
3209 m_clNtfSI.resize( m_nFreq, m_nModes );
3210 m_clXferLP.resize( m_nFreq, m_nModes );
3211 m_clNtfLP.resize( m_nFreq, m_nModes );
3212
3213 m_olPSDs.resize( m_nModes );
3214 m_rawOlPSDs.resize( m_nModes );
3215 m_smoothOlPSDs.resize( m_nModes );
3216 m_nPSDs.resize( m_nModes );
3217 for( size_t n = 0; n < m_olPSDs.size(); ++n )
3218 {
3219 m_olPSDs[n].resize( m_nFreq );
3220 m_rawOlPSDs[n].resize( m_nFreq );
3221 m_smoothOlPSDs[n].resize( m_nFreq );
3222 m_nPSDs[n].resize( m_nFreq );
3223 }
3224
3225 m_modeVarOL.resize( m_nModes );
3226
3227 m_optGainSIRaw.resize( m_nModes );
3228 m_optGainSI.resize( m_nModes );
3229 m_gmaxSI.resize( m_nModes );
3230 m_modeVarSI.resize( m_nModes );
3231 m_timesOnSI.resize( m_nModes, 5 );
3232
3233 m_optGainLP.resize( m_nModes );
3234 m_modeVarLP.resize( m_nModes );
3235 m_timesOnLP.resize( m_nModes, 5 );
3237
3238 if( m_olPSDStream != nullptr &&
3239 ( m_olPSDStream->md->size[0] != m_nFreq || m_olPSDStream->md->size[1] != m_nModes ) )
3240 {
3251 }
3252
3253 if( m_olPSDStream == nullptr )
3254 {
3256 0 )
3257 {
3258 return -1;
3259 }
3260
3263 m_nFreq,
3264 m_nModes,
3265 1,
3267 {
3268 return -1;
3269 }
3270
3273 m_nFreq,
3274 m_nModes,
3275 1,
3277 {
3278 return -1;
3279 }
3280
3283 m_nFreq,
3284 m_nModes,
3285 1,
3287 {
3288 return -1;
3289 }
3290
3293 m_nFreq,
3294 m_nModes,
3295 1,
3297 {
3298 return -1;
3299 }
3300
3303 m_nFreq,
3304 m_nModes,
3305 1,
3307 {
3308 return -1;
3309 }
3310
3313 m_nFreq,
3314 m_nModes,
3315 1,
3317 {
3318 return -1;
3319 }
3320
3323 m_nFreq,
3324 m_nModes,
3325 1,
3327 {
3328 return -1;
3329 }
3330
3333 m_nFreq,
3334 m_nModes,
3335 1,
3337 {
3338 return -1;
3339 }
3340
3343 m_nFreq,
3344 m_nModes,
3345 1,
3347 {
3348 return -1;
3349 }
3350 }
3351
3352 if( m_optGainStream != nullptr &&
3353 ( m_optGainStream->md->size[0] != psdShmimMonitorT::m_height || m_optGainStream->md->size[1] != 1 ) )
3354 {
3362 }
3363
3364 if( m_optGainStream == nullptr )
3365 {
3367 {
3368 return -1;
3369 }
3370
3372 0 )
3373 {
3374 return -1;
3375 }
3376
3379 m_nModes,
3380 1,
3381 1,
3383 {
3384 return -1;
3385 }
3386
3388 0 )
3389 {
3390 return -1;
3391 }
3392
3394 0 )
3395 {
3396 return -1;
3397 }
3398
3400 0 )
3401 {
3402 return -1;
3403 }
3404
3406 {
3407 return -1;
3408 }
3409 }
3410
3411 m_sinceChange = -1;
3412
3413 m_updating = false;
3414 return 0;
3415}
3416
3417int modalGainOpt::processImage( void *curr_src, const psdShmimT &dummy )
3418{
3419 static_cast<void>( dummy );
3420
3421 ++m_sinceChange;
3422
3423 if( m_psdAvgTime <= 0 || m_psdTime <= 0 ) // Safety check, shouldn't happen but means we need to wait.
3424 {
3425 return 0;
3426 }
3427
3429
3430 if( m_sinceChange < deadTime )
3431 {
3432 return 0;
3433 }
3434
3435 // Here we would update psds, but don't do that if we're in the middle of
3436 // calculating
3437 std::unique_lock<std::mutex> lock( m_goptMutex, std::try_to_lock );
3438 if( !lock.owns_lock() )
3439 {
3440 ///\todo update a frame-missed counter
3441 return 0;
3442 }
3443
3444 m_updating = true;
3445
3446 m_clPSDs = Eigen::Map<Eigen::Array<float, -1, -1>>( static_cast<float *>( curr_src ),
3449
3450 m_updating = false;
3451
3452 lock.unlock();
3453
3454 if( sem_post( &m_goptSemaphore ) < 0 )
3455 {
3456 return log<software_critical, -1>( { errno, 0, "Error posting to semaphore" } );
3457 }
3458
3459 return 0;
3460}
3461
3463{
3464 static_cast<void>( dummy );
3465
3466 return 0;
3467}
3468
3469int modalGainOpt::processImage( void *curr_src, const freqShmimT &dummy )
3470{
3471 static_cast<void>( dummy );
3472
3474 {
3475 return log<software_error, -1>( { "got freq with width not 1" } );
3476 }
3477
3478 float *f = static_cast<float *>( curr_src );
3480
3481 bool sizeChange = ( sz != m_freq.size() );
3482 bool dataChange = false;
3483
3484 if( !sizeChange )
3485 {
3486 for( size_t n = 0; n < sz; ++n )
3487 {
3488 if( f[n] != m_freq[n] )
3489 {
3490 dataChange = true;
3491 break;
3492 }
3493 }
3494 }
3495
3496 if( sizeChange || dataChange )
3497 {
3498 m_updating = true;
3499 std::lock_guard<std::mutex> lock( m_goptMutex );
3500
3501 m_updating = true; // Make sure it didn't get set to false by thread that
3502 // had the lock
3503
3504 if( applyFrequencyUpdate( f, sz ) )
3505 {
3506 std::cerr << "got freq: " << sz << '\n';
3507 std::cerr << " fps: " << m_fps << '\n';
3508 }
3509
3510 m_updating = false;
3511 }
3512
3513 return 0;
3514}
3515
3517{
3518 static_cast<void>( dummy );
3519
3521 {
3522 return log<software_error, -1>( { "got gains with height not 1" } );
3523 }
3524
3525 return 0;
3526}
3527
3528int modalGainOpt::processImage( void *curr_src, const gainFactShmimT &dummy )
3529{
3530 static_cast<void>( dummy );
3531
3533 float *g = static_cast<float *>( curr_src );
3534
3535 std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
3536
3537 bool sizeChange = ( w != m_gainFacts.size() );
3538 bool dataChange = false;
3539
3540 if( !sizeChange )
3541 {
3542 for( uint32_t n = 0; n < w; ++n )
3543 {
3544 if( m_gainFacts[n] != g[n] )
3545 {
3546 dataChange = true;
3547 break;
3548 }
3549 }
3550 }
3551
3552 if( sizeChange || dataChange )
3553 {
3554 m_updating = true;
3555 lock.lock();
3556 m_updating = true; // Make sure it didn't get set to false by thread that
3557 // had the lock
3558
3559 if( applyGainFactorUpdate( m_gainFacts, g, w, false ) )
3560 {
3561 m_updating = false;
3562 std::cerr << "got gains: " << m_gainFacts.size() << "\n";
3563
3564 lock.unlock();
3565 }
3566 else
3567 {
3568 m_updating = false;
3569 }
3570 }
3571
3572 return 0;
3573}
3574
3576{
3577 static_cast<void>( dummy );
3578
3580 {
3581 return log<software_error, -1>( { "got multcoeffs with height not 1" } );
3582 }
3583
3584 return 0;
3585}
3586
3587int modalGainOpt::processImage( void *curr_src, const multFactShmimT &dummy )
3588{
3589 static_cast<void>( dummy );
3590
3592 float *m = static_cast<float *>( curr_src );
3593
3594 std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
3595
3596 bool sizeChange = ( w != m_multFacts.size() );
3597 bool dataChange = false;
3598
3599 if( !sizeChange )
3600 {
3601 for( uint32_t n = 0; n < w; ++n )
3602 {
3603 if( m_multFacts[n] != m[n] )
3604 {
3605 dataChange = true;
3606 break;
3607 }
3608 }
3609 }
3610
3611 if( sizeChange || dataChange )
3612 {
3613 m_updating = true;
3614 lock.lock();
3615 m_updating = true; // Make sure it didn't get set to false by thread that
3616 // had the lock
3617
3618 if( applyMultiplierUpdate( m_multFacts, m, w, false ) )
3619 {
3620 m_updating = false;
3621 std::cerr << "got mcs: " << m_multFacts.size() << " " << w << "\n";
3622
3623 lock.unlock();
3624 }
3625 else
3626 {
3627 m_updating = false;
3628 }
3629 }
3630
3631 return 0;
3632}
3633
3635{
3636 static_cast<void>( dummy );
3637
3639 {
3640 return log<software_error, -1>( { "got pc gains with height not 1" } );
3641 }
3642
3643 return 0;
3644}
3645
3646int modalGainOpt::processImage( void *curr_src, const pcGainFactShmimT &dummy )
3647{
3648 static_cast<void>( dummy );
3649
3651 float *g = static_cast<float *>( curr_src );
3652
3653 std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
3654
3655 bool sizeChange = ( w != m_pcGainFacts.size() );
3656 bool dataChange = false;
3657
3658 if( !sizeChange )
3659 {
3660 for( uint32_t n = 0; n < w; ++n )
3661 {
3662 if( m_pcGainFacts[n] != g[n] )
3663 {
3664 dataChange = true;
3665 break;
3666 }
3667 }
3668 }
3669
3670 if( sizeChange || dataChange )
3671 {
3672 m_updating = true;
3673 lock.lock();
3674 m_updating = true; // Make sure it didn't get set to false by thread that
3675 // had the lock
3676
3677 if( applyGainFactorUpdate( m_pcGainFacts, g, w, true ) )
3678 {
3679 m_updating = false;
3680 std::cerr << "got pc gains: " << m_pcGainFacts.size() << "\n";
3681
3682 lock.unlock();
3683 }
3684 else
3685 {
3686 m_updating = false;
3687 }
3688 }
3689
3690 return 0;
3691}
3692
3694{
3695 static_cast<void>( dummy );
3696
3698 {
3699 return log<software_error, -1>( { "got pcMultcoeffs with height not 1" } );
3700 }
3701
3702 return 0;
3703}
3704
3705int modalGainOpt::processImage( void *curr_src, const pcMultFactShmimT &dummy )
3706{
3707 static_cast<void>( dummy );
3708
3710 float *m = static_cast<float *>( curr_src );
3711
3712 std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
3713
3714 bool sizeChange = ( w != m_pcMultFacts.size() );
3715 bool dataChange = false;
3716
3717 if( !sizeChange )
3718 {
3719 for( uint32_t n = 0; n < w; ++n )
3720 {
3721 if( m_pcMultFacts[n] != m[n] )
3722 {
3723 dataChange = true;
3724 break;
3725 }
3726 }
3727 }
3728
3729 if( sizeChange || dataChange )
3730 {
3731 m_updating = true;
3732 lock.lock();
3733 m_updating = true; // Make sure it didn't get set to false by thread that
3734 // had the lock
3735
3736 if( applyMultiplierUpdate( m_pcMultFacts, m, w, true ) )
3737 {
3738 m_updating = false;
3739
3740 lock.unlock();
3741 std::cerr << "got mcs: " << m_pcMultFacts.size() << "\n";
3742 }
3743 else
3744 {
3745 m_updating = false;
3746 }
3747 }
3748
3749 return 0;
3750}
3751
3753{
3754 static_cast<void>( dummy );
3755
3757 {
3758 return log<software_error, -1>( { "got numpccoeff's with height not 2" } );
3759 }
3760
3761 std::cerr << "numpccoeffShmimMonitorT::allocate\n";
3762 return 0;
3763}
3764
3765int modalGainOpt::processImage( void *curr_src, const numpccoeffShmimT &dummy )
3766{
3767 static_cast<void>( dummy );
3768
3769 bool change = false;
3770
3772
3773 std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
3774
3775 if( w != m_Na.size() || w != m_Nb.size() || w != m_regCounter.size() || w != m_regScale.size() )
3776 {
3777 m_updating = true;
3778 lock.lock();
3779 m_updating = true; // Make sure it didn't get set to false by thread that
3780 // had the lock
3781
3782 change = true;
3783 m_Na.resize( w );
3784 m_Nb.resize( w );
3785
3786 m_regCounter.resize( w );
3787
3788 // Initialize the regCounter
3789 int nc = 0;
3790
3791 for( size_t n = 0; n < m_regCounter.size(); ++n )
3792 {
3793 m_regCounter[n] = nc;
3794 ++nc;
3795
3796 if( nc >= m_nRegCycles )
3797 {
3798 nc = 0;
3799 }
3800 }
3801
3802 m_regScale.resize( w, -999 );
3803 m_gmaxLP.resize( w, 0 );
3804 }
3805
3806 mx::improc::eigenMap<uint32_t> Npc( reinterpret_cast<uint32_t *>( curr_src ), w, 2 );
3807
3808 for( uint32_t n = 0; n < w; ++n )
3809 {
3810 if( change || m_Na[n] != Npc( n, 0 ) || m_Nb[n] != Npc( n, 1 ) )
3811 {
3812 if( !change )
3813 {
3814 m_updating = true;
3815 lock.lock();
3816 m_updating = true; // Make sure it didn't get set to false by thread
3817 // that had the lock
3818
3819 change = true;
3820 }
3821
3822 m_Na[n] = Npc( n, 0 );
3823 m_Nb[n] = Npc( n, 1 );
3824 }
3825 }
3826
3827 if( change )
3828 {
3829 if( m_loop )
3830 {
3831 m_sinceChange = -1;
3832 }
3833
3834 m_updating = false;
3835 m_goptUpdated = true;
3836
3837 lock.unlock();
3838 std::cerr << "got num pc coeffs: " << m_Na.size() << "\n";
3839 }
3840
3841 return 0;
3842}
3843
3845{
3846 static_cast<void>( dummy );
3847
3848 return 0;
3849}
3850
3851int modalGainOpt::processImage( void *curr_src, const acoeffShmimT &dummy )
3852{
3853 static_cast<void>( dummy );
3854
3855 bool change = false;
3856
3857 std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
3858
3861
3862 // If there's a size change we lock
3863 if( w - 1 != m_as.rows() || h != m_as.cols() || h != m_NaCurrent.size() )
3864 {
3865 m_updating = true;
3866 lock.lock();
3867 m_updating = true; // Make sure it didn't get set to false by thread that
3868 // had the lock
3869
3870 change = true;
3871 m_NaCurrent.resize( h );
3872 m_as.resize( w - 1, h );
3873 }
3874
3875 eigenMap<float> ac( reinterpret_cast<float *>( curr_src ), w, h );
3876
3877 for( uint32_t cc = 0; cc < h; ++cc )
3878 {
3879 if( change || m_NaCurrent[cc] != ac( 0, cc ) )
3880 {
3881 if( !change )
3882 {
3883 m_updating = true;
3884 lock.lock();
3885 m_updating = true; // Make sure it didn't get set to false by thread
3886 // that had the lock
3887
3888 change = true;
3889 }
3890
3891 m_NaCurrent[cc] = ac( 0, cc );
3892 }
3893
3894 for( uint32_t rr = 1; rr < w; ++rr )
3895 {
3896 if( change || m_as( rr - 1, cc ) != ac( rr, cc ) )
3897 {
3898 if( !change )
3899 {
3900 m_updating = true;
3901 lock.lock();
3902 m_updating = true; // Make sure it didn't get set to false by thread
3903 // that had the lock
3904
3905 change = true;
3906 }
3907
3908 m_as( rr - 1, cc ) = ac( rr, cc );
3909 }
3910 }
3911 }
3912
3913 if( change )
3914 {
3915 if( m_loop && m_pcOn )
3916 {
3917 m_sinceChange = -1;
3918 }
3919
3920 m_updating = false;
3921 m_pcgoptUpdated = true;
3922
3923 lock.unlock();
3924 std::cerr << "got a coeffs: " << w << ' ' << h << ' ' << m_NaCurrent.size() << "\n";
3925 }
3926
3927 return 0;
3928}
3929
3931{
3932 static_cast<void>( dummy );
3933
3934 return 0;
3935}
3936
3937int modalGainOpt::processImage( void *curr_src, const bcoeffShmimT &dummy )
3938{
3939 static_cast<void>( dummy );
3940
3941 bool change = false;
3942
3943 std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
3944
3947
3948 // If there's a size change we lock
3949 if( w - 1 != m_bs.rows() || h != m_bs.cols() || h != m_NbCurrent.size() )
3950 {
3951 m_updating = true;
3952 lock.lock();
3953 m_updating = true; // Make sure it didn't get set to false by thread that
3954 // had the lock
3955
3956 change = true;
3957
3958 m_NbCurrent.resize( h );
3959 m_bs.resize( w - 1, h );
3960 }
3961
3962 eigenMap<float> bc( reinterpret_cast<float *>( curr_src ), w, h );
3963
3964 for( uint32_t cc = 0; cc < h; ++cc )
3965 {
3966 if( change || m_NbCurrent[cc] != bc( 0, cc ) )
3967 {
3968 if( !change )
3969 {
3970 m_updating = true;
3971 lock.lock();
3972 m_updating = true; // Make sure it didn't get set to false by thread
3973 // that had the lock
3974
3975 change = true;
3976 }
3977
3978 m_NbCurrent[cc] = bc( 0, cc );
3979 }
3980
3981 for( uint32_t rr = 1; rr < w; ++rr )
3982 {
3983 if( change || m_bs( rr - 1, cc ) != bc( rr, cc ) )
3984 {
3985 if( !change )
3986 {
3987 m_updating = true;
3988 lock.lock();
3989 m_updating = true; // Make sure it didn't get set to false by thread
3990 // that had the lock
3991
3992 change = true;
3993 }
3994
3995 m_bs( rr - 1, cc ) = bc( rr, cc );
3996 }
3997 }
3998 }
3999
4000 if( change )
4001 {
4002 if( m_loop && m_pcOn )
4003 {
4004 m_sinceChange = -1;
4005 }
4006
4007 m_updating = false;
4008 m_pcgoptUpdated = true;
4009
4010 std::cerr << "got b coeffs: " << w << ' ' << h << ' ' << m_NbCurrent.size() << "\n";
4011
4012 lock.unlock();
4013 }
4014
4015 return 0;
4016}
4017
4019{
4020 static_cast<void>( dummy );
4021
4022 return 0;
4023}
4024
4025int modalGainOpt::processImage( void *curr_src, const gainCalShmimT &dummy )
4026{
4027 static_cast<void>( dummy );
4028
4030 {
4031 return log<software_error, -1>( { "got gainCals with height not 1" } );
4032 }
4033
4034 bool change = false;
4035
4037
4038 std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
4039
4040 if( w != m_gainCals.size() )
4041 {
4042 m_updating = true;
4043 lock.lock();
4044
4045 m_updating = true; // Make sure it didn't get set to false by thread that
4046 // had the lock
4047
4048 change = true;
4049 m_gainCals.resize( w );
4050 }
4051
4052 float *g = static_cast<float *>( curr_src );
4053
4054 for( uint32_t n = 0; n < w; ++n )
4055 {
4056 if( change || m_gainCals[n] != g[n] )
4057 {
4058 if( !change )
4059 {
4060 m_updating = true;
4061 lock.lock();
4062 m_updating = true; // Make sure it didn't get set to false by thread
4063 // that had the lock
4064
4065 change = true;
4066 }
4067
4068 m_gainCals[n] = g[n];
4069 }
4070 }
4071
4072 if( change )
4073 {
4074 m_sinceChange = -1;
4075 m_updating = false;
4076 std::cerr << "got gainCals: " << m_gainCals.size() << "\n";
4077 lock.unlock();
4078 }
4079
4080 return 0;
4081}
4082
4084{
4085 static_cast<void>( dummy );
4086
4087 return 0;
4088}
4089
4090int modalGainOpt::processImage( void *curr_src, const gainCalFactShmimT &dummy )
4091{
4092 static_cast<void>( dummy );
4093
4095 {
4096 return log<software_error, -1>( { "got gainCalFacts with height not 1" } );
4097 }
4098
4099 bool change = false;
4100
4102
4103 std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
4104
4105 if( w != m_gainCalFacts.size() )
4106 {
4107 m_updating = true;
4108 lock.lock();
4109 m_updating = true; // Make sure it didn't get set to false by thread that
4110 // had the lock
4111
4112 change = true;
4113 m_gainCalFacts.resize( w );
4114 }
4115
4116 float *g = static_cast<float *>( curr_src );
4117
4118 for( uint32_t n = 0; n < w; ++n )
4119 {
4120 if( change || m_gainCalFacts[n] != g[n] )
4121 {
4122 if( !change )
4123 {
4124 m_updating = true;
4125 lock.lock();
4126 m_updating = true; // Make sure it didn't get set to false by thread
4127 // that had the lock
4128
4129 change = true;
4130 }
4131
4132 m_gainCalFacts[n] = g[n];
4133 }
4134 }
4135
4136 if( change )
4137 {
4138 m_sinceChange = -1;
4139 m_updating = false;
4140 std::cerr << "got gainCalsFacts: " << m_gainCalFacts.size() << "\n";
4141 lock.unlock();
4142 }
4143
4144 return 0;
4145}
4146
4148{
4149 static_cast<void>( dummy );
4150
4151 return 0;
4152}
4153
4154int modalGainOpt::processImage( void *curr_src, const tauShmimT &dummy )
4155{
4156 static_cast<void>( dummy );
4157
4159 {
4160 return log<software_error, -1>( { "got tau with height not 1" } );
4161 }
4162
4163 bool change = false;
4164
4166
4167 std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
4168
4169 if( w != m_taus.size() )
4170 {
4171 m_updating = true;
4172 lock.lock();
4173 m_updating = true; // Make sure it didn't get set to false by thread that
4174 // had the lock
4175
4176 change = true;
4177 m_taus.resize( w );
4178 }
4179
4180 float *t = static_cast<float *>( curr_src );
4181
4182 for( uint32_t n = 0; n < w; ++n )
4183 {
4184 if( change || m_taus[n] != t[n] )
4185 {
4186 if( !change )
4187 {
4188 m_updating = true;
4189 lock.lock();
4190 m_updating = true; // Make sure it didn't get set to false by thread
4191 // that had the lock
4192
4193 change = true;
4194 }
4195
4196 m_taus[n] = t[n];
4197 }
4198 }
4199
4200 if( change )
4201 {
4202 m_sinceChange = -1;
4203 m_updating = false;
4204 m_goptUpdated = true;
4205 std::cerr << "got taus: " << m_taus.size() << "\n";
4206 lock.unlock();
4207 }
4208 return 0;
4209}
4210
4212{
4213 static_cast<void>( dummy );
4214
4215 return 0;
4216}
4217
4218int modalGainOpt::processImage( void *curr_src, const noiseShmimT &dummy )
4219{
4220 static_cast<void>( dummy );
4221
4223 {
4224 return log<software_error, -1>( { "got tau with width not 3" } );
4225 }
4226
4227 bool change = false;
4228
4230
4231 std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
4232
4233 if( h != m_noiseParams.cols() )
4234 {
4235 m_updating = true;
4236 lock.lock();
4237 m_updating = true; // Make sure it didn't get set to false by thread that
4238 // had the lock
4239
4240 change = true;
4241 m_noiseParams.resize( 3, h );
4242 }
4243
4244 mx::improc::eigenMap<float> np( static_cast<float *>( curr_src ), 3, h );
4245
4246 for( uint32_t n = 0; n < h; ++n )
4247 {
4248 if( change || m_noiseParams( 0, n ) != np( 0, n ) || m_noiseParams( 1, n ) != np( 1, n ) ||
4249 m_noiseParams( 2, n ) != np( 2, n ) )
4250 {
4251 if( !change )
4252 {
4253 m_updating = true;
4254 lock.lock();
4255 m_updating = true; // Make sure it didn't get set to false by thread
4256 // that had the lock
4257
4258 change = true;
4259 }
4260
4261 m_noiseParams.col( n ) = np.col( n );
4262 }
4263 }
4264
4265 if( change )
4266 {
4267 m_sinceChange = -1;
4268 m_updating = false;
4269 m_goptUpdated = true;
4270 std::cerr << "got noise params: " << m_noiseParams.rows() << " x " << m_noiseParams.cols() << "\n";
4271 lock.unlock();
4272 }
4273 return 0;
4274}
4275
4277{
4278 static_cast<void>( dummy );
4279
4280 std::cerr << "Got WFS avg: " << wfsavgShmimMonitorT::m_width << " x " << wfsavgShmimMonitorT::m_height << '\n';
4281 return 0;
4282}
4283
4284int modalGainOpt::processImage( void *curr_src, const wfsavgShmimT &dummy )
4285{
4286 static_cast<void>( dummy );
4287
4288 { // mutex scope
4289 std::lock_guard<std::mutex> lock( m_goptMutex );
4290
4291 m_wfsavg = mx::improc::eigenMap<float>( reinterpret_cast<float *>( curr_src ),
4294
4295 if( m_wfsavg.rows() == m_wfsmask.rows() && m_wfsavg.cols() == m_wfsmask.cols() )
4296 {
4297 m_counts = ( m_wfsavg * m_wfsmask ).sum();
4298 }
4299 }
4300
4301 return 0;
4302}
4303
4305{
4306 static_cast<void>( dummy );
4307
4308 std::cerr << "Got WFS mask: " << wfsmaskShmimMonitorT::m_width << " x " << wfsmaskShmimMonitorT::m_height << '\n';
4309 return 0;
4310}
4311
4312int modalGainOpt::processImage( void *curr_src, const wfsmaskShmimT &dummy )
4313{
4314 static_cast<void>( dummy );
4315
4316 { // mutex scope
4317 std::lock_guard<std::mutex> lock( m_goptMutex );
4318
4319 m_wfsmask = mx::improc::eigenMap<float>( reinterpret_cast<float *>( curr_src ),
4322
4323 m_npix = m_wfsmask.sum();
4324
4325 if( m_wfsavg.rows() == m_wfsmask.rows() && m_wfsavg.cols() == m_wfsmask.cols() )
4326 {
4327 m_counts = ( m_wfsavg * m_wfsmask ).sum();
4328 }
4329 }
4330
4331 return 0;
4332}
4333
4335{
4336 static std::vector<bool> logged( 50, false );
4337
4338 int L = 0;
4339 if( m_clPSDs.rows() == 0 || m_clPSDs.cols() == 0 ) // somehow here without any data
4340 {
4341 if( !logged[L] )
4342 {
4343 log<software_error>( { "PSDs have not been updated" } );
4344 }
4345 logged[L] = true;
4346 return -1;
4347 }
4348 logged[L++] = false;
4349
4350 if( static_cast<size_t>( m_clPSDs.rows() ) != m_freq.size() )
4351 {
4352 if( !logged[L] )
4353 {
4354 log<software_error>( { "PSDs and freq size mismatch" } );
4355 }
4356 logged[L] = true;
4357 return -1;
4358 }
4359 logged[L++] = false;
4360
4361 if( m_nModes != m_gainFacts.size() )
4362 {
4363 if( !logged[L] )
4364 {
4365 log<software_error>( { "PSDs and gains number of modes mismatch" } );
4366 }
4367 logged[L] = true;
4368 return -1;
4369 }
4370 logged[L++] = false;
4371
4372 if( m_nModes != m_multFacts.size() )
4373 {
4374 if( !logged[L] )
4375 {
4376 log<software_error>( { "PSDs and mult coeffs number of modes mismatch" } );
4377 }
4378 logged[L] = true;
4379 return -1;
4380 }
4381 logged[L++] = false;
4382
4383 if( m_nModes != m_gainCals.size() )
4384 {
4385 if( !logged[L] )
4386 {
4387 log<software_error>( { "PSDs and gain cals number of modes mismatch" } );
4388 }
4389 logged[L] = true;
4390 return -1;
4391 }
4392 logged[L++] = false;
4393
4394 if( m_nModes != m_gainCalFacts.size() )
4395 {
4396 if( !logged[L] )
4397 {
4398 log<software_error>( { "PSDs and gain cal facts number of modes mismatch" } );
4399 }
4400 logged[L] = true;
4401 return -1;
4402 }
4403 logged[L++] = false;
4404
4405 if( m_nModes != m_taus.size() )
4406 {
4407 if( !logged[L] )
4408 {
4409 log<software_error>( { "Loop taus have not been set" } );
4410 }
4411 logged[L] = true;
4412 return -1;
4413 }
4414 logged[L++] = false;
4415
4416 /*if( m_clPSDs.cols() != m_noiseParams.cols() || m_noiseParams.rows() != 3 )
4417 {
4418 if( !logged[L] )
4419 {
4420 log<software_error>( { "noise params have not been set" } );
4421 }
4422 logged[L] = true;
4423 return -1;
4424 }
4425 logged[L++] = false;*/
4426
4427 if( m_fps <= 0 )
4428 {
4429 if( !logged[L] )
4430 {
4431 log<software_error>( { "Loop fps has not been set" } );
4432 }
4433 logged[L] = true;
4434 return -1;
4435 }
4436 logged[L++] = false;
4437
4438 if( m_olPSDStream == nullptr )
4439 {
4440 if( !logged[L] )
4441 {
4442 log<software_error>( { "m_olPSDStream is not allocated" } );
4443 }
4444 logged[L] = true;
4445 return -1;
4446 }
4447 logged[L++] = false;
4448
4449 if( m_rawOlPSDStream == nullptr )
4450 {
4451 if( !logged[L] )
4452 {
4453 log<software_error>( { "m_rawOlPSDStream is not allocated" } );
4454 }
4455 logged[L] = true;
4456 return -1;
4457 }
4458 logged[L++] = false;
4459
4460 if( m_smoothOlPSDStream == nullptr )
4461 {
4462 if( !logged[L] )
4463 {
4464 log<software_error>( { "m_smoothOlPSDStream is not allocated" } );
4465 }
4466 logged[L] = true;
4467 return -1;
4468 }
4469 logged[L++] = false;
4470
4471 if( m_noisePSDStream == nullptr )
4472 {
4473 if( !logged[L] )
4474 {
4475 log<software_error>( { "m_noisePSDStream is not allocated" } );
4476 }
4477 logged[L] = true;
4478 return -1;
4479 }
4480 logged[L++] = false;
4481
4482 if( m_clXferCurrentStream == nullptr )
4483 {
4484 if( !logged[L] )
4485 {
4486 log<software_error>( { "m_clXferCurrentStream is not allocated" } );
4487 }
4488 logged[L] = true;
4489 return -1;
4490 }
4491 logged[L++] = false;
4492
4493 if( m_clNtfCurrentStream == nullptr )
4494 {
4495 if( !logged[L] )
4496 {
4497 log<software_error>( { "m_clNtfCurrentStream is not allocated" } );
4498 }
4499 logged[L] = true;
4500 return -1;
4501 }
4502 logged[L++] = false;
4503
4504 if( m_clXferSIStream == nullptr )
4505 {
4506 if( !logged[L] )
4507 {
4508 log<software_error>( { "m_clXferSIStream is not allocated" } );
4509 }
4510 logged[L] = true;
4511 return -1;
4512 }
4513 logged[L++] = false;
4514
4515 if( m_clNtfSIStream == nullptr )
4516 {
4517 if( !logged[L] )
4518 {
4519 log<software_error>( { "m_clNtfSIStream is not allocated" } );
4520 }
4521 logged[L] = true;
4522 return -1;
4523 }
4524 logged[L++] = false;
4525
4526 if( m_optGainStream == nullptr )
4527 {
4528 if( !logged[L] )
4529 {
4530 log<software_error>( { "optGainsStream is not allocated" } );
4531 }
4532 logged[L] = true;
4533 return -1;
4534 }
4535 logged[L++] = false;
4536
4537 if( m_optGainSIStream == nullptr )
4538 {
4539 if( !logged[L] )
4540 {
4541 log<software_error>( { "optGainsStream SI is not allocated" } );
4542 }
4543 logged[L] = true;
4544 return -1;
4545 }
4546 logged[L++] = false;
4547
4548 if( m_optGainSIRawStream == nullptr )
4549 {
4550 if( !logged[L] )
4551 {
4552 log<software_error>( { "optGainsStream SI raw is not allocated" } );
4553 }
4554 logged[L] = true;
4555 return -1;
4556 }
4557 logged[L++] = false;
4558
4559 // Check the PC shmims that we don't automatically create
4560 if( m_Na.size() != m_nModes || m_NaCurrent.size() != m_nModes || (size_t)m_as.cols() != m_nModes ||
4561 m_Nb.size() != m_nModes || m_NbCurrent.size() != m_nModes || (size_t)m_bs.cols() != m_nModes ||
4562 m_pcGainFacts.size() != m_nModes || m_pcMultFacts.size() != m_nModes )
4563 {
4564
4565 if( allocatePCShmims() < 0 )
4566 {
4567 log<software_error>( { "error allocating PC shmims" } );
4568 }
4569
4570 if( m_Na.size() != m_nModes || m_NaCurrent.size() != m_nModes || (size_t)m_as.cols() != m_nModes ||
4571 m_Nb.size() != m_nModes || m_NbCurrent.size() != m_nModes || (size_t)m_bs.cols() != m_nModes ||
4572 m_pcGainFacts.size() != m_nModes || m_pcMultFacts.size() != m_nModes )
4573 {
4574
4575 if( !logged[L] )
4576 {
4577 log<software_error>( { "PC shmims not allcoated" } );
4578 }
4579 logged[L] = true;
4580 return -1;
4581 }
4582 else
4583 {
4584 logged[L] = false;
4585 }
4586 }
4587 else
4588 {
4589 logged[L] = false;
4590 }
4591 ++L;
4592
4593 if( m_clXferLPStream == nullptr )
4594 {
4595 if( !logged[L] )
4596 {
4597 log<software_error>( { "m_clXferLPStream is not allocated" } );
4598 }
4599 logged[L] = true;
4600 return -1;
4601 }
4602 logged[L++] = false;
4603
4604 if( m_clNtfLPStream == nullptr )
4605 {
4606 if( !logged[L] )
4607 {
4608 log<software_error>( { "m_clNtfLPStream is not allocated" } );
4609 }
4610 logged[L] = true;
4611 return -1;
4612 }
4613 logged[L++] = false;
4614
4615 if( m_optGainLPStream == nullptr )
4616 {
4617 if( !logged[L] )
4618 {
4619 log<software_error>( { "m_optGainLPStream is not allocated" } );
4620 }
4621 logged[L] = true;
4622 return -1;
4623 }
4624 logged[L++] = false;
4625
4626 if( m_nModes != m_optGainLP.size() )
4627 {
4628 if( !logged[L] )
4629 {
4630 log<software_error>( { "m_optGainLP is not allocated" } );
4631 }
4632 logged[L] = true;
4633 return -1;
4634 }
4635 logged[L++] = false;
4636
4637 return 0;
4638}
4639
4641{
4642 float mc = m_noiseParams( 1, n ) * m_counts / m_emg;
4643
4644 float snr2 = ( mc * mc ) / ( mc + m_npix * pow( m_noiseParams( 2, n ) / m_emg, 2 ) );
4645
4646 return 0.05 * m_noiseParams( 0, n ) / snr2;
4647}
4648
4653
4655{
4657
4658 while( m_goptThreadInit == true && shutdown() == 0 )
4659 {
4660 sleep( 1 );
4661 }
4662
4663 while( shutdown() == 0 )
4664 {
4665 timespec ts;
4666 XWC_SEM_WAIT_TS_RETVOID( ts, 1, 0 );
4667
4668 if( sem_timedwait( &m_goptSemaphore, &ts ) == 0 )
4669 {
4670 std::lock_guard<std::mutex> lock( m_goptMutex );
4671
4672 if( checkSizes() < 0 )
4673 {
4674 std::cerr << "check sizes failed\n";
4675 continue; // we just wait
4676 }
4677
4679
4681 if( m_updating )
4682 {
4683 continue;
4684 }
4685
4687 {
4689 }
4690
4691 if( m_zeroGains )
4692 {
4693 std::fill( m_optGainSI.begin(), m_optGainSI.end(), 0.0F );
4694 m_zeroGains = false;
4695 }
4696
4697 timePointT t0 = std::chrono::steady_clock::now();
4698
4700
4701 int off = 0;
4702 int offLP = 0;
4703
4704#pragma omp parallel for num_threads( 15 )
4705 for( size_t n = 0; n < m_goptCurrent.size(); ++n )
4706 {
4707 if( m_updating || m_shutdown )
4708 {
4709 continue; // don't break b/c of omp
4710 }
4711
4712 if( !m_pcOn )
4713 {
4716
4717 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
4718 {
4720 }
4721 }
4722 else
4723 {
4725 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
4726 {
4728 }
4729 }
4730
4732 // Calculate the OL PSD with the current gopt (PC or SI)
4734 std::vector<float> clMeasuredPsd( m_goptCurrent[n].f_size(), 0.0F );
4735 std::vector<float> etfCorrectionPsd( m_goptCurrent[n].f_size(), 1.0F );
4736 std::vector<float> ntfCorrectionPsd( m_goptCurrent[n].f_size(), 1.0F );
4737 if( !m_loop )
4738 {
4740 for( size_t f = 1; f < m_goptCurrent[n].f_size(); ++f )
4741 {
4742 clMeasuredPsd[f] = m_clPSDs( f, n ) / og2;
4743 m_olPSDs[n][f] = clMeasuredPsd[f];
4744 }
4745 }
4746 else
4747 {
4749 for( size_t f = 1; f < m_goptCurrent[n].f_size(); ++f )
4750 {
4751 clMeasuredPsd[f] = m_clPSDs( f, n ) / og2;
4755 }
4756 }
4757
4759
4763 m_olPSDs[n][0] = m_olPSDs[n][1];
4764
4765 bool flagOff = false;
4766 std::vector<float> lpProcessPsd = m_olPSDs[n];
4772 std::vector<float> noiseEstimateWorkPsd;
4773 std::vector<float> clSignificanceNoisePsd;
4774 float clSignificanceNoiseFloor = 0;
4777 const std::vector<float> *noiseEstimateSourcePsd =
4780 {
4781 const float tiny = std::numeric_limits<float>::min();
4782 noiseEstimateWorkPsd.resize( clMeasuredPsd.size(), 0.0F );
4783 for( size_t f = 0; f < clMeasuredPsd.size(); ++f )
4784 {
4786 }
4787
4789 }
4790
4792 {
4793 mx::error_t clSignificanceErr =
4797 m_freq,
4798 n,
4802 if( !!clSignificanceErr )
4803 {
4804#pragma omp critical
4805 {
4806 log<software_error>( { "error estimating raw CL modal significance noise PSD" } );
4807 }
4808
4809 continue;
4810 }
4811 }
4812
4814 {
4815 float noiseFloor = 0;
4816 mx::error_t errc =
4818 noiseFloor,
4820 m_freq,
4821 n,
4825 if( !!errc )
4826 {
4827#pragma omp critical
4828 {
4829 log<software_error>( { "error estimating modal noise PSD" } );
4830 }
4831
4832 continue;
4833 }
4834
4836 {
4837 const float tiny = std::numeric_limits<float>::min();
4838 for( size_t f = 1; f < m_goptCurrent[n].f_size(); ++f )
4839 {
4840 float closedLoopNoise = m_nPSDs[n][f];
4842 {
4843 closedLoopNoise *= std::max( ntfCorrectionPsd[f], tiny );
4844 }
4845
4846 m_olPSDs[n][f] = std::max( clMeasuredPsd[f] - closedLoopNoise, tiny ) /
4847 std::max( etfCorrectionPsd[f], tiny );
4848 }
4849
4850 m_olPSDs[n][0] = m_olPSDs[n][1];
4851 }
4852
4853 m_rawOlPSDs[n] = m_olPSDs[n];
4855 }
4856 else
4857 {
4860 processConfig.m_noiseEstimateDomain = extrapNoiseEstimateDomainName(
4864 processConfig.m_noiseEstimateStatistic =
4866 processConfig.m_noiseEstimateLowFreqMaxHz = m_extrapConfig.m_noiseEstimateLowFreqMaxHz;
4867 processConfig.m_closedLoopOlEstimateMethod =
4869
4871 const std::vector<float> &processMeasuredPsd =
4873 const std::vector<float> *processEtfPsd = useClosedLoopNoiseEstimate ? &etfCorrectionPsd : nullptr;
4874 const std::vector<float> *processNtfPsd = useClosedLoopNoiseEstimate ? &ntfCorrectionPsd : nullptr;
4875 mx::error_t errc =
4878 m_freq,
4879 n,
4881 0,
4884 processNtfPsd );
4885 if( !!errc )
4886 {
4887#pragma omp critical
4888 {
4890 __LINE__,
4891 "error processing modal PSD with method " +
4892 olProcessMethodName( m_extrapOL ) + ": [" +
4893 std::string( mx::errorName( errc ) ) + "] " +
4894 mx::errorMessage( errc ) } );
4896 "extrapolation settings: noiseDomain=" + processConfig.m_noiseEstimateDomain +
4897 " noiseRange=" + processConfig.m_noiseEstimateRange +
4898 " noiseStatistic=" + processConfig.m_noiseEstimateStatistic +
4899 " noiseLowMax=" + std::to_string( processConfig.m_noiseEstimateLowFreqMaxHz ) +
4900 " olEstimateMethod=" + processConfig.m_closedLoopOlEstimateMethod +
4901 " match=" + std::to_string( processConfig.m_powerLawMatchFreq ) +
4902 " matchWindow=" + std::to_string( processConfig.m_powerLawMatchFallbackWindowHz ) +
4903 " crossoverMode=" + processConfig.m_powerLawCrossoverMode +
4904 " autoSmooth=" + std::to_string( processConfig.m_powerLawAutoSmoothWidthHz ) +
4905 " autoMaxFrac=" + std::to_string( processConfig.m_powerLawAutoMaxFreqFraction ) +
4906 " fitIndex=" + std::string( processConfig.m_fitPowerLawIndex ? "true" : "false" ) +
4907 " fitMin=" + std::to_string( processConfig.m_powerLawFitMinFreqHz ) +
4908 " fitMax=" + std::to_string( processConfig.m_powerLawFitMaxFreqHz ) +
4909 " fitBin=" + std::to_string( processConfig.m_powerLawFitBinWidthHz ) +
4910 " blendBins=" + std::to_string( processConfig.m_powerLawBlendBins ) +
4911 " peakWidth=" + std::to_string( processConfig.m_peakDetectWidthHz ) +
4912 " peakFactor=" + std::to_string( processConfig.m_peakDetectFactor ) +
4913 " peakBroadFactor=" + std::to_string( processConfig.m_peakDetectBroadFactor ) +
4914 " peakMinWidthLog=" + std::to_string( processConfig.m_peakDetectMinWidthLog ) +
4915 " peakPasses=" + std::to_string( processConfig.m_peakDetectPasses ) +
4916 " peakBeta=" + std::to_string( processConfig.m_peakMoffatBeta ) +
4917 " dropoutGap=" + std::to_string( processConfig.m_dropoutGapFactor ) +
4918 " dropoutTiny=" + std::to_string( processConfig.m_dropoutTinyFactor ) +
4919 " dropoutMaxBins=" + std::to_string( processConfig.m_dropoutMaxBins ) +
4920 " powerLawOnlyAbove=" + std::to_string( processConfig.m_powerLawOnlyAboveFreq ),
4922 }
4923
4924 float noiseFloor = 0;
4925 mx::error_t noiseErr =
4927 noiseFloor,
4929 m_freq,
4930 n,
4931 processConfig.m_noiseEstimateRange,
4932 processConfig.m_noiseEstimateStatistic,
4933 processConfig.m_noiseEstimateLowFreqMaxHz );
4934 if( !!noiseErr )
4935 {
4936#pragma omp critical
4937 {
4938 log<software_error>( { "error estimating fallback modal noise PSD" } );
4939 }
4940
4941 continue;
4942 }
4943
4945 {
4946 const float tiny = std::numeric_limits<float>::min();
4947 for( size_t f = 1; f < m_goptCurrent[n].f_size(); ++f )
4948 {
4949 float closedLoopNoise = m_nPSDs[n][f];
4951 {
4952 closedLoopNoise *= std::max( ntfCorrectionPsd[f], tiny );
4953 }
4954
4955 m_olPSDs[n][f] = std::max( clMeasuredPsd[f] - closedLoopNoise, tiny ) /
4956 std::max( etfCorrectionPsd[f], tiny );
4957 }
4958
4959 m_olPSDs[n][0] = m_olPSDs[n][1];
4960 }
4961
4962 m_rawOlPSDs[n] = m_olPSDs[n];
4964 }
4965 else
4966 {
4967 m_nPSDs[n] = processResult.m_noisePsd;
4968 m_olPSDs[n] = processResult.m_processPsd;
4969 m_rawOlPSDs[n] = processResult.m_rawProcessPsd;
4970 m_smoothOlPSDs[n] = processResult.m_smoothedProcessPsd;
4971 lpProcessPsd = processResult.m_lpProcessPsd;
4972 }
4973 }
4974
4975 if( !flagOff && doClSignificanceCheck && clMeasuredPsd.size() > 1 )
4976 {
4977 size_t significantCount = 0;
4978 size_t totalCount = 0;
4979 for( size_t f = 1; f < clMeasuredPsd.size(); ++f )
4980 {
4981 ++totalCount;
4983 {
4985 }
4986 }
4987
4988 if( totalCount == 0 || static_cast<float>( significantCount ) / static_cast<float>( totalCount ) <
4990 {
4991 flagOff = true;
4992 }
4993 }
4994
4996
4997 if( flagOff )
4998 {
5000#pragma omp critical
5001 {
5002 ++off;
5003 }
5004
5005 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
5006 {
5007 m_olPSDs[n][f] = 0;
5008 }
5009
5010 m_modeVarOL[n] = mx::sigproc::psdVar( m_freq, m_olPSDs[n] );
5011
5012 m_optGainSIRaw[n] = 0;
5014
5015 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
5016 {
5017 m_clXferSI( f, n ) = 1;
5018 m_clNtfSI( f, n ) = 0;
5019 }
5020
5021 m_timesOnSI[n] = 0;
5022 }
5023 else
5024 {
5026
5028 m_modeVarOL[n] = mx::sigproc::psdVar( m_freq, m_olPSDs[n] );
5029
5030 m_optGainSIRaw[n] =
5031 m_goptSI[n].optGainOpenLoop( m_modeVarSI[n], m_olPSDs[n], m_nPSDs[n], m_gmaxSI[n], false );
5032
5033 if( ( m_modeVarSI[n] - m_modeVarOL[n] ) / m_modeVarOL[n] > -0.001 )
5034 {
5035#pragma omp critical
5036 {
5037 ++off;
5038 }
5039
5041 m_optGainSIRaw[n] = 0;
5043
5044 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
5045 {
5046 m_clXferSI( f, n ) = 1;
5047 m_clNtfSI( f, n ) = 0;
5048 }
5049
5050 m_timesOnSI[n] = 0;
5051 }
5052 else if( m_timesOnSI[n] < 5 )
5053 {
5054#pragma omp critical
5055 {
5056 ++off;
5057 }
5058
5060 // Would be on, but we debounce
5061 m_optGainSIRaw[n] = 0;
5063
5064 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
5065 {
5066 m_clXferSI( f, n ) = 1;
5067 m_clNtfSI( f, n ) = 0;
5068 }
5069
5070 ++m_timesOnSI[n];
5071 }
5072 else
5073 {
5075 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
5076 {
5077 m_goptSI[n].clTF2( m_clXferSI( f, n ), m_clNtfSI( f, n ), f, m_optGainSIRaw[n] );
5078 }
5079
5080 ++m_timesOnSI[n];
5081 }
5082 }
5083
5085
5086 if( m_doPCCalcs && !flagOff )
5087 {
5089 if( m_regScale[n] == -999 || m_regCounter[n] >= m_nRegCycles )
5090 {
5092 float min_sc;
5093 float gmax_lp = 0;
5094
5096 m_optGainLP[n],
5097 m_modeVarLP[n],
5098 min_sc,
5099 m_goptLP[n],
5101 m_nPSDs[n],
5102 m_Na[n] ) < 0 )
5103 {
5105
5106 m_optGainLP[n] = 0;
5108
5109 ///\todo what to do about coeffs?
5110 }
5111
5113
5114 if( m_regScale[n] == -999 )
5115 {
5118 }
5119 else
5120 {
5122 m_regCounter[n] = 0;
5123 }
5124
5125 m_regScale[n] = min_sc;
5126 m_gmaxLP[n] = gmax_lp;
5127 }
5128 else
5129 {
5131 // use pre-regularized version
5132 float psdReg = lpProcessPsd[0];
5134 m_nPSDs[n],
5135 psdReg * pow( 10, -m_regScale[n] / 10 ),
5136 m_Na[n] ) < 0 )
5137 {
5138 m_optGainLP[n] = 0;
5140
5141 ///\todo what to do about coeffs?
5142 }
5143 else
5144 {
5145 m_goptLP[n].a( m_linPred[n].m_lp.m_c );
5146 m_goptLP[n].b( m_linPred[n].m_lp.m_c );
5147
5148 m_optGainLP[n] = m_goptLP[n].optGainOpenLoop( m_modeVarLP[n],
5149 m_olPSDs[n],
5150 m_nPSDs[n],
5151 m_gmaxLP[n],
5152 false );
5153 }
5154 ++m_regCounter[n];
5155 }
5156
5158
5159 /*if( ( m_modeVarLP[n] - m_modeVarOL[n] ) / m_modeVarOL[n] > -0.001 )
5160 {
5161 m_optGainLP[n] = 0;
5162 m_modeVarLP[n] = m_modeVarOL[n];
5163
5164 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
5165 {
5166 m_clXferLP( f, n ) = 1;
5167 }
5168
5169 m_timesOnLP[n] = 0;
5170 }
5171 else*/
5172 if( ( m_modeVarLP[n] - m_modeVarSI[n] ) / m_modeVarSI[n] > -0.001 )
5173 {
5174#pragma omp critical
5175 {
5176 ++offLP;
5177 }
5178
5182
5183 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
5184 {
5185 m_clXferLP( f, n ) = m_clXferSI( f, n );
5186 m_clNtfLP( f, n ) = m_clNtfSI( f, n );
5187 }
5188
5189 m_timesOnLP[n] = 0;
5190 }
5191 else if( m_timesOnLP[n] < 5 )
5192 {
5193#pragma omp critical
5194 {
5195 ++offLP;
5196 }
5197
5201
5202 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
5203 {
5204 m_clXferLP( f, n ) = m_clXferSI( f, n );
5205 m_clNtfLP( f, n ) = m_clNtfSI( f, n );
5206 }
5207
5208 ++m_timesOnLP[n];
5209 }
5210 else
5211 {
5213 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
5214 {
5215 m_goptLP[n].clTF2( m_clXferLP( f, n ), m_clNtfLP( f, n ), f, m_optGainLP[n] );
5216 }
5217
5218 ++m_timesOnLP[n];
5219 }
5220 }
5221 else
5222 {
5223#pragma omp critical
5224 {
5225 ++offLP;
5226 }
5227
5229 m_optGainLP[n] = 0;
5230
5231 ++m_regCounter[n];
5232
5233 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
5234 {
5235 m_clXferLP( f, n ) = 1;
5236 m_clNtfLP( f, n ) = 0;
5237 }
5238
5239 m_timesOnLP[n] = 0;
5240 }
5241
5243 }
5244
5246
5249
5250 if( m_updating )
5251 {
5252 continue; // don't break b/c of omp
5253 }
5254
5255 timePointT t1 = std::chrono::steady_clock::now();
5256 durationT dt = t1 - t0;
5257
5258 std::cerr << "Optimization took " << dt.count() << " seconds\n";
5259
5260 /*float totVar = 0;
5261 for( size_t n = 0; n < m_modeVarSI.size(); ++n )
5262 {
5263 totVar += m_modeVarSI[n];
5264 }*/
5265
5266 // std::cerr << "total variance: " << totVar << '\n';
5267
5268 float *f = m_optGainStream->array.F;
5269 float *fSIRaw = m_optGainSIRawStream->array.F;
5270 float *fSI = m_optGainSIStream->array.F;
5271 float *fmaxSI = m_maxGainSIStream->array.F;
5272 float *fLP = m_optGainLPStream->array.F;
5273 float *fmaxLP = m_maxGainLPStream->array.F;
5274
5275 mx::improc::eigenMap<float> mvs( m_modevarStream->array.F, 3, m_modeVarSI.size() );
5276
5277 m_optGainStream->md->write = 1;
5278 m_optGainSIRawStream->md->write = 1;
5279 m_optGainSIStream->md->write = 1;
5280 m_maxGainSIStream->md->write = 1;
5281 m_optGainLPStream->md->write = 1;
5282 m_maxGainLPStream->md->write = 1;
5283 m_modevarStream->md->write = 1;
5284
5286
5294
5295 if( m_autoUpdate || m_updateOnce || m_dump )
5296 {
5297 float *f = gainFactShmimMonitorT::m_imageStream.array.F;
5298
5300 for( size_t n = 0; n < m_nModes; ++n )
5301 {
5303 }
5304
5306
5307 if( m_doPCCalcs )
5308 {
5310 float *fa = acoeffShmimMonitorT::m_imageStream.array.F;
5311 float *fb = bcoeffShmimMonitorT::m_imageStream.array.F;
5312
5316
5318 fa,
5320 fb,
5322 !m_dump );
5323
5327 }
5328
5329 if( m_dump )
5330 {
5331 log<text_log>( "gains updated by dump", logPrio::LOG_NOTICE );
5332 m_dump = false;
5333 }
5334 else if( m_updateOnce && !m_autoUpdate )
5335 {
5336 log<text_log>( "gains updated once", logPrio::LOG_NOTICE );
5337 }
5338
5339 m_updateOnce = false;
5340 }
5341
5342 if( m_loop & m_autoUpdate )
5343 {
5344 m_sinceChange = -1;
5345 }
5346
5347 // Update OL PSDs and Transfer Functions
5348 m_olPSDStream->md->write = 1;
5349 m_rawOlPSDStream->md->write = 1;
5350 m_smoothOlPSDStream->md->write = 1;
5351 m_noisePSDStream->md->write = 1;
5352 m_clXferCurrentStream->md->write = 1;
5353 m_clNtfCurrentStream->md->write = 1;
5354 m_clXferSIStream->md->write = 1;
5355 m_clNtfSIStream->md->write = 1;
5356 m_clXferLPStream->md->write = 1;
5357 m_clNtfLPStream->md->write = 1;
5358
5359 for( size_t q = 0; q < m_olPSDs.size(); ++q )
5360 {
5361 memcpy( m_olPSDStream->array.F + q * m_olPSDs[0].size(),
5362 m_olPSDs[q].data(),
5363 m_olPSDs[0].size() * sizeof( float ) );
5364 memcpy( m_rawOlPSDStream->array.F + q * m_rawOlPSDs[0].size(),
5365 m_rawOlPSDs[q].data(),
5366 m_rawOlPSDs[0].size() * sizeof( float ) );
5367 memcpy( m_smoothOlPSDStream->array.F + q * m_smoothOlPSDs[0].size(),
5368 m_smoothOlPSDs[q].data(),
5369 m_smoothOlPSDs[0].size() * sizeof( float ) );
5370
5371 // m_noisePSDStream->array.F[q] = m_nPSDs[q][0];
5372 memcpy( m_noisePSDStream->array.F + q * m_nPSDs[0].size(),
5373 m_nPSDs[q].data(),
5374 m_nPSDs[0].size() * sizeof( float ) );
5375 }
5376
5377 memcpy( m_clXferCurrentStream->array.F,
5378 m_clXferCurrent.data(),
5379 m_clXferCurrent.rows() * m_clXferCurrent.cols() * sizeof( float ) );
5380 memcpy( m_clNtfCurrentStream->array.F,
5381 m_clNtfCurrent.data(),
5382 m_clNtfCurrent.rows() * m_clNtfCurrent.cols() * sizeof( float ) );
5383 memcpy( m_clXferSIStream->array.F,
5384 m_clXferSI.data(),
5385 m_clXferSI.rows() * m_clXferSI.cols() * sizeof( float ) );
5386 memcpy( m_clNtfSIStream->array.F, m_clNtfSI.data(), m_clNtfSI.rows() * m_clNtfSI.cols() * sizeof( float ) );
5387 memcpy( m_clXferLPStream->array.F,
5388 m_clXferLP.data(),
5389 m_clXferLP.rows() * m_clXferLP.cols() * sizeof( float ) );
5390 memcpy( m_clNtfLPStream->array.F, m_clNtfLP.data(), m_clNtfLP.rows() * m_clNtfLP.cols() * sizeof( float ) );
5391
5402 }
5403 else
5404 {
5405 /* Check for why we timed out */
5406 /* ETIMEDOUT just means keep waiting */
5407 if( errno == ETIMEDOUT )
5408 {
5409 std::lock_guard<std::mutex> lock( m_goptMutex );
5410
5411 if( checkSizes() >= 0 )
5412 {
5414 }
5415 continue;
5416 }
5417
5418 /* EINTER probably indicates time to shutdown, loop wil exit if m_shutdown
5419 * is set */
5420 if( errno == EINTR )
5421 {
5422 continue;
5423 }
5424
5425 /*Otherwise, report an error.*/
5426 log<software_error>( { errno, "sem_timedwait" } );
5427 break;
5428 }
5429 }
5430}
5431
5432INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_autoUpdate )
5433( const pcf::IndiProperty &ipRecv )
5434{
5435 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_autoUpdate, ipRecv );
5436
5437 if( ipRecv.find( "toggle" ) )
5438 {
5439 recordModalGainOpt( false );
5440 {
5441 std::lock_guard<std::mutex> lock( m_goptMutex );
5442
5443 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On )
5444 {
5445 if( !m_autoUpdate )
5446 {
5447 log<text_log>( "updating gains", logPrio::LOG_NOTICE );
5448 }
5449 m_autoUpdate = true;
5450 }
5451 else
5452 {
5453 if( m_autoUpdate )
5454 {
5455 log<text_log>( "stopped updating gains", logPrio::LOG_NOTICE );
5456 }
5457 m_autoUpdate = false;
5458 }
5459 }
5460
5461 recordModalGainOpt( false );
5462 }
5463
5464 return 0;
5465}
5466
5467INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_updateOnce )
5468( const pcf::IndiProperty &ipRecv )
5469{
5470 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_updateOnce, ipRecv );
5471
5472 if( ipRecv.find( "request" ) )
5473 {
5474 std::lock_guard<std::mutex> lock( m_goptMutex );
5475
5476 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On )
5477 {
5478 m_updateOnce = true;
5479 }
5480 else
5481 {
5482 m_updateOnce = false;
5483 }
5484 }
5485
5486 return 0;
5487}
5488
5489INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_dump )
5490( const pcf::IndiProperty &ipRecv )
5491{
5492 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_dump, ipRecv );
5493
5494 if( ipRecv.find( "request" ) )
5495 {
5496 std::lock_guard<std::mutex> lock( m_goptMutex );
5497
5498 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On )
5499 {
5500 m_dump = true;
5501 }
5502 else
5503 {
5504 m_dump = false;
5505 }
5506 }
5507
5508 return 0;
5509}
5510
5511INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_opticalGain )
5512( const pcf::IndiProperty &ipRecv )
5513{
5514 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_opticalGain, ipRecv );
5515
5516 float target;
5517 if( indiTargetUpdate( m_indiP_opticalGain, target, ipRecv, true ) < 0 )
5518 {
5519 log<software_error>( { __FILE__, __LINE__ } );
5520 return -1;
5521 }
5522
5523 { // mutex scope
5524 recordModalGainOpt( false );
5525
5526 std::lock_guard<std::mutex> lock( m_goptMutex );
5528 }
5529
5531
5532 return 0;
5533}
5534
5535INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_opticalGainUpdate )
5536( const pcf::IndiProperty &ipRecv )
5537{
5538 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_opticalGainUpdate, ipRecv );
5539
5540 if( ipRecv.find( "toggle" ) )
5541 {
5542 recordModalGainOpt( false );
5543 {
5544 std::lock_guard<std::mutex> lock( m_goptMutex );
5545
5546 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::Off )
5547 {
5548 m_opticalGainUpdate = false;
5549 }
5550 else
5551 {
5552 m_opticalGainUpdate = true;
5553
5554 if( m_opticalGainSource > 0 && m_opticalGainSource < 1 )
5555 {
5556 m_opticalGain = m_opticalGainSource;
5557 }
5558 }
5559 }
5560
5561 recordModalGainOpt( false );
5562 }
5563
5564 return 0;
5565}
5566
5567INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_opticalGainSource )
5568( const pcf::IndiProperty &ipRecv )
5569{
5570 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_opticalGainSource, ipRecv );
5571
5572 if( ipRecv.find( m_opticalGainElement ) )
5573 {
5574 recordModalGainOpt( false );
5575 {
5576 std::lock_guard<std::mutex> lock( m_goptMutex );
5577
5578 float opticalg = ipRecv[m_opticalGainElement].get<float>();
5579
5580 opticalg = ( floor( opticalg * 100 + 0.5 ) ) / 100.;
5581
5582 if( opticalg > 0 && opticalg < 1 )
5583 {
5584 m_opticalGainSource = opticalg;
5585 }
5586
5587 if( m_opticalGainUpdate )
5588 {
5589 m_opticalGain = m_opticalGainSource;
5590 }
5591 }
5592
5593 recordModalGainOpt( false );
5594 }
5595 return 0;
5596}
5597
5598INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_gainGain )
5599( const pcf::IndiProperty &ipRecv )
5600{
5601 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_gainGain, ipRecv );
5602
5603 float target;
5604 if( indiTargetUpdate( m_indiP_gainGain, target, ipRecv, true ) < 0 )
5605 {
5606 log<software_error>( { __FILE__, __LINE__ } );
5607 return -1;
5608 }
5609
5610 { // mutex scope
5611 recordModalGainOpt( false );
5612
5613 std::lock_guard<std::mutex> lock( m_goptMutex );
5615 }
5616
5617 recordModalGainOpt( false );
5618
5619 return 0;
5620}
5621
5622INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_gainLeak )
5623( const pcf::IndiProperty &ipRecv )
5624{
5625 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_gainLeak, ipRecv );
5626
5627 float target;
5628 if( indiTargetUpdate( m_indiP_gainLeak, target, ipRecv, true ) < 0 )
5629 {
5630 log<software_error>( { __FILE__, __LINE__ } );
5631 return -1;
5632 }
5633
5634 { // mutex scope
5635 recordModalGainOpt( false );
5636
5637 std::lock_guard<std::mutex> lock( m_goptMutex );
5639 }
5640
5641 recordModalGainOpt( false );
5642
5643 return 0;
5644}
5645
5646INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_zeroGains )
5647( const pcf::IndiProperty &ipRecv )
5648{
5649 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_zeroGains, ipRecv );
5650
5651 if( ipRecv.find( "request" ) )
5652 {
5653 std::lock_guard<std::mutex> lock( m_goptMutex );
5654
5655 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On )
5656 {
5657 std::fill( m_optGainSI.begin(), m_optGainSI.end(), 0.0F );
5658 m_siGainStateNeedsSync = false;
5659 m_zeroGains = true;
5660 }
5661 else
5662 {
5663 m_zeroGains = false;
5664 }
5665 }
5666
5667 return 0;
5668}
5669
5670template <typename valueT>
5671int modalGainOpt::handleExtrapNumberProperty( pcf::IndiProperty &localProperty,
5672 valueT &localTarget,
5673 const pcf::IndiProperty &ipRecv,
5674 const std::string &label )
5675{
5676 valueT target;
5677 if( indiTargetUpdate( localProperty, target, ipRecv, true ) < 0 )
5678 {
5680 return -1;
5681 }
5682
5683 if( target != localTarget )
5684 {
5685 m_updating = true;
5686 std::lock_guard<std::mutex> lock( m_goptMutex );
5687 m_updating = true;
5688
5690
5691 m_sinceChange = -1;
5692 m_updating = false;
5693 std::cerr << "Got " << label << ": " << localTarget << '\n';
5694 }
5695
5696 return 0;
5697}
5698
5699int modalGainOpt::handleExtrapToggleProperty( pcf::IndiProperty &localProperty,
5700 bool &localTarget,
5701 const pcf::IndiProperty &ipRecv,
5702 const std::string &label )
5703{
5704 static_cast<void>( localProperty );
5705
5706 if( !ipRecv.find( "toggle" ) )
5707 {
5708 return log<software_error, -1>( { "Missing toggle element for " + label } );
5709 }
5710
5711 bool target = ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On;
5712
5713 if( target != localTarget )
5714 {
5715 m_updating = true;
5716 std::lock_guard<std::mutex> lock( m_goptMutex );
5717 m_updating = true;
5718
5720
5721 m_sinceChange = -1;
5722 m_updating = false;
5723 std::cerr << "Got " << label << ": " << extrapBoolString( localTarget ) << '\n';
5724 }
5725
5726 return 0;
5727}
5728
5730{
5731 int target = c_olProcessNone;
5732 bool found = false;
5733 for( auto elit = ipRecv.getElements().begin(); elit != ipRecv.getElements().end(); ++elit )
5734 {
5735 if( elit->second.getSwitchState() != pcf::IndiElement::On )
5736 {
5737 continue;
5738 }
5739
5740 if( found )
5741 {
5742 return log<software_error, -1>( { "Multiple extrapolation methods selected in one update" } );
5743 }
5744
5747 {
5748 return log<software_error, -1>( { "Invalid extrapolation method element: " + elit->first } );
5749 }
5750
5751 found = true;
5752 }
5753
5754 if( !found )
5755 {
5757 {
5758 std::lock_guard<std::mutex> lock( m_goptMutex );
5760 }
5761
5762 const std::string currentElement = olProcessMethodElement( current );
5764 {
5765 for( auto elit = m_indiP_extrapMethod.getElements().begin();
5766 elit != m_indiP_extrapMethod.getElements().end();
5767 ++elit )
5768 {
5769 m_indiP_extrapMethod[elit->first].setSwitchState(
5770 elit->first == currentElement ? pcf::IndiElement::On : pcf::IndiElement::Off );
5771 }
5772 m_indiP_extrapMethod.setState( pcf::IndiProperty::Ok );
5773 }
5774
5776 return 0;
5777 }
5778
5779 if( target != m_extrapOL )
5780 {
5781 m_updating = true;
5782 std::lock_guard<std::mutex> lock( m_goptMutex );
5783 m_updating = true;
5784
5786
5787 m_sinceChange = -1;
5788 m_updating = false;
5789 std::cerr << "Got extrapolation method: " << olProcessMethodName( m_extrapOL ) << '\n';
5790 }
5791
5792 return 0;
5793}
5794
5796{
5798 bool found = false;
5799 for( auto elit = ipRecv.getElements().begin(); elit != ipRecv.getElements().end(); ++elit )
5800 {
5801 if( elit->second.getSwitchState() != pcf::IndiElement::On )
5802 {
5803 continue;
5804 }
5805
5806 if( found )
5807 {
5808 return log<software_error, -1>( { "Multiple noise-estimate domains selected in one update" } );
5809 }
5810
5814 {
5815 return log<software_error, -1>( { "Invalid noise-estimate-domain element: " + elit->first } );
5816 }
5817
5818 found = true;
5819 }
5820
5821 if( !found )
5822 {
5824 {
5825 std::lock_guard<std::mutex> lock( m_goptMutex );
5827 }
5828
5831 {
5832 for( auto elit = m_indiP_extrapNoiseEstimateDomain.getElements().begin();
5833 elit != m_indiP_extrapNoiseEstimateDomain.getElements().end();
5834 ++elit )
5835 {
5836 m_indiP_extrapNoiseEstimateDomain[elit->first].setSwitchState(
5837 elit->first == currentElement ? pcf::IndiElement::On : pcf::IndiElement::Off );
5838 }
5839 m_indiP_extrapNoiseEstimateDomain.setState( pcf::IndiProperty::Ok );
5840 }
5841
5845 INDI_OK );
5846 return 0;
5847 }
5848
5850 {
5851 m_updating = true;
5852 std::lock_guard<std::mutex> lock( m_goptMutex );
5853 m_updating = true;
5854
5857
5858 m_sinceChange = -1;
5859 m_updating = false;
5860 std::cerr << "Got noise-estimate domain: " << extrapNoiseEstimateDomainName( target ) << '\n';
5861 }
5862
5863 return 0;
5864}
5865
5867{
5869 bool found = false;
5870 for( auto elit = ipRecv.getElements().begin(); elit != ipRecv.getElements().end(); ++elit )
5871 {
5872 if( elit->second.getSwitchState() != pcf::IndiElement::On )
5873 {
5874 continue;
5875 }
5876
5877 if( found )
5878 {
5879 return log<software_error, -1>( { "Multiple noise-estimate ranges selected in one update" } );
5880 }
5881
5885 {
5886 return log<software_error, -1>( { "Invalid noise-estimate-range element: " + elit->first } );
5887 }
5888
5889 found = true;
5890 }
5891
5892 if( !found )
5893 {
5895 {
5896 std::lock_guard<std::mutex> lock( m_goptMutex );
5898 }
5899
5902 {
5903 for( auto elit = m_indiP_extrapNoiseEstimateRange.getElements().begin();
5904 elit != m_indiP_extrapNoiseEstimateRange.getElements().end();
5905 ++elit )
5906 {
5907 m_indiP_extrapNoiseEstimateRange[elit->first].setSwitchState(
5908 elit->first == currentElement ? pcf::IndiElement::On : pcf::IndiElement::Off );
5909 }
5910 m_indiP_extrapNoiseEstimateRange.setState( pcf::IndiProperty::Ok );
5911 }
5912
5914 return 0;
5915 }
5916
5918 {
5919 m_updating = true;
5920 std::lock_guard<std::mutex> lock( m_goptMutex );
5921 m_updating = true;
5922
5925
5926 m_sinceChange = -1;
5927 m_updating = false;
5928 std::cerr << "Got noise-estimate range: " << extrapNoiseEstimateRangeName( target ) << '\n';
5929 }
5930
5931 return 0;
5932}
5933
5935{
5937 bool found = false;
5938 for( auto elit = ipRecv.getElements().begin(); elit != ipRecv.getElements().end(); ++elit )
5939 {
5940 if( elit->second.getSwitchState() != pcf::IndiElement::On )
5941 {
5942 continue;
5943 }
5944
5945 if( found )
5946 {
5947 return log<software_error, -1>( { "Multiple noise-estimate statistics selected in one update" } );
5948 }
5949
5953 {
5954 return log<software_error, -1>( { "Invalid noise-estimate-statistic element: " + elit->first } );
5955 }
5956
5957 found = true;
5958 }
5959
5960 if( !found )
5961 {
5963 {
5964 std::lock_guard<std::mutex> lock( m_goptMutex );
5966 }
5967
5970 {
5971 for( auto elit = m_indiP_extrapNoiseEstimateStatistic.getElements().begin();
5972 elit != m_indiP_extrapNoiseEstimateStatistic.getElements().end();
5973 ++elit )
5974 {
5975 m_indiP_extrapNoiseEstimateStatistic[elit->first].setSwitchState(
5976 elit->first == currentElement ? pcf::IndiElement::On : pcf::IndiElement::Off );
5977 }
5978 m_indiP_extrapNoiseEstimateStatistic.setState( pcf::IndiProperty::Ok );
5979 }
5980
5984 INDI_OK );
5985 return 0;
5986 }
5987
5989 {
5990 m_updating = true;
5991 std::lock_guard<std::mutex> lock( m_goptMutex );
5992 m_updating = true;
5993
5996
5997 m_sinceChange = -1;
5998 m_updating = false;
5999 std::cerr << "Got noise-estimate statistic: " << extrapNoiseEstimateStatisticName( target ) << '\n';
6000 }
6001
6002 return 0;
6003}
6004
6006{
6008 bool found = false;
6009 for( auto elit = ipRecv.getElements().begin(); elit != ipRecv.getElements().end(); ++elit )
6010 {
6011 if( elit->second.getSwitchState() != pcf::IndiElement::On )
6012 {
6013 continue;
6014 }
6015
6016 if( found )
6017 {
6018 return log<software_error, -1>( { "Multiple closed-loop OL estimate methods selected in one update" } );
6019 }
6020
6024 {
6025 return log<software_error, -1>( { "Invalid closed-loop-OL-estimate-method element: " + elit->first } );
6026 }
6027
6028 found = true;
6029 }
6030
6031 if( !found )
6032 {
6034 {
6035 std::lock_guard<std::mutex> lock( m_goptMutex );
6037 }
6038
6041 {
6042 for( auto elit = m_indiP_extrapClosedLoopOlEstimateMethod.getElements().begin();
6043 elit != m_indiP_extrapClosedLoopOlEstimateMethod.getElements().end();
6044 ++elit )
6045 {
6046 m_indiP_extrapClosedLoopOlEstimateMethod[elit->first].setSwitchState(
6047 elit->first == currentElement ? pcf::IndiElement::On : pcf::IndiElement::Off );
6048 }
6049 m_indiP_extrapClosedLoopOlEstimateMethod.setState( pcf::IndiProperty::Ok );
6050 }
6051
6055 INDI_OK );
6056 return 0;
6057 }
6058
6060 {
6061 m_updating = true;
6062 std::lock_guard<std::mutex> lock( m_goptMutex );
6063 m_updating = true;
6064
6067
6068 m_sinceChange = -1;
6069 m_updating = false;
6070 std::cerr << "Got closed-loop OL estimate method: " << extrapClosedLoopOlEstimateMethodName( target ) << '\n';
6071 }
6072
6073 return 0;
6074}
6075
6077{
6079 bool found = false;
6080 for( auto elit = ipRecv.getElements().begin(); elit != ipRecv.getElements().end(); ++elit )
6081 {
6082 if( elit->second.getSwitchState() != pcf::IndiElement::On )
6083 {
6084 continue;
6085 }
6086
6087 if( found )
6088 {
6089 return log<software_error, -1>( { "Multiple power-law crossover modes selected in one update" } );
6090 }
6091
6095 {
6096 return log<software_error, -1>( { "Invalid power-law-crossover-mode element: " + elit->first } );
6097 }
6098
6099 found = true;
6100 }
6101
6102 if( !found )
6103 {
6105 {
6106 std::lock_guard<std::mutex> lock( m_goptMutex );
6108 }
6109
6112 {
6113 for( auto elit = m_indiP_extrapPowerLawCrossoverMode.getElements().begin();
6114 elit != m_indiP_extrapPowerLawCrossoverMode.getElements().end();
6115 ++elit )
6116 {
6117 m_indiP_extrapPowerLawCrossoverMode[elit->first].setSwitchState(
6118 elit->first == currentElement ? pcf::IndiElement::On : pcf::IndiElement::Off );
6119 }
6120 m_indiP_extrapPowerLawCrossoverMode.setState( pcf::IndiProperty::Ok );
6121 }
6122
6126 INDI_OK );
6127 return 0;
6128 }
6129
6131 {
6132 m_updating = true;
6133 std::lock_guard<std::mutex> lock( m_goptMutex );
6134 m_updating = true;
6135
6138
6139 m_sinceChange = -1;
6140 m_updating = false;
6141 std::cerr << "Got power-law crossover mode: " << extrapPowerLawCrossoverModeName( target ) << '\n';
6142 }
6143
6144 return 0;
6145}
6146
6147INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapMethod )
6148( const pcf::IndiProperty &ipRecv )
6149{
6150 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapMethod, ipRecv );
6152}
6153
6154INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapNoiseEstimateDomain )
6155( const pcf::IndiProperty &ipRecv )
6156{
6157 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapNoiseEstimateDomain, ipRecv );
6159}
6160
6161INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapNoiseEstimateRange )
6162( const pcf::IndiProperty &ipRecv )
6163{
6164 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapNoiseEstimateRange, ipRecv );
6166}
6167
6168INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapNoiseEstimateStatistic )
6169( const pcf::IndiProperty &ipRecv )
6170{
6171 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapNoiseEstimateStatistic, ipRecv );
6173}
6174
6175INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapNoiseEstimateLowFreqMaxHz )
6176( const pcf::IndiProperty &ipRecv )
6177{
6178 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapNoiseEstimateLowFreqMaxHz, ipRecv );
6179 return handleExtrapNumberProperty( m_indiP_extrapNoiseEstimateLowFreqMaxHz,
6180 m_extrapConfig.m_noiseEstimateLowFreqMaxHz,
6181 ipRecv,
6182 "extrap noise-estimate low-freq max hz" );
6183}
6184
6185INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapClosedLoopOlEstimateMethod )
6186( const pcf::IndiProperty &ipRecv )
6187{
6188 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapClosedLoopOlEstimateMethod, ipRecv );
6190}
6191
6192INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapPowerLawIndex )
6193( const pcf::IndiProperty &ipRecv )
6194{
6195 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapPowerLawIndex, ipRecv );
6196 return handleExtrapNumberProperty( m_indiP_extrapPowerLawIndex,
6197 m_extrapConfig.m_powerLawIndex,
6198 ipRecv,
6199 "extrap power-law index" );
6200}
6201
6202INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapPowerLawNormFreq )
6203( const pcf::IndiProperty &ipRecv )
6204{
6205 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapPowerLawNormFreq, ipRecv );
6206 return handleExtrapNumberProperty( m_indiP_extrapPowerLawNormFreq,
6207 m_extrapConfig.m_powerLawNormFreq,
6208 ipRecv,
6209 "extrap power-law norm freq" );
6210}
6211
6212INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapPowerLawMatchFreq )
6213( const pcf::IndiProperty &ipRecv )
6214{
6215 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapPowerLawMatchFreq, ipRecv );
6216 return handleExtrapNumberProperty( m_indiP_extrapPowerLawMatchFreq,
6217 m_extrapConfig.m_powerLawMatchFreq,
6218 ipRecv,
6219 "extrap power-law match freq" );
6220}
6221
6222INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapPowerLawMatchFallbackWindowHz )
6223( const pcf::IndiProperty &ipRecv )
6224{
6225 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapPowerLawMatchFallbackWindowHz, ipRecv );
6226 return handleExtrapNumberProperty( m_indiP_extrapPowerLawMatchFallbackWindowHz,
6227 m_extrapConfig.m_powerLawMatchFallbackWindowHz,
6228 ipRecv,
6229 "extrap power-law match fallback window" );
6230}
6231
6232INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapPowerLawCrossoverMode )
6233( const pcf::IndiProperty &ipRecv )
6234{
6235 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapPowerLawCrossoverMode, ipRecv );
6237}
6238
6239INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapPowerLawAutoSmoothWidthHz )
6240( const pcf::IndiProperty &ipRecv )
6241{
6242 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapPowerLawAutoSmoothWidthHz, ipRecv );
6243 return handleExtrapNumberProperty( m_indiP_extrapPowerLawAutoSmoothWidthHz,
6244 m_extrapConfig.m_powerLawAutoSmoothWidthHz,
6245 ipRecv,
6246 "extrap power-law auto smooth width" );
6247}
6248
6249INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapPowerLawAutoMaxFreqFraction )
6250( const pcf::IndiProperty &ipRecv )
6251{
6252 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapPowerLawAutoMaxFreqFraction, ipRecv );
6253 return handleExtrapNumberProperty( m_indiP_extrapPowerLawAutoMaxFreqFraction,
6254 m_extrapConfig.m_powerLawAutoMaxFreqFraction,
6255 ipRecv,
6256 "extrap power-law auto max freq fraction" );
6257}
6258
6259INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapFitPowerLawIndex )
6260( const pcf::IndiProperty &ipRecv )
6261{
6262 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapFitPowerLawIndex, ipRecv );
6263 return handleExtrapToggleProperty( m_indiP_extrapFitPowerLawIndex,
6264 m_extrapConfig.m_fitPowerLawIndex,
6265 ipRecv,
6266 "extrap fit power-law index" );
6267}
6268
6269INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapPowerLawOnlyAboveFreq )
6270( const pcf::IndiProperty &ipRecv )
6271{
6272 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapPowerLawOnlyAboveFreq, ipRecv );
6273 return handleExtrapNumberProperty( m_indiP_extrapPowerLawOnlyAboveFreq,
6274 m_extrapConfig.m_powerLawOnlyAboveFreq,
6275 ipRecv,
6276 "extrap power-law only above freq" );
6277}
6278
6279INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapPowerLawFitIncludesMatchPoint )
6280( const pcf::IndiProperty &ipRecv )
6281{
6282 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapPowerLawFitIncludesMatchPoint, ipRecv );
6283 return handleExtrapToggleProperty( m_indiP_extrapPowerLawFitIncludesMatchPoint,
6284 m_extrapConfig.m_powerLawFitIncludesMatchPoint,
6285 ipRecv,
6286 "extrap fit includes match point" );
6287}
6288
6289INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapPowerLawFitMinFreqHz )
6290( const pcf::IndiProperty &ipRecv )
6291{
6292 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapPowerLawFitMinFreqHz, ipRecv );
6293 return handleExtrapNumberProperty( m_indiP_extrapPowerLawFitMinFreqHz,
6294 m_extrapConfig.m_powerLawFitMinFreqHz,
6295 ipRecv,
6296 "extrap fit min freq" );
6297}
6298
6299INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapPowerLawFitMaxFreqHz )
6300( const pcf::IndiProperty &ipRecv )
6301{
6302 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapPowerLawFitMaxFreqHz, ipRecv );
6303 return handleExtrapNumberProperty( m_indiP_extrapPowerLawFitMaxFreqHz,
6304 m_extrapConfig.m_powerLawFitMaxFreqHz,
6305 ipRecv,
6306 "extrap fit max freq" );
6307}
6308
6309INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapPowerLawFitBinWidthHz )
6310( const pcf::IndiProperty &ipRecv )
6311{
6312 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapPowerLawFitBinWidthHz, ipRecv );
6313 return handleExtrapNumberProperty( m_indiP_extrapPowerLawFitBinWidthHz,
6314 m_extrapConfig.m_powerLawFitBinWidthHz,
6315 ipRecv,
6316 "extrap fit bin width" );
6317}
6318
6319INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapPowerLawBlendBins )
6320( const pcf::IndiProperty &ipRecv )
6321{
6322 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapPowerLawBlendBins, ipRecv );
6323 return handleExtrapNumberProperty( m_indiP_extrapPowerLawBlendBins,
6324 m_extrapConfig.m_powerLawBlendBins,
6325 ipRecv,
6326 "extrap power-law blend bins" );
6327}
6328
6329INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapDropoutGapFactor )
6330( const pcf::IndiProperty &ipRecv )
6331{
6332 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapDropoutGapFactor, ipRecv );
6333 return handleExtrapNumberProperty( m_indiP_extrapDropoutGapFactor,
6334 m_extrapConfig.m_dropoutGapFactor,
6335 ipRecv,
6336 "extrap dropout gap factor" );
6337}
6338
6339INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapDropoutTinyFactor )
6340( const pcf::IndiProperty &ipRecv )
6341{
6342 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapDropoutTinyFactor, ipRecv );
6343 return handleExtrapNumberProperty( m_indiP_extrapDropoutTinyFactor,
6344 m_extrapConfig.m_dropoutTinyFactor,
6345 ipRecv,
6346 "extrap dropout tiny factor" );
6347}
6348
6349INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapDropoutMaxBins )
6350( const pcf::IndiProperty &ipRecv )
6351{
6352 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapDropoutMaxBins, ipRecv );
6353 return handleExtrapNumberProperty( m_indiP_extrapDropoutMaxBins,
6354 m_extrapConfig.m_dropoutMaxBins,
6355 ipRecv,
6356 "extrap dropout max bins" );
6357}
6358
6359INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapClSignificanceThreshold )
6360( const pcf::IndiProperty &ipRecv )
6361{
6362 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapClSignificanceThreshold, ipRecv );
6363 return handleExtrapNumberProperty( m_indiP_extrapClSignificanceThreshold,
6364 m_extrapConfig.m_clSignificanceThreshold,
6365 ipRecv,
6366 "extrap CL significance threshold" );
6367}
6368
6369INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapClMinSignificantFraction )
6370( const pcf::IndiProperty &ipRecv )
6371{
6372 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapClMinSignificantFraction, ipRecv );
6373 return handleExtrapNumberProperty( m_indiP_extrapClMinSignificantFraction,
6374 m_extrapConfig.m_clMinSignificantFraction,
6375 ipRecv,
6376 "extrap CL minimum significant fraction" );
6377}
6378
6379INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_emg )
6380( const pcf::IndiProperty &ipRecv )
6381{
6382 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_emg, ipRecv );
6383
6384 if( ipRecv.find( "current" ) )
6385 {
6386 std::lock_guard<std::mutex> lock( m_goptMutex );
6387
6388 float emg = ipRecv["current"].get<float>();
6389
6390 if( emg != m_emg )
6391 {
6392 m_emg = emg;
6393 std::cerr << "Got EMG: " << m_emg << '\n';
6394 }
6395 }
6396 return 0;
6397}
6398
6399INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_psdTime )
6400( const pcf::IndiProperty &ipRecv )
6401{
6402 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_psdTime, ipRecv );
6403
6404 if( ipRecv.find( "current" ) )
6405 {
6406 float psdTime = ipRecv["current"].get<float>();
6407
6408 if( psdTime != m_psdTime )
6409 {
6410 m_updating = true;
6411 std::lock_guard<std::mutex> lock( m_goptMutex );
6412 m_updating = true;
6413
6414 m_psdTime = psdTime;
6415
6416 m_sinceChange = -1;
6417 m_updating = false;
6418
6419 std::cerr << "Got psdTime: " << m_psdTime << '\n';
6420 }
6421 }
6422 return 0;
6423}
6424
6425INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_psdAvgTime )
6426( const pcf::IndiProperty &ipRecv )
6427{
6428 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_psdAvgTime, ipRecv );
6429
6430 if( ipRecv.find( "current" ) )
6431 {
6432 float psdAvgTime = ipRecv["current"].get<float>();
6433
6434 if( psdAvgTime != m_psdAvgTime )
6435 {
6436 m_updating = true;
6437 std::lock_guard<std::mutex> lock( m_goptMutex );
6438 m_updating = true;
6439
6440 m_psdAvgTime = psdAvgTime;
6441
6442 m_sinceChange = -1;
6443 m_updating = false;
6444
6445 std::cerr << "Got psdAvgTime: " << m_psdAvgTime << '\n';
6446 }
6447 }
6448
6449 return 0;
6450}
6451
6452INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_loop )
6453( const pcf::IndiProperty &ipRecv )
6454{
6455 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_loop, ipRecv );
6456
6457 if( ipRecv.find( "toggle" ) )
6458 {
6459 bool state;
6460 bool changed{ false };
6461
6462 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On )
6463 {
6464 state = true;
6465 }
6466 else
6467 {
6468 state = false;
6469 }
6470
6471 if( state != m_loop )
6472 {
6473 changed = true;
6474 recordModalGainOpt( false );
6475 m_updating = true;
6476 std::lock_guard<std::mutex> lock( m_goptMutex );
6477 m_updating = true;
6478
6479 m_loop = state;
6480
6481 if( !m_loop )
6482 {
6483 m_autoUpdate = false;
6484 m_dump = false;
6485 }
6486
6487 m_sinceChange = -1;
6488 m_updating = false;
6489 std::cerr << "Got loop: " << m_loop << '\n';
6490 }
6491
6492 if( changed )
6493 {
6494 recordModalGainOpt( false );
6495 }
6496 }
6497
6498 return 0;
6499}
6500
6501INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_siGain )
6502( const pcf::IndiProperty &ipRecv )
6503{
6504 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_siGain, ipRecv );
6505
6506 if( ipRecv.find( "current" ) )
6507 {
6508 float gain = ipRecv["current"].get<float>();
6509
6510 if( gain != m_gain && !m_pcOn )
6511 {
6512 m_updating = true;
6513 std::lock_guard<std::mutex> lock( m_goptMutex );
6514 m_updating = true;
6515
6516 m_gain = gain;
6517
6518 if( m_loop )
6519 {
6520 m_sinceChange = -1;
6521 }
6522
6523 m_updating = false;
6524
6525 std::cerr << "Got gain: " << m_gain << '\n';
6526 }
6527 else
6528 {
6529 m_gain = gain; // for the m_pcOn case
6530 }
6531 }
6532
6533 return 0;
6534}
6535
6536INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_siMult )
6537( const pcf::IndiProperty &ipRecv )
6538{
6539 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_siMult, ipRecv );
6540
6541 if( ipRecv.find( "current" ) )
6542 {
6543 float mc = ipRecv["current"].get<float>();
6544
6545 if( mc != m_mult && !m_pcOn )
6546 {
6547 m_updating = true;
6548 std::lock_guard<std::mutex> lock( m_goptMutex );
6549 m_updating = true;
6550
6551 m_mult = mc;
6552
6553 if( m_loop )
6554 {
6555 m_sinceChange = -1;
6556 }
6557
6558 m_goptUpdated = true;
6559 m_updating = false;
6560 std::cerr << "Got mc: " << m_mult << '\n';
6561 }
6562 else
6563 {
6564 m_mult = mc; // for the m_pcOn case
6565 }
6566 }
6567
6568 return 0;
6569}
6570
6571INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_pcGain )
6572( const pcf::IndiProperty &ipRecv )
6573{
6574 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_pcGain, ipRecv );
6575
6576 if( ipRecv.find( "current" ) )
6577 {
6578 float gain = ipRecv["current"].get<float>();
6579
6580 if( gain != m_pcGain && m_pcOn )
6581 {
6582 m_updating = true;
6583 std::lock_guard<std::mutex> lock( m_goptMutex );
6584 m_updating = true;
6585
6586 m_pcGain = gain;
6587
6588 if( m_loop )
6589 {
6590 m_sinceChange = -1;
6591 }
6592
6593 m_updating = false;
6594
6595 std::cerr << "Got pc gain: " << m_pcGain << '\n';
6596 }
6597 else
6598 {
6599 m_pcGain = gain; // for the !m_pcOn case
6600 }
6601 }
6602
6603 return 0;
6604}
6605
6606INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_pcMult )
6607( const pcf::IndiProperty &ipRecv )
6608{
6609 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_pcMult, ipRecv );
6610
6611 if( ipRecv.find( "current" ) )
6612 {
6613 float mc = ipRecv["current"].get<float>();
6614
6615 if( mc != m_pcMult && m_pcOn )
6616 {
6617 m_updating = true;
6618 std::lock_guard<std::mutex> lock( m_goptMutex );
6619 m_updating = true;
6620
6621 m_pcMult = mc;
6622
6623 if( m_loop )
6624 {
6625 m_sinceChange = -1;
6626 }
6627
6628 m_pcgoptUpdated = true;
6629 m_updating = false;
6630 std::cerr << "Got pc mc: " << m_pcMult << '\n';
6631 }
6632 else
6633 {
6634 m_pcMult = mc; // for the !m_pcOn case
6635 }
6636 }
6637
6638 return 0;
6639}
6640
6641INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_pcOn )
6642( const pcf::IndiProperty &ipRecv )
6643{
6644 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_pcOn, ipRecv );
6645
6646 if( ipRecv.find( "toggle" ) )
6647 {
6648 bool state;
6649
6650 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On )
6651 {
6652 state = true;
6653 }
6654 else
6655 {
6656 state = false;
6657 }
6658
6659 if( state != m_pcOn )
6660 {
6661 m_updating = true;
6662 std::lock_guard<std::mutex> lock( m_goptMutex );
6663 m_updating = true;
6664
6665 m_pcOn = state;
6666
6667 m_sinceChange = -1;
6668 m_updating = false;
6669 std::cerr << "Got pcOn: " << std::boolalpha << m_pcOn << '\n';
6670 }
6671 }
6672
6673 return 0;
6674}
6675
6676} // namespace app
6677} // namespace MagAOX
6678
6679#endif // modalGainOpt_hpp
#define XWCAPP_THREAD_CHECK(thrdSt, thrdName)
Error handling wrapper for checking on thread status with tryjoin.
#define XWCAPP_THREAD_START(thrdSt, thrdInit, thrdId, thrdProp, thrdPrio, thrdCpuset, thrdName, thrdStart)
Error handling wrapper for the threadStart function of the XWCApp.
#define XWCAPP_THREAD_STOP(thrdSt)
Error handlng wrapper for stopping a thread.
The base-class for XWCTk applications.
stateCodes::stateCodeT state()
Get the current state code.
int registerIndiPropertyNew(pcf::IndiProperty &prop, int(*)(void *, const pcf::IndiProperty &))
Register an INDI property which is exposed for others to request a New Property for.
int createStandardIndiToggleSw(pcf::IndiProperty &prop, const std::string &name, const std::string &label="", const std::string &group="")
Create a standard R/W INDI switch with a single toggle element.
int m_shutdown
Flag to signal it's time to shutdown. When not 0, the main loop exits.
int shutdown()
Get the value of the shutdown flag.
indiDriver< MagAOXApp > * m_indiDriver
The INDI driver wrapper. Constructed and initialized by execute, which starts and stops communication...
void updateSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, const pcf::IndiElement::SwitchStateType &newVal, pcf::IndiProperty::PropertyStateType ipState=pcf::IndiProperty::Ok)
Update an INDI switch element value if it has changed.
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
int createStandardIndiSelectionSw(pcf::IndiProperty &prop, const std::string &name, const std::vector< std::string > &elements, const std::vector< std::string > &elementLabels, const std::string &label="", const std::string &group="")
Create a standard R/W INDI selection (one of many) switch with vector of elements and element labels.
int indiTargetUpdate(pcf::IndiProperty &localProperty, T &localTarget, const pcf::IndiProperty &remoteProperty, bool setBusy=true)
Get the target element value from an new property.
uint32_t m_width
The width of the images in the stream.
uint32_t m_height
The height of the images in the stream.
IMAGE m_imageStream
The ImageStreamIO shared memory buffer.
int create(uint32_t width, uint32_t height, uint32_t depth, uint8_t datatype, void *initData=nullptr)
Create the image.
The MagAO-X PSD-based gain optimizer.
int countEnabledGainFactors(const std::vector< float > &gainFacts) const
Count how many modes are enabled by a gain-factor vector.
void destroyImageStream(IMAGE *&stream)
Destroy an owned ImageStreamIO output stream and clear its pointer.
pcf::IndiProperty m_indiP_emg
std::vector< mx::AO::analysis::clGainOpt< float > > m_goptCurrent
Each mode gets its own gain optimizer.
pcf::IndiProperty m_indiP_extrapPowerLawNormFreq
pcf::IndiProperty m_indiP_extrapClMinSignificantFraction
int recordTelem(const telem_modalgainopt *)
void updateAppliedModeCount(const std::vector< float > &gainFacts, bool predictorPath)
eigenImage< float > m_wfsavg
pcf::IndiProperty m_indiP_gainGain
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawIndex)
pcf::IndiProperty m_indiP_extrapNoiseEstimateLowFreqMaxHz
void syncSiGainStateFromAppliedGains()
Synchronize the integrated SI gain state from the applied gain-factor stream.
std::vector< uint32_t > m_NbCurrent
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_updateOnce)
pcf::IndiProperty m_indiP_extrapDropoutTinyFactor
dev::shmimMonitor< modalGainOpt, numpccoeffShmimT > numpccoeffShmimMonitorT
pcf::IndiProperty m_indiP_extrapNoiseEstimateRange
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapClSignificanceThreshold)
mx::improc::eigenImage< float > m_clNtfLP
Published predictive closed-loop noise transfer function.
mx::improc::eigenImage< float > m_clXferCurrent
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawFitBinWidthHz)
~modalGainOpt() noexcept
D'tor, declared and defined for noexcept.
std::vector< float > m_modeVarCL
int handleExtrapPowerLawCrossoverModeProperty(const pcf::IndiProperty &ipRecv)
Handle the power-law crossover-mode selection switch property.
dev::shmimMonitor< modalGainOpt, wfsmaskShmimT > wfsmaskShmimMonitorT
std::vector< int > m_regCounter
Counters to track when this mode was last regularized.
pcf::IndiProperty m_indiP_extrapClSignificanceThreshold
int handleExtrapNoiseEstimateDomainProperty(const pcf::IndiProperty &ipRecv)
Handle the noise-estimation-domain selection switch property.
std::vector< float > m_gmaxLP
The previously calculated maximum gains for LP.
std::vector< float > m_pcGainFacts
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapClMinSignificantFraction)
std::vector< mx::AO::analysis::clGainOpt< float > > m_goptLP
pcf::IndiProperty m_indiP_extrapPowerLawFitMaxFreqHz
std::chrono::time_point< std::chrono::steady_clock > timePointT
eigenImage< float > m_as
dev::shmimMonitor< modalGainOpt, pcGainFactShmimT > pcGainFactShmimMonitorT
pid_t m_goptThreadID
gain optimization thread PID.
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_autoUpdate)
pcf::IndiProperty m_indiP_extrapDropoutMaxBins
bool applyMultiplierUpdate(std::vector< float > &multFacts, const float *incoming, uint32_t width, bool predictorPath)
dev::shmimMonitor< modalGainOpt, pcMultFactShmimT > pcMultFactShmimMonitorT
std::vector< float > m_taus
dev::shmimMonitor< modalGainOpt, gainCalShmimT > gainCalShmimMonitorT
pcf::IndiProperty m_indiP_extrapPowerLawMatchFallbackWindowHz
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapMethod)
int allocate(const psdShmimT &)
std::vector< int > m_timesOnLP
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_dump)
int handleExtrapMethodProperty(const pcf::IndiProperty &ipRecv)
Handle the extrapolation-method selection switch property.
std::vector< std::vector< float > > m_rawOlPSDs
std::vector< float > m_freq
pcf::IndiProperty m_indiP_siGain
virtual int appLogic()
Implementation of the FSM for modalGainOpt.
std::vector< float > m_modeVarSI
pcf::IndiProperty m_indiP_extrapFitPowerLawIndex
pcf::IndiProperty m_indiP_autoUpdate
std::vector< float > m_gainCalFacts
pcf::IndiProperty m_indiP_dump
mx::improc::eigenImage< float > m_clNtfSI
std::vector< float > m_gainFacts
dev::shmimMonitor< modalGainOpt, bcoeffShmimT > bcoeffShmimMonitorT
int checkSizes()
Check that all sizes and allocations have occurred.
pcf::IndiProperty m_indiP_extrapPowerLawOnlyAboveFreq
int m_goptThreadPrio
Priority of the gain optimization thread.
pcf::IndiProperty m_indiP_opticalGainUpdate
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_pcOn)
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawMatchFallbackWindowHz)
std::vector< float > m_optGainLP
int createImageStream(IMAGE *&stream, const std::string &name, uint32_t size0, uint32_t size1, uint32_t size2, uint8_t dataType)
Allocate and create an owned ImageStreamIO output stream.
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapDropoutTinyFactor)
pcf::IndiProperty m_indiP_extrapNoiseEstimateDomain
pcf::IndiProperty m_indiP_loop
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_siGain)
int handleExtrapClosedLoopOlEstimateMethodProperty(const pcf::IndiProperty &ipRecv)
Handle the closed-loop OL-estimation-method selection switch property.
mx::improc::eigenImage< float > m_clPSDs
dev::shmimMonitor< modalGainOpt, wfsavgShmimT > wfsavgShmimMonitorT
std::vector< float > m_gmaxSI
The previously calculated maximum gains for SI.
std::vector< std::vector< float > > m_smoothOlPSDs
pcf::IndiProperty m_indiP_siMult
pcf::IndiProperty m_indiP_pcOn
processPsdProcessorT::processModelConfig m_extrapConfig
Configuration of the OL PSD extrapolation model.
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapFitPowerLawIndex)
std::vector< std::vector< float > > m_olPSDs
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_loop)
eigenImage< float > m_wfsmask
pcf::IndiProperty m_indiP_modesOn
bool applyFrequencyUpdate(const float *incoming, size_t size)
Apply an incoming frequency frame to the stored frequency scale.
int handleExtrapNumberProperty(pcf::IndiProperty &localProperty, valueT &localTarget, const pcf::IndiProperty &ipRecv, const std::string &label)
Handle a standard target/current numeric extrapolation property update.
mx::improc::eigenImage< float > m_clXferLP
Published predictive closed-loop error transfer function.
dev::shmimMonitor< modalGainOpt, freqShmimT > freqShmimMonitorT
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawBlendBins)
std::string m_loopName
The name of the loop control INDI device name.
std::chrono::duration< double > durationT
int handleExtrapToggleProperty(pcf::IndiProperty &localProperty, bool &localTarget, const pcf::IndiProperty &ipRecv, const std::string &label)
Handle a boolean extrapolation toggle property update.
dev::shmimMonitor< modalGainOpt, gainFactShmimT > gainFactShmimMonitorT
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawMatchFreq)
pcf::IndiProperty m_indiP_extrapPowerLawFitIncludesMatchPoint
bool m_updateOnce
Flag to trigger a single update with gain.
pcf::IndiProperty m_indiP_extrapPowerLawAutoSmoothWidthHz
pcf::IndiProperty m_indiP_updateOnce
int recordModalGainOpt(bool force=false)
dev::shmimMonitor< modalGainOpt, tauShmimT > tauShmimMonitorT
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_zeroGains)
eigenImage< float > m_noiseParams
std::vector< mx::AO::analysis::clAOLinearPredictor< float > > m_linPred
pcf::IndiProperty m_goptThreadProp
static void goptThreadStart(modalGainOpt *p)
Gain Optimization thread starter function.
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_psdAvgTime)
eigenImage< float > m_bs
mx::improc::eigenImage< float > m_clNtfCurrent
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapNoiseEstimateDomain)
void updateIntegratedSiGain(size_t modeIndex)
Apply one SI leaky-integrator update from the raw optimal gain.
bool m_dump
Flag to trigger a single update with no gain.
void writePublishedPredictorArrays(float *pcGainData, float *aCoeffData, uint32_t aWidth, float *bCoeffData, uint32_t bWidth, bool blend)
Populate the published predictive-control gain and coefficient arrays.
mx::improc::eigenImage< float > m_clXferSI
pcf::IndiProperty m_indiP_extrapPowerLawCrossoverMode
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapNoiseEstimateRange)
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawAutoMaxFreqFraction)
bool m_goptSemaphoreInit
Tracks whether the gain optimization semaphore needs cleanup.
pcf::IndiProperty m_indiP_psdAvgTime
std::vector< float > m_modeVarLP
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_opticalGainSource)
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawFitMaxFreqHz)
pcf::IndiProperty m_indiP_extrapDropoutGapFactor
std::vector< float > m_optGainSI
The leaky-integrated SI optimal gains.
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_gainLeak)
std::atomic< bool > m_updating
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_psdTime)
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
bool m_zeroGains
Flag requesting the SI gain integrator state be zeroed.
int handleExtrapNoiseEstimateStatisticProperty(const pcf::IndiProperty &ipRecv)
Handle the noise-estimation-statistic selection switch property.
std::vector< float > m_gainCals
virtual int appStartup()
Startup function.
void writePublishedGainArrays(float *currentData, float *siRawData, float *siData, float *maxSiData, float *lpData, float *maxLpData, float *modeVarData)
std::thread m_goptThread
The gain optimization thread.
void goptThreadExec()
Gain optimization thread function.
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawAutoSmoothWidthHz)
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_opticalGain)
pcf::IndiProperty m_indiP_opticalGain
dev::shmimMonitor< modalGainOpt, psdShmimT > psdShmimMonitorT
pcf::IndiProperty m_indiP_gainLeak
pcf::IndiProperty m_indiP_extrapPowerLawIndex
virtual int appShutdown()
Shutdown the app.
bool m_goptThreadInit
Initialization flag for the gain optimization thread.
int processImage(void *curr_src, const psdShmimT &)
std::vector< float > m_modeVarOL
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawFitMinFreqHz)
std::vector< float > m_pcMultFacts
pcf::IndiProperty m_indiP_extrapMethod
std::mutex m_goptMutex
Mutex for synchronizing updates.
dev::shmimMonitor< modalGainOpt, multFactShmimT > multFactShmimMonitorT
pcf::IndiProperty m_indiP_extrapPowerLawFitBinWidthHz
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_siMult)
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_emg)
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapNoiseEstimateStatistic)
int handleExtrapNoiseEstimateRangeProperty(const pcf::IndiProperty &ipRecv)
Handle the noise-estimation-range selection switch property.
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawNormFreq)
bool m_autoUpdate
Flag controlling whether gains are automatically updated.
dev::shmimMonitor< modalGainOpt, gainCalFactShmimT > gainCalFactShmimMonitorT
pcf::IndiProperty m_indiP_zeroGains
std::vector< uint32_t > m_NaCurrent
std::vector< int > m_timesOnSI
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapClosedLoopOlEstimateMethod)
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_pcMult)
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapNoiseEstimateLowFreqMaxHz)
int m_extrapOL
Which extrapolation method to use for the OL PSD.
std::vector< float > m_multFacts
dev::shmimMonitor< modalGainOpt, acoeffShmimT > acoeffShmimMonitorT
std::vector< float > m_regScale
The regularization scale factors for each mode.
pcf::IndiProperty m_indiP_opticalGainSource
pcf::IndiProperty m_indiP_extrapNoiseEstimateStatistic
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawCrossoverMode)
pcf::IndiProperty m_indiP_extrapPowerLawBlendBins
pcf::IndiProperty m_indiP_extrapPowerLawAutoMaxFreqFraction
std::vector< uint32_t > m_Nb
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_opticalGainUpdate)
std::vector< std::vector< float > > m_nPSDs
float m_gainGain
The gain to use for SI gain correction updates. Default is 0.1.
pcf::IndiProperty m_indiP_pcGain
std::vector< mx::AO::analysis::clGainOpt< float > > m_goptSI
dev::shmimMonitor< modalGainOpt, noiseShmimT > noiseShmimMonitorT
pcf::IndiProperty m_indiP_extrapClosedLoopOlEstimateMethod
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_pcGain)
bool applyGainFactorUpdate(std::vector< float > &gainFacts, const float *incoming, uint32_t width, bool predictorPath)
Apply an incoming gain-factor frame to one of the stored gain vectors.
pcf::IndiProperty m_indiP_extrapPowerLawMatchFreq
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_gainGain)
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapDropoutMaxBins)
std::vector< uint32_t > m_Na
pcf::IndiProperty m_indiP_psdTime
int m_nRegCycles
How often to regularize each mode.
pcf::IndiProperty m_indiP_pcMult
float m_gainLeak
The leak factor used for SI gain integration. Default is 0.9.
pcf::IndiProperty m_indiP_extrapPowerLawFitMinFreqHz
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapDropoutGapFactor)
std::vector< float > m_optGainSIRaw
The raw SI optimal gains before leaky integration.
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawOnlyAboveFreq)
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawFitIncludesMatchPoint)
realT m_dropoutGapFactor
The threshold used to identify dropout bins.
realT m_peakDetectWidthHz
The wide smoothing width used for peak detection.
realT m_peakDetectMinWidthLog
The minimum accepted broad-peak width in log-frequency.
realT m_peakMoffatBeta
The minimum Moffat beta used for synthesized peaks.
bool m_fitPowerLawIndex
Whether to fit the power-law exponent from high-frequency bins.
realT m_powerLawOnlyAboveFreq
Above this frequency, force the extrapolation to be power-law only.
static constexpr realT c_defaultLpContinuumWidthHz
The default LP-continuum smoothing width.
realT m_powerLawNormFreq
The normalization frequency for the power-law continuum.
std::string m_noiseEstimateRange
Which end of the PSD is used to estimate the flat noise floor.
realT m_peakDetectBroadFactor
The lower factor used for broad-peak candidates.
size_t m_dropoutMaxBins
The maximum dropout-run length repaired by the gap-filling logic.
realT m_powerLawFitMaxFreqHz
The high edge of the exponent-fit range.
static mx::error_t estimateNoisePsd(std::vector< realT > &noisePsd, realT &noiseFloor, const std::vector< realT > &measuredPsd, const std::vector< realT > &freq, size_t modeIndex, std::string noiseEstimateRange=c_defaultNoiseEstimateRange, std::string noiseEstimateStatistic=c_defaultNoiseEstimateStatistic, realT noiseEstimateLowFreqMaxHz=c_defaultNoiseEstimateLowFreqMaxHz)
Estimate the flat noise PSD using the configured modalGainOpt statistic.
realT m_peakDetectFactor
The minimum factor above the smoothed PSD for a strong peak.
int m_peakDetectPasses
The number of iterative peak-detection passes.
static mx::error_t analyzePsd(processResults &result, const std::vector< realT > &measuredPsd, const std::vector< realT > &freq, size_t modeIndex, const processModelConfig &config, realT lpContinuumFreq=static_cast< realT >(0), realT lpContinuumWidthHz=c_defaultLpContinuumWidthHz, const std::vector< realT > *etfPsd=nullptr, const std::vector< realT > *ntfPsd=nullptr)
Build the noise PSD, disturbance PSD, and LP continuum PSD for one mode.
std::string m_powerLawCrossoverMode
How the power-law match/cutoff frequencies are chosen.
std::string m_noiseEstimateDomain
The domain used to estimate the flat noise floor.
bool m_powerLawFitIncludesMatchPoint
Whether the match point is included directly in the exponent fit.
realT m_powerLawFitMinFreqHz
The low edge of the exponent-fit range.
std::string m_method
The extrapolation method name.
realT m_powerLawFitBinWidthHz
The width of the exponent-fit median bins.
Configuration of the disturbance-PSD extrapolation model.
Results of modal PSD noise estimation and disturbance extrapolation.
int nc
Definition cycle.cpp:13
int m_nRegCycles
Definition cycle.cpp:11
#define INDI_NEWCALLBACK_DEFN(class, prop)
Define the callback for a new property request.
#define CREATE_REG_INDI_NEW_TOGGLESWITCH(prop, name)
Create and register a NEW INDI property as a standard toggle switch, using the standard callback name...
#define CREATE_REG_INDI_NEW_REQUESTSWITCH(prop, name)
Create and register a NEW INDI property as a standard request switch, using the standard callback nam...
#define INDI_NEWCALLBACK(prop)
Get the name of the static callback wrapper for a new property.
#define CREATE_REG_INDI_NEW_NUMBERF(prop, name, min, max, step, format, label, group)
Create and register a NEW INDI property as a standard number as float, using the standard callback na...
#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.
#define CREATE_REG_INDI_RO_NUMBER(prop, name, label, group)
Create and register a RO INDI property as a number, using the standard callback name.
#define CREATE_REG_INDI_NEW_NUMBERI(prop, name, min, max, step, format, label, group)
Create and register a NEW INDI property as a standard number as int, using the standard callback name...
#define INDI_VALIDATE_CALLBACK_PROPS(prop1, prop2)
Standard check for matching INDI properties in a callback.
#define INDI_IDLE
Definition indiUtils.hpp:27
#define INDI_OK
Definition indiUtils.hpp:28
#define MGO_BREADCRUMB
Header-only template class for modal PSD noise estimation and disturbance extrapolation.
void updateSelectionSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, indiDriverT *indiDriver, pcf::IndiProperty::PropertyStateType newState=pcf::IndiProperty::Ok)
Update the values of a one-of-many INDI switch vector, but only if it has changed.
int addNumberElement(pcf::IndiProperty &prop, const std::string &name, const T &min, const T &max, const T &step, const std::string &format, const std::string &label="")
Add a standard INDI Number element.
Definition indiUtils.hpp:59
std::string extrapBoolString(bool value)
recordModalGainOpt(false)
int extrapClosedLoopOlEstimateMethodFromElement(const std::string &element)
modalPsdProcessor< float > processPsdProcessorT
std::string extrapClosedLoopOlEstimateMethodLabel(int method)
return handleExtrapNoiseEstimateStatisticProperty(ipRecv)
int olProcessMethodFromName(std::string method)
return handleExtrapToggleProperty(m_indiP_extrapFitPowerLawIndex, m_extrapConfig.m_fitPowerLawIndex, ipRecv, "extrap fit power-law index")
const pcf::IndiProperty & ipRecv
return handleExtrapNoiseEstimateRangeProperty(ipRecv)
return handleExtrapClosedLoopOlEstimateMethodProperty(ipRecv)
int olProcessMethodFromElement(const std::string &element)
std::string extrapNoiseEstimateDomainElement(int domain)
static constexpr int c_olProcessPowerLawOnly
std::string extrapNoiseEstimateRangeLabel(int range)
std::string extrapNoiseEstimateRangeName(int range)
std::string extrapClosedLoopOlEstimateMethodElement(int method)
std::string extrapNoiseEstimateStatisticElement(int statistic)
std::string extrapPowerLawCrossoverModeElement(int mode)
std::string extrapNoiseEstimateRangeElement(int range)
static constexpr int c_olProcessLegacy
return handleExtrapNoiseEstimateDomainProperty(ipRecv)
static constexpr int c_extrapNoiseEstimateHighFreq
std::string extrapNoiseEstimateDomainName(int domain)
static constexpr int c_extrapPowerLawCrossoverManual
return handleExtrapNumberProperty(m_indiP_extrapNoiseEstimateLowFreqMaxHz, m_extrapConfig.m_noiseEstimateLowFreqMaxHz, ipRecv, "extrap noise-estimate low-freq max hz")
std::string extrapPowerLawCrossoverModeName(int mode)
static constexpr int c_olProcessNone
static constexpr int c_extrapNoiseEstimateMinimum
static constexpr int c_olProcessMoffatPeaks
return handleExtrapPowerLawCrossoverModeProperty(ipRecv)
static constexpr int c_extrapNoiseEstimatePercentile
static constexpr int c_extrapClosedLoopOlEstimateEtfOnly
std::string olProcessMethodElement(int method)
std::string extrapClosedLoopOlEstimateMethodName(int method)
int extrapPowerLawCrossoverModeFromElement(const std::string &element)
static constexpr int c_extrapNoiseEstimateLowFreq
std::string extrapNoiseEstimateStatisticName(int statistic)
int extrapNoiseEstimateDomainFromElement(const std::string &element)
std::string extrapNoiseEstimateStatisticLabel(int statistic)
int extrapNoiseEstimateStatisticFromElement(const std::string &element)
int extrapNoiseEstimateRangeFromElement(const std::string &element)
std::string extrapPowerLawCrossoverModeLabel(int mode)
static constexpr int c_extrapNoiseEstimateOpenLoop
static constexpr int c_extrapNoiseEstimateClosedLoopPreXfer
static constexpr int c_extrapPowerLawCrossoverAutoSmoothedCrossing
int extrapPowerLawCrossoverModeFromName(std::string mode)
int extrapClosedLoopOlEstimateMethodFromName(std::string method)
std::unique_lock< std::mutex > lock(m_indiMutex)
int extrapNoiseEstimateStatisticFromName(std::string statistic)
int extrapNoiseEstimateDomainFromName(std::string domain)
static constexpr int c_extrapClosedLoopOlEstimateNtfAware
std::string extrapNoiseEstimateDomainLabel(int domain)
std::string olProcessMethodLabel(int method)
std::string olProcessMethodName(int method)
int extrapNoiseEstimateRangeFromName(std::string range)
return handleExtrapMethodProperty(ipRecv)
Definition dm.hpp:19
static constexpr logPrioT LOG_NOTICE
A normal but significant condition.
static constexpr logPrioT LOG_CRITICAL
The process can not continue and will shut down (fatal)
#define XWC_SEM_WAIT_TS_RETVOID(ts, sec, nsec)
Add the wait time to a timespec for a sem_timedwait call, with no value returned on error.
Definition semUtils.hpp:20
#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()
static std::string indiPrefix()
static std::string indiPrefix()
static std::string configSection()
A device base class which saves telemetry.
Definition telemeter.hpp:75
int appShutdown()
Perform telemeter application shutdown.
int loadConfig(appConfigurator &config)
Load the device section from an application configurator.
int appLogic()
Perform telemeter application logic.
int setupConfig(appConfigurator &config)
Setup an application configurator for the device section.
int appStartup()
Starts the telemetry log thread.
int checkRecordTimes(const telT &tel, telTs... tels)
Check the time of the last record for each telemetry type and make an entry if needed.
static std::string indiPrefix()
static std::string configSection()
static std::string configSection()
static std::string indiPrefix()
static std::string indiPrefix()
static std::string configSection()
static std::string configSection()
static std::string indiPrefix()
static std::string configSection()
static std::string indiPrefix()
static std::string indiPrefix()
static std::string configSection()
static std::string indiPrefix()
static std::string configSection()
static std::string configSection()
static std::string indiPrefix()
static std::string indiPrefix()
static std::string configSection()
static std::string configSection()
static std::string indiPrefix()
@ OPERATING
The device is operating, other than homing.
static std::string indiPrefix()
static std::string configSection()
Tag type for the live WFS average shmim monitor.
static std::string configSection()
static std::string indiPrefix()
Tag type for the WFS mask shmim monitor.
static std::string indiPrefix()
static std::string configSection()
Software CRITICAL log entry.
Software ERR log entry.
Log entry recording modalGainOpt control state.