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 <mx/ao/analysis/clGainOpt.hpp>
11#include <mx/ao/analysis/clAOLinearPredictor.hpp>
12
13#include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
14#include "../../magaox_git_version.h"
15
16/** \defgroup modalGainOpt
17 * \brief The MagAO-X application to perform PSD-based gain optimization
18 *
19 * <a href="../handbook/operating/software/apps/modalGainOpt.html">Application Documentation</a>
20 *
21 * \ingroup apps
22 *
23 */
24
25/** \defgroup modalGainOpt_files
26 * \ingroup modalGainOpt
27 */
28
29namespace MagAOX
30{
31namespace app
32{
33
34#define MGO_BREADCRUMB
35
36// #define MGO_BREADCRUMB std::cerr << __FILE__ << ' ' << __LINE__ << '\n';
37
39{
40 static std::string configSection()
41 {
42 return "psdShmim";
43 };
44
45 static std::string indiPrefix()
46 {
47 return "psd";
48 };
49};
50
52{
53 static std::string configSection()
54 {
55 return "freqShmim";
56 };
57
58 static std::string indiPrefix()
59 {
60 return "freq";
61 };
62};
63
64struct gainFactShmimT
65{
66 static std::string configSection()
67 {
68 return "gainFactShmim";
69 };
70
71 static std::string indiPrefix()
72 {
73 return "gainFact";
74 };
75};
76
77struct multFactShmimT
78{
79 static std::string configSection()
80 {
81 return "multFactShmim";
82 };
83
84 static std::string indiPrefix()
85 {
86 return "multFact";
87 };
88};
89
90struct pcGainFactShmimT
91{
92 static std::string configSection()
93 {
94 return "pcGainFactShmim";
95 };
96
97 static std::string indiPrefix()
98 {
99 return "pcGainFact";
100 };
101};
102
103struct pcMultFactShmimT
104{
105 static std::string configSection()
106 {
107 return "pcMultFactShmim";
108 };
109
110 static std::string indiPrefix()
111 {
112 return "pcMultFact";
113 };
114};
115
117{
118 static std::string configSection()
119 {
120 return "numpccoeffShmim";
121 };
122
123 static std::string indiPrefix()
124 {
125 return "numpccoeff";
126 };
127};
128
129struct acoeffShmimT
130{
131 static std::string configSection()
132 {
133 return "acoeffShmim";
134 };
135
136 static std::string indiPrefix()
137 {
138 return "acoeff";
139 };
140};
141
142struct bcoeffShmimT
143{
144 static std::string configSection()
145 {
146 return "bcoeffShmim";
147 };
148
149 static std::string indiPrefix()
150 {
151 return "bcoeff";
152 };
153};
154
156{
157 static std::string configSection()
158 {
159 return "gainCalShmim";
160 };
161
162 static std::string indiPrefix()
163 {
164 return "gainCal";
165 };
166};
167
169{
170 static std::string configSection()
171 {
172 return "gainCalFactShmim";
173 };
174
175 static std::string indiPrefix()
176 {
177 return "gainCalFact";
178 };
179};
180
182{
183 static std::string configSection()
184 {
185 return "tauShmim";
186 };
187
188 static std::string indiPrefix()
189 {
190 return "tau";
191 };
192};
193
195{
196 static std::string configSection()
197 {
198 return "noiseShmim";
199 };
200
201 static std::string indiPrefix()
202 {
203 return "noise";
204 };
205};
206
208{
209 static std::string configSection()
210 {
211 return "wfsavgShmim";
212 };
213
214 static std::string indiPrefix()
215 {
216 return "wfsavg";
217 };
218};
219
221{
222 static std::string configSection()
223 {
224 return "wfsmaskShmim";
225 };
226
227 static std::string indiPrefix()
228 {
229 return "wfsmask";
230 };
231};
232
233/// The MagAO-X PSD-based gain optimizer
234/**
235 * \ingroup modalGainOpt
236 */
237class modalGainOpt : public MagAOXApp<true>,
238 dev::shmimMonitor<modalGainOpt, psdShmimT>,
239 dev::shmimMonitor<modalGainOpt, freqShmimT>,
240 dev::shmimMonitor<modalGainOpt, gainFactShmimT>,
241 dev::shmimMonitor<modalGainOpt, multFactShmimT>,
242 dev::shmimMonitor<modalGainOpt, pcGainFactShmimT>,
243 dev::shmimMonitor<modalGainOpt, pcMultFactShmimT>,
244 dev::shmimMonitor<modalGainOpt, numpccoeffShmimT>,
245 dev::shmimMonitor<modalGainOpt, acoeffShmimT>,
246 dev::shmimMonitor<modalGainOpt, bcoeffShmimT>,
247 dev::shmimMonitor<modalGainOpt, gainCalShmimT>,
248 dev::shmimMonitor<modalGainOpt, gainCalFactShmimT>,
249 dev::shmimMonitor<modalGainOpt, tauShmimT>,
250 dev::shmimMonitor<modalGainOpt, noiseShmimT>,
251 dev::shmimMonitor<modalGainOpt, wfsavgShmimT>,
252 dev::shmimMonitor<modalGainOpt, wfsmaskShmimT>
253
254{
255
256 // Give the test harness access.
257 friend class modalGainOpt_test;
258
274
275 public:
291
292 typedef std::chrono::time_point<std::chrono::steady_clock> timePointT;
293 typedef std::chrono::duration<double> durationT;
294
295 protected:
296 /** \name Configurable Parameters
297 *@{
298 */
299
300 int m_loopNum{ 1 }; ///< The number of the loop. Used to set shmim names, as in aolN_mgainfact.
301
302 std::string m_loopName; ///< The name of the loop control INDI device name.
303
304 std::string m_wfsDevice{ "camwfs" };
305
306 std::string m_psdDevice{ "hopsds" }; /**< The INDI device name of the PSD calculator. Defaults to aolN_modevalPSDs
307 where N is m_loopNum.*/
308
309 std::string m_opticalGainDevice {"strehl"};
310 std::string m_opticalGainProperty {"strehl_optimal"};
311 std::string m_opticalGainElement {"pyramid"};
312
313 bool m_autoUpdate{ false }; ///< Flag controlling whether gains are automatically updated
314 bool m_opticalGainUpdate {false}; ///< Flag controlling whether optical gain is automatically updated;
315
316 float m_gainGain{ 0.1 }; ///< The gain to use for closed-loop gain updates. Default is 0.1.
317
319
321
322 int m_extrapOL {0}; ///< Which extrapolation method to use for the OL PSD. 0 is none. The only other option is 1.
323
324 ///@}
325
328
329 bool m_updateOnce{ false }; ///< Flag to trigger a single update with gain.
330
331 bool m_dump{ false }; ///< Flag to trigger a single update with no gain.
332
333 float m_fps{ 0 };
334
335 /// Each mode gets its own gain optimizer
336 std::vector<mx::AO::analysis::clGainOpt<float>> m_goptCurrent;
337 std::vector<mx::AO::analysis::clGainOpt<float>> m_goptSI;
338 std::vector<mx::AO::analysis::clGainOpt<float>> m_goptLP;
339 std::vector<mx::AO::analysis::clAOLinearPredictor<float>> m_linPred;
340
341 bool m_goptUpdated{ true }; ///< Tracks if a parameter has updated requiring updates to the m_gopt entries.
342 bool m_pcgoptUpdated{ true }; ///< Tracks if a parameter has updated requiring updates to the m_gopt entries.
343
344 bool m_freqUpdated{ true }; /**< Tracks if the frequency scale has updated, which necessitates additional calcs.
345 If true, implies m_goptUpdate == true.*/
346 float m_psdTime{ 1 };
347 float m_psdAvgTime{ 10 };
349
350 std::vector<float> m_freq;
351
352 mx::improc::eigenImage<float> m_clPSDs;
353 mx::improc::eigenImage<float> m_clXferCurrent;
354 mx::improc::eigenImage<float> m_clXferSI;
355 mx::improc::eigenImage<float> m_clXferLP;
356
357 std::vector<std::vector<float>> m_olPSDs;
358 std::vector<std::vector<float>> m_nPSDs;
359
360 std::vector<float> m_modeVarCL;
361 std::vector<float> m_modeVarOL;
362
364
365 std::vector<float> m_optGainSI;
366 std::vector<float> m_gmaxSI; ///< The previously calculated maximum gains for LP
367 std::vector<float> m_modeVarSI;
368 std::vector<int> m_timesOnSI;
370
371 std::vector<float> m_optGainLP;
372 std::vector<float> m_gmaxLP; ///< The previously calculated maximum gains for LP
373 std::vector<float> m_modeVarLP;
374 std::vector<int> m_timesOnLP;
376
377 bool m_loop{ false };
378
379 float m_opticalGain{ 1 };
380
382
383 float m_gain{ 0 };
384
385 float m_mult{ 1 };
386
387 float m_siGain{ 0 };
388
389 float m_siMult{ 1 };
390
391 bool m_doPCCalcs{ true };
392
393 float m_pcGain{ 0 };
394
395 float m_pcMult{ 0 };
396
397 bool m_pcOn{ false };
398
399 std::vector<float> m_gainFacts;
400
401 std::vector<float> m_multFacts;
402
403 std::vector<float> m_pcGainFacts;
404
405 std::vector<float> m_pcMultFacts;
406
407 std::vector<uint32_t> m_Na; // The latest user specified number of a coefficients
408
409 std::vector<uint32_t> m_NaCurrent; // The current number of a coefficients
410
411 std::vector<uint32_t> m_Nb; // The latest user specified number of b coefficients
412
413 std::vector<uint32_t> m_NbCurrent; // The current number of b coefficients
414
416
418
419 int m_nRegCycles{ 60 }; ///< How often to regularize each mode
420
421 std::vector<int> m_regCounter; ///< Counters to track when this mode was last regularized
422
423 std::vector<float> m_regScale; ///< The regularization scale factors for each mode
424
425 std::vector<float> m_gainCals;
426
427 std::vector<float> m_gainCalFacts;
428
429 std::vector<float> m_taus;
430
432
435 float m_counts{ 0 };
436 float m_emg{ 1 };
437 int m_npix{ 0 };
438
439 int m_sinceChange{ -1 };
440
441 std::string m_olPSDShmimName;
446
450
453
455
456 IMAGE *m_olPSDStream{ nullptr }; ///< The ImageStreamIO shared memory buffer to publish the open loop PSDs
457 IMAGE *m_noisePSDStream{ nullptr }; /**< The ImageStreamIO shared memory buffer to publish the noise
458 PSDs (single value per mode)*/
459 IMAGE *m_clXferCurrentStream{ nullptr }; ///< The ImageStreamIO shared memory buffer to publish the SI ETF
460 IMAGE *m_clXferSIStream{ nullptr }; ///< The ImageStreamIO shared memory buffer to publish the SI ETF
461 IMAGE *m_clXferLPStream{ nullptr }; ///< The ImageStreamIO shared memory buffer to publish the LP ETF
462
463 IMAGE *m_optGainStream{ nullptr }; ///< The ImageStreamIO shared memory buffer to publish the optimal gains
464
465 IMAGE *m_optGainSIStream{ nullptr }; ///< The ImageStreamIO shared memory buffer to publish the SI optimal gains
466 IMAGE *m_maxGainSIStream{ nullptr }; ///< The ImageStreamIO shared memory buffer to publish the SI max gains
467
468 IMAGE *m_optGainLPStream{ nullptr }; ///< The ImageStreamIO shared memory buffer to publish the LP optimal gains
469 IMAGE *m_maxGainLPStream{ nullptr }; ///< The ImageStreamIO shared memory buffer to publish the LP max gains
470
471 IMAGE *m_modevarStream{ nullptr }; ///< The ImageStreamIO shared memory buffer to publish the LP optimal gains
472
473 public:
474 /// Default c'tor.
475 modalGainOpt();
476
477 /// D'tor, declared and defined for noexcept.
479 {
480 }
481
482 virtual void setupConfig();
483
484 /// Implementation of loadConfig logic, separated for testing.
485 /** This is called by loadConfig().
486 */
487 int loadConfigImpl( mx::app::appConfigurator &_config /**< [in] an application configuration
488 from which to load values*/ );
489
490 virtual void loadConfig();
491
492 /// Startup function
493 /**
494 *
495 */
496 virtual int appStartup();
497
498 /// Implementation of the FSM for modalGainOpt.
499 /**
500 * \returns 0 on no critical error
501 * \returns -1 on an error requiring shutdown
502 */
503 virtual int appLogic();
504
505 /// Shutdown the app.
506 /**
507 *
508 */
509 virtual int appShutdown();
510
511 int allocatePCShmims();
512
513 int allocate( const psdShmimT & ///< [in] tag to differentiate shmimMonitor parents.
514 );
515
516 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
517 const psdShmimT & ///< [in] tag to differentiate shmimMonitor parents.
518 );
519
520 int allocate( const freqShmimT & ///< [in] tag to differentiate shmimMonitor parents.
521 );
522
523 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
524 const freqShmimT & ///< [in] tag to differentiate shmimMonitor parents.
525 );
526
527 int allocate( const gainFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
528 );
529
530 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
531 const gainFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
532 );
533
534 int allocate( const multFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
535 );
536
537 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
538 const multFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
539 );
540
541 int allocate( const pcGainFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
542 );
543
544 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
545 const pcGainFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
546 );
547
548 int allocate( const pcMultFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
549 );
550
551 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
552 const pcMultFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
553 );
554
555 int allocate( const numpccoeffShmimT & ///< [in] tag to differentiate shmimMonitor parents.
556 );
557
558 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
559 const numpccoeffShmimT & ///< [in] tag to differentiate shmimMonitor parents.
560 );
561
562 int allocate( const acoeffShmimT & ///< [in] tag to differentiate shmimMonitor parents.
563 );
564
565 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
566 const acoeffShmimT & ///< [in] tag to differentiate shmimMonitor parents.
567 );
568
569 int allocate( const bcoeffShmimT & ///< [in] tag to differentiate shmimMonitor parents.
570 );
571
572 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
573 const bcoeffShmimT & ///< [in] tag to differentiate shmimMonitor parents.
574 );
575
576 int allocate( const gainCalShmimT & ///< [in] tag to differentiate shmimMonitor parents.
577 );
578
579 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
580 const gainCalShmimT & ///< [in] tag to differentiate shmimMonitor parents.
581 );
582
583 int allocate( const gainCalFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
584 );
585
586 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
587 const gainCalFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
588 );
589
590 int allocate( const tauShmimT & ///< [in] tag to differentiate shmimMonitor parents.
591 );
592
593 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
594 const tauShmimT & ///< [in] tag to differentiate shmimMonitor parents.
595 );
596
597 int allocate( const noiseShmimT & ///< [in] tag to differentiate shmimMonitor parents.
598 );
599
600 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
601 const noiseShmimT & ///< [in] tag to differentiate shmimMonitor parents.
602 );
603
604 int allocate( const wfsavgShmimT & ///< [in] tag to differentiate shmimMonitor parents.
605 );
606
607 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
608 const wfsavgShmimT & ///< [in] tag to differentiate shmimMonitor parents.
609 );
610
611 int allocate( const wfsmaskShmimT & ///< [in] tag to differentiate shmimMonitor parents.
612 );
613
614 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
615 const wfsmaskShmimT & ///< [in] tag to differentiate shmimMonitor parents.
616 );
617
618 /// Check that all sizes and allocations have occurred
619 int checkSizes();
620
621 protected:
622 /// Mutex for synchronizing updates.
623 std::mutex m_goptMutex;
624
625 /// Flag used to indicate to the goptThread that it should stop calculations ASAP
626 bool m_updating{ false };
627
628 /** \name Gain Optimization Thread
629 *
630 * @{
631 */
632 int m_goptThreadPrio{ 0 }; ///< Priority of the gain optimization thread.
633
634 std::string m_goptThreadCpuset; ///< The cpuset to use for the gain optimization thread.
635
636 std::thread m_goptThread; ///< The gain optimization thread.
637
638 bool m_goptThreadInit{ true }; ///< Initialization flag for the gain optimization thread.
639
640 pid_t m_goptThreadID{ 0 }; ///< gain optimization thread PID.
641
642 pcf::IndiProperty m_goptThreadProp; ///< The property to hold the gain optimization thread details.
643
644 sem_t m_goptSemaphore; ///< Semaphore used to synchronize the psdShmim thread and the gopt thread.
645
646 float noisePSD( int n );
647
648 /// Gain Optimization thread starter function
649 static void goptThreadStart( modalGainOpt *p /**< [in] pointer to this */ );
650
651 /// Gain optimization thread function
652 /** Runs until m_shutdown is true.
653 */
654 void goptThreadExec();
655
656 ///@}
657
658 public:
659 /** \name INDI
660 * @{
661 */
662
663 pcf::IndiProperty m_indiP_autoUpdate;
664 pcf::IndiProperty m_indiP_updateOnce;
665 pcf::IndiProperty m_indiP_dump;
666
667 pcf::IndiProperty m_indiP_opticalGain;
668
669 pcf::IndiProperty m_indiP_gainGain;
670
671 pcf::IndiProperty m_indiP_emg;
672 pcf::IndiProperty m_indiP_psdTime;
673 pcf::IndiProperty m_indiP_psdAvgTime;
674 pcf::IndiProperty m_indiP_loop;
675 pcf::IndiProperty m_indiP_siGain;
676 pcf::IndiProperty m_indiP_siMult;
677 pcf::IndiProperty m_indiP_pcGain;
678 pcf::IndiProperty m_indiP_pcMult;
679 pcf::IndiProperty m_indiP_pcOn;
680
681 pcf::IndiProperty m_indiP_extrapOL;
682
683 pcf::IndiProperty m_indiP_modesOn;
684
685 pcf::IndiProperty m_indiP_opticalGainSource;
686 pcf::IndiProperty m_indiP_opticalGainUpdate;
687
688
704
707
708
709 ///@}
710};
711
732
734{
735 config.add( "loop.number",
736 "",
737 "loop.number",
738 argType::Required,
739 "loop",
740 "number",
741 false,
742 "int",
743 "The number of the loop. Used to set shmim names, as in aolN_mgainfact." );
744
745 config.add( "loop.name",
746 "",
747 "loop.name",
748 argType::Required,
749 "loop",
750 "name",
751 false,
752 "string",
753 "The name of the loop control INDI device name." );
754
755 config.add( "loop.psdDev",
756 "",
757 "loop.psdDev",
758 argType::Required,
759 "loop",
760 "psdDev",
761 false,
762 "string",
763 "The INDI device name of the PSD calculator. Defaults to aolN_modevalPSDs where N is loop.number." );
764
765 config.add( "loop.autoUpdate",
766 "",
767 "loop.autoUpdate",
768 argType::Required,
769 "loop",
770 "autoUpdate",
771 false,
772 "bool",
773 "Flag controlling whether the gains are auto updated. Also settable via INDI." );
774
775 config.add( "loop.gainGain",
776 "",
777 "loop.gainGain",
778 argType::Required,
779 "loop",
780 "gainGain",
781 false,
782 "float",
783 "The gain to use for closed-loop gain updates. Default is 0.1" );
784
800}
801
802int modalGainOpt::loadConfigImpl( mx::app::appConfigurator &_config )
803{
804 _config( m_loopNum, "loop.number" );
805 _config( m_loopName, "loop.name" );
806 _config( m_autoUpdate, "loop.autoUpdate" );
807 _config( m_autoUpdate, "loop.gainGain" );
808
809 char shmim[1024];
810
811 _config( m_psdDevice, "loop.psdDev" );
812
813 snprintf( shmim, sizeof( shmim ), "aol%d_clpsds", m_loopNum );
816
817 snprintf( shmim, sizeof( shmim ), "aol%d_freq", m_loopNum );
820
821 snprintf( shmim, sizeof( shmim ), "aol%d_mgainfact", m_loopNum );
824
825 snprintf( shmim, sizeof( shmim ), "aol%d_mmultfact", m_loopNum );
828
829 snprintf( shmim, sizeof( shmim ), "aol%d_mpcgainfact", m_loopNum );
832
833 snprintf( shmim, sizeof( shmim ), "aol%d_mpcmultfact", m_loopNum );
836
837 snprintf( shmim, sizeof( shmim ), "aol%d_numpccoeff", m_loopNum );
840
841 snprintf( shmim, sizeof( shmim ), "aol%d_acoeff", m_loopNum );
844
845 snprintf( shmim, sizeof( shmim ), "aol%d_bcoeff", m_loopNum );
848
849 snprintf( shmim, sizeof( shmim ), "aol%d_mgaincal", m_loopNum );
852
853 snprintf( shmim, sizeof( shmim ), "aol%d_mgaincalfact", m_loopNum );
856
857 snprintf( shmim, sizeof( shmim ), "aol%d_looptau", m_loopNum );
860
861 snprintf( shmim, sizeof( shmim ), "aol%d_mnoiseparam", m_loopNum );
864
865 snprintf( shmim, sizeof( shmim ), "aol%d_wfsavg", m_loopNum );
868
869 snprintf( shmim, sizeof( shmim ), "aol%d_wfsmask", m_loopNum );
872
873 snprintf( shmim, sizeof( shmim ), "aol%d_olpsds", m_loopNum );
874 m_olPSDShmimName = shmim;
875
876 snprintf( shmim, sizeof( shmim ), "aol%d_noisepsds", m_loopNum );
877 m_noisePSDShmimName = shmim;
878
879 snprintf( shmim, sizeof( shmim ), "aol%d_clxferCurrent", m_loopNum );
881
882 snprintf( shmim, sizeof( shmim ), "aol%d_clxferSI", m_loopNum );
883 m_clXferSIShmimName = shmim;
884
885 snprintf( shmim, sizeof( shmim ), "aol%d_clxferLP", m_loopNum );
886 m_clXferLPShmimName = shmim;
887
888 snprintf( shmim, sizeof( shmim ), "aol%d_mgainoptimal", m_loopNum );
889 m_optGainShmimName = shmim;
890
891 snprintf( shmim, sizeof( shmim ), "aol%d_mgainoptimalSI", m_loopNum );
892 m_optGainSIShmimName = shmim;
893
894 snprintf( shmim, sizeof( shmim ), "aol%d_mgainmaxSI", m_loopNum );
895 m_maxGainSIShmimName = shmim;
896
897 snprintf( shmim, sizeof( shmim ), "aol%d_mgainoptimalLP", m_loopNum );
898 m_optGainLPShmimName = shmim;
899
900 snprintf( shmim, sizeof( shmim ), "aol%d_mgainmaxLP", m_loopNum );
901 m_maxGainLPShmimName = shmim;
902
903 snprintf( shmim, sizeof( shmim ), "aol%d_mmodevar", m_loopNum );
904 m_modevarShmimName = shmim;
905
906 return 0;
907}
908
910{
911 loadConfigImpl( config );
912}
913
915{
931
935
937 m_indiP_opticalGain, "opticalGain", 0, 1, 0.01, "%0.01f", "Optical Gain", "Gain Opt." );
938 CREATE_REG_INDI_NEW_NUMBERF( m_indiP_gainGain, "gainGain", 0, 1, 0.01, "%0.01f", "Gain Gain", "Gain Opt." );
939
943 REG_INDI_SETPROP( m_indiP_loop, m_loopName, "loop_state" );
945 REG_INDI_SETPROP( m_indiP_siMult, m_loopName, "loop_multcoeff" );
946 REG_INDI_SETPROP( m_indiP_pcGain, m_loopName, "loop_pcgain" );
947 REG_INDI_SETPROP( m_indiP_pcMult, m_loopName, "loop_pcmultcoeff" );
949
951
952 CREATE_REG_INDI_RO_NUMBER(m_indiP_modesOn, "num_modes", "number of modes", "Gain Opt.");
953 indi::addNumberElement(m_indiP_modesOn, "current", 0, 2400, 1, "%d", "Applied Modes");
954 indi::addNumberElement(m_indiP_modesOn, "integrator", 0, 2400, 1, "%d", "SI optimal");
955 indi::addNumberElement(m_indiP_modesOn, "predictor", 0, 2400, 1, "%d", "LP optimal");
956
958
960
961 if( sem_init( &m_goptSemaphore, 0, 0 ) < 0 )
962 {
963 return log<software_critical, -1>( { __FILE__, __LINE__, errno, 0, "Initializing gopt semaphore" } );
964 }
965
972 "gainopt",
974
976 return 0;
977}
978
980{
996
997 XWCAPP_THREAD_CHECK( m_goptThread, "gainopt" );
998
1014
1015 if( m_autoUpdate )
1016 {
1017 updateSwitchIfChanged( m_indiP_autoUpdate, "toggle", pcf::IndiElement::On, INDI_OK );
1018 }
1019 else
1020 {
1021 updateSwitchIfChanged( m_indiP_autoUpdate, "toggle", pcf::IndiElement::Off, INDI_IDLE );
1022 }
1023
1024 if( m_updateOnce )
1025 {
1026 updateSwitchIfChanged( m_indiP_updateOnce, "request", pcf::IndiElement::On, INDI_OK );
1027 }
1028 else
1029 {
1030 updateSwitchIfChanged( m_indiP_updateOnce, "request", pcf::IndiElement::Off, INDI_IDLE );
1031 }
1032
1033 if( m_dump )
1034 {
1035 updateSwitchIfChanged( m_indiP_dump, "request", pcf::IndiElement::On, INDI_OK );
1036 }
1037 else
1038 {
1039 updateSwitchIfChanged( m_indiP_dump, "request", pcf::IndiElement::Off, INDI_IDLE );
1040 }
1041
1043 {
1044 updateSwitchIfChanged( m_indiP_opticalGainUpdate, "toggle", pcf::IndiElement::On, INDI_OK );
1045 }
1046 else
1047 {
1048 updateSwitchIfChanged( m_indiP_opticalGainUpdate, "toggle", pcf::IndiElement::Off, INDI_IDLE );
1049 }
1050
1052
1053 updatesIfChanged<float>( m_indiP_gainGain, { "current", "target" }, { m_gainGain, m_gainGain } );
1054
1055 if(m_extrapOL == 0)
1056 {
1057 updateSwitchIfChanged(m_indiP_extrapOL, "toggle", pcf::IndiElement::Off);
1058 }
1059 else
1060 {
1061 updateSwitchIfChanged(m_indiP_extrapOL, "toggle", pcf::IndiElement::On);
1062 }
1063
1064 updatesIfChanged<int>(m_indiP_modesOn, {"current","integrator","predictor"}, {m_modesOn, m_modesOnSI, m_modesOnLP});
1065
1066
1067 return 0;
1068}
1069
1071{
1073
1089
1090 if( m_olPSDStream != nullptr )
1091 {
1094 m_olPSDStream = nullptr;
1095
1098 m_noisePSDStream = nullptr;
1099
1102 m_clXferCurrentStream = nullptr;
1103
1106 m_clXferSIStream = nullptr;
1107
1110 m_clXferLPStream = nullptr;
1111 }
1112
1113 if( m_optGainStream != nullptr )
1114 {
1117 m_optGainStream = nullptr;
1118
1121 m_optGainSIStream = nullptr;
1122
1125 m_maxGainSIStream = nullptr;
1126
1129 m_optGainLPStream = nullptr;
1130
1133 m_maxGainLPStream = nullptr;
1134
1137 m_modevarStream = nullptr;
1138 }
1139
1140 return 0;
1141}
1142
1144{
1145 // mutex should be locked before calling this
1146
1149 {
1150 mx::improc::eigenImage<uint32_t> Npc( m_nModes, 2 );
1151 Npc.setConstant( m_defaultNCoeff );
1152
1154 {
1155 return log<software_error, -1>( { __FILE__, __LINE__, "error creating numpccoeffShmim" } );
1156 }
1157
1159
1160 std::cerr << "created numppccoeff shmim\n";
1161 }
1162
1165 {
1167 {
1168 return log<software_error, -1>( { __FILE__, __LINE__, "error creating acoeffShmim" } );
1169 }
1170
1171 std::cerr << "created acoeff shmim\n";
1172 }
1173
1176 {
1178 {
1179 return log<software_error, -1>( { __FILE__, __LINE__, "error creating bcoeffShmim" } );
1180 }
1181
1182 std::cerr << "created bcoeff shmim\n";
1183 }
1184
1187 {
1189 {
1190 return log<software_error, -1>( { __FILE__, __LINE__, "error creating pcGainFactShmim" } );
1191 }
1192
1193 std::cerr << "created pcGainFact shmim\n";
1194 }
1195
1198 {
1200 {
1201 return log<software_error, -1>( { __FILE__, __LINE__, "error creating pcMultFactShmim" } );
1202 }
1203
1204 std::cerr << "created pcMultFact shmim\n";
1205 }
1206
1207 return 0;
1208}
1209
1211{
1212 static_cast<void>( dummy );
1213
1214 m_updating = true;
1215 std::lock_guard<std::mutex> lock( m_goptMutex );
1216
1217 m_updating = true;
1218
1221
1222 m_clPSDs.resize( m_nFreq, m_nModes );
1223
1224 m_clXferCurrent.resize( m_nFreq, m_nModes );
1225 m_clXferSI.resize( m_nFreq, m_nModes );
1226 m_clXferLP.resize( m_nFreq, m_nModes );
1227
1228 m_olPSDs.resize( m_nModes );
1229 m_nPSDs.resize( m_nModes );
1230
1231 for( size_t n = 0; n < m_olPSDs.size(); ++n )
1232 {
1233 m_olPSDs[n].resize( m_nFreq );
1234 m_nPSDs[n].resize( m_nFreq );
1235 }
1236
1237 m_modeVarOL.resize( m_nModes );
1238
1239 m_optGainSI.resize( m_nModes );
1240 m_gmaxSI.resize( m_nModes );
1241 m_modeVarSI.resize( m_nModes );
1242 m_timesOnSI.resize( m_nModes, 5 );
1243
1244
1245 m_optGainLP.resize( m_nModes );
1246 m_modeVarLP.resize( m_nModes );
1247 m_timesOnLP.resize( m_nModes, 5 );
1248
1249 if( m_olPSDStream != nullptr &&
1250 ( m_olPSDStream->md->size[0] != m_nFreq || m_olPSDStream->md->size[1] != m_nModes ) )
1251 {
1254 m_olPSDStream = nullptr;
1255
1258 m_noisePSDStream = nullptr;
1259
1262 m_clXferCurrentStream = nullptr;
1263
1266 m_clXferSIStream = nullptr;
1267
1270 m_clXferLPStream = nullptr;
1271 }
1272
1273 if( m_olPSDStream == nullptr )
1274 {
1275 m_olPSDStream = static_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
1276 uint32_t imsize[3];
1277
1278 imsize[0] = m_nFreq;
1279 imsize[1] = m_nModes;
1280 imsize[2] = 1;
1282 m_olPSDShmimName.c_str(),
1283 3,
1284 imsize,
1286 -1,
1287 1,
1289 0,
1291 0 );
1292
1293 m_olPSDStream->md->cnt0 = 0;
1294 m_olPSDStream->md->cnt1 = 0;
1295
1296 m_noisePSDStream = static_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
1297
1299 m_noisePSDShmimName.c_str(),
1300 3,
1301 imsize,
1303 -1,
1304 1,
1306 0,
1308 0 );
1309
1310 m_noisePSDStream->md->cnt0 = 0;
1311 m_noisePSDStream->md->cnt1 = 0;
1312
1313 m_clXferCurrentStream = static_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
1314
1317 3,
1318 imsize,
1320 -1,
1321 1,
1323 0,
1325 0 );
1326
1327 m_clXferCurrentStream->md->cnt0 = 0;
1328 m_clXferCurrentStream->md->cnt1 = 0;
1329
1330 m_clXferSIStream = static_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
1331
1333 m_clXferSIShmimName.c_str(),
1334 3,
1335 imsize,
1337 -1,
1338 1,
1340 0,
1342 0 );
1343
1344 m_clXferSIStream->md->cnt0 = 0;
1345 m_clXferSIStream->md->cnt1 = 0;
1346
1347 m_clXferLPStream = static_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
1348
1350 m_clXferLPShmimName.c_str(),
1351 3,
1352 imsize,
1354 -1,
1355 1,
1357 0,
1359 0 );
1360
1361 m_clXferLPStream->md->cnt0 = 0;
1362 m_clXferLPStream->md->cnt1 = 0;
1363 }
1364
1365 if( m_optGainStream != nullptr &&
1366 ( m_optGainStream->md->size[0] != psdShmimMonitorT::m_height || m_optGainStream->md->size[1] != 1 ) )
1367 {
1370 m_optGainStream = nullptr;
1371
1374 m_optGainSIStream = nullptr;
1375
1378 m_maxGainSIStream = nullptr;
1379
1382 m_optGainLPStream = nullptr;
1383
1386 m_maxGainLPStream = nullptr;
1387 }
1388
1389 if( m_optGainStream == nullptr )
1390 {
1391 m_optGainStream = static_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
1392 uint32_t imsize[3];
1393
1394 imsize[0] = m_nModes;
1395 imsize[1] = 1;
1396 imsize[2] = 1;
1398 m_optGainShmimName.c_str(),
1399 3,
1400 imsize,
1402 -1,
1403 1,
1405 0,
1407 0 );
1408
1409 m_optGainStream->md->cnt0 = 0;
1410 m_optGainStream->md->cnt1 = 0;
1411
1412 m_optGainSIStream = static_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
1413
1415 m_optGainSIShmimName.c_str(),
1416 3,
1417 imsize,
1419 -1,
1420 1,
1422 0,
1424 0 );
1425
1426 m_optGainSIStream->md->cnt0 = 0;
1427 m_optGainSIStream->md->cnt1 = 0;
1428
1429 m_maxGainSIStream = static_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
1430
1432 m_maxGainSIShmimName.c_str(),
1433 3,
1434 imsize,
1436 -1,
1437 1,
1439 0,
1441 0 );
1442
1443 m_maxGainSIStream->md->cnt0 = 0;
1444 m_maxGainSIStream->md->cnt1 = 0;
1445
1446 m_optGainLPStream = static_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
1447
1449 m_optGainLPShmimName.c_str(),
1450 3,
1451 imsize,
1453 -1,
1454 1,
1456 0,
1458 0 );
1459
1460 m_optGainLPStream->md->cnt0 = 0;
1461 m_optGainLPStream->md->cnt1 = 0;
1462
1463 m_maxGainLPStream = static_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
1464
1466 m_maxGainLPShmimName.c_str(),
1467 3,
1468 imsize,
1470 -1,
1471 1,
1473 0,
1475 0 );
1476
1477 m_maxGainLPStream->md->cnt0 = 0;
1478 m_maxGainLPStream->md->cnt1 = 0;
1479
1480 m_modevarStream = static_cast<IMAGE *>( malloc( sizeof( IMAGE ) ) );
1481
1482 imsize[0] = 3;
1484 imsize[2] = 1;
1485
1487 m_modevarShmimName.c_str(),
1488 3,
1489 imsize,
1491 -1,
1492 1,
1494 0,
1496 0 );
1497
1498 m_modevarStream->md->cnt0 = 0;
1499 m_modevarStream->md->cnt1 = 0;
1500 }
1501
1502 m_sinceChange = -1;
1503
1504 m_updating = false;
1505 return 0;
1506}
1507
1508int modalGainOpt::processImage( void *curr_src, const psdShmimT &dummy )
1509{
1510 static_cast<void>( dummy );
1511
1512 ++m_sinceChange;
1513
1514 if( m_psdAvgTime <= 0 || m_psdTime <= 0 ) // Safety check, shouldn't happen but means we need to wait.
1515 {
1516 return 0;
1517 }
1518
1520
1521 if( m_sinceChange < deadTime )
1522 {
1523 return 0;
1524 }
1525
1526 // Here we would update psds, but don't do that if we're in the middle of calculating
1527 std::unique_lock<std::mutex> lock( m_goptMutex, std::try_to_lock );
1528 if( !lock.owns_lock() )
1529 {
1530 ///\todo update a frame-missed counter
1531 return 0;
1532 }
1533
1534 m_updating = true;
1535
1536 m_clPSDs = Eigen::Map<Eigen::Array<float, -1, -1>>(
1538
1539 m_updating = false;
1540
1541 lock.unlock();
1542
1543 if( sem_post( &m_goptSemaphore ) < 0 )
1544 {
1545 return log<software_critical, -1>( { __FILE__, __LINE__, errno, 0, "Error posting to semaphore" } );
1546 }
1547
1548 return 0;
1549}
1550
1552{
1553 static_cast<void>( dummy );
1554
1555 return 0;
1556}
1557
1558int modalGainOpt::processImage( void *curr_src, const freqShmimT &dummy )
1559{
1560 static_cast<void>( dummy );
1561
1563 {
1564 return log<software_error, -1>( { __FILE__, __LINE__, "got freq with width not 1" } );
1565 }
1566
1567 bool change = false;
1568
1569 float *f = static_cast<float *>( curr_src );
1570
1572
1573 if( sz != m_freq.size() )
1574 {
1575 change = true;
1576 }
1577
1578 if( !change ) // f is same size
1579 {
1580 for( size_t n = 0; n < sz; ++n )
1581 {
1582 if( f[n] != m_freq[n] )
1583 {
1584 change = true;
1585 break;
1586 }
1587 }
1588 }
1589
1590 if( change )
1591 {
1592 m_updating = true;
1593 std::lock_guard<std::mutex> lock( m_goptMutex );
1594
1595 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
1596
1597 m_freq.resize( sz );
1598
1599 for( size_t n = 0; n < sz; ++n )
1600 {
1601 m_freq[n] = f[n];
1602 }
1603
1604 m_fps = 2 * m_freq.back();
1605
1606 m_sinceChange = -1;
1607 m_goptUpdated = true;
1608 m_freqUpdated = true;
1609
1610 m_updating = false;
1611 std::cerr << "got freq: " << sz << '\n';
1612 std::cerr << " fps: " << m_fps << '\n';
1613 }
1614
1615 return 0;
1616}
1617
1619{
1620 static_cast<void>( dummy );
1621
1623 {
1624 return log<software_error, -1>( { __FILE__, __LINE__, "got gains with height not 1" } );
1625 }
1626
1627 return 0;
1628}
1629
1630int modalGainOpt::processImage( void *curr_src, const gainFactShmimT &dummy )
1631{
1632 static_cast<void>( dummy );
1633
1634 bool change = false;
1635
1637
1638 std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
1639
1640 if( w != m_gainFacts.size() )
1641 {
1642 m_updating = true;
1643 lock.lock();
1644 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
1645
1646 change = true;
1647 m_gainFacts.resize( w );
1648 }
1649
1650 float *g = static_cast<float *>( curr_src );
1651
1652 for( uint32_t n = 0; n < w; ++n )
1653 {
1654 if( change || m_gainFacts[n] != g[n] )
1655 {
1656 if( !change )
1657 {
1658 m_updating = true;
1659 lock.lock();
1660 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
1661 change = true;
1662 }
1663
1664 m_gainFacts[n] = g[n];
1665 }
1666 }
1667
1668 if( change )
1669 {
1670 if( m_loop )
1671 {
1672 m_sinceChange = -1;
1673 }
1674
1675 if(!m_pcOn)
1676 {
1677 int modesOn = 0;
1678
1679 for(size_t n = 0; n < m_gainFacts.size(); ++n)
1680 {
1681 if(m_gainFacts[n] > 0)
1682 {
1683 ++modesOn;
1684 }
1685 }
1686
1688 }
1689
1690
1691 m_updating = false;
1692 std::cerr << "got gains: " << m_gainFacts.size() << "\n";
1693
1694 lock.unlock();
1695 }
1696
1697 return 0;
1698}
1699
1701{
1702 static_cast<void>( dummy );
1703
1705 {
1706 return log<software_error, -1>( { __FILE__, __LINE__, "got multcoeffs with height not 1" } );
1707 }
1708
1709 return 0;
1710}
1711
1712int modalGainOpt::processImage( void *curr_src, const multFactShmimT &dummy )
1713{
1714 static_cast<void>( dummy );
1715
1716 bool change = false;
1717
1719
1720 std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
1721
1722 if( w != m_multFacts.size() )
1723 {
1724 m_updating = true;
1725 lock.lock();
1726 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
1727
1728 change = true;
1729 m_multFacts.resize( w );
1730 }
1731
1732 float *m = static_cast<float *>( curr_src );
1733
1734 for( uint32_t n = 0; n < w; ++n )
1735 {
1736 if( change || m_multFacts[n] != m[n] )
1737 {
1738 if( !change )
1739 {
1740 m_updating = true;
1741 lock.lock();
1742 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
1743
1744 change = true;
1745 }
1746
1747 m_multFacts[n] = m[n];
1748 }
1749 }
1750
1751 if( change )
1752 {
1753 if( m_loop )
1754 {
1755 m_sinceChange = -1;
1756 }
1757
1758 m_updating = false;
1759 m_goptUpdated = true;
1760
1761 std::cerr << "got mcs: " << m_multFacts.size() << " " << w << "\n";
1762 lock.unlock();
1763 }
1764
1765 return 0;
1766}
1767
1769{
1770 static_cast<void>( dummy );
1771
1773 {
1774 return log<software_error, -1>( { __FILE__, __LINE__, "got pc gains with height not 1" } );
1775 }
1776
1777 return 0;
1778}
1779
1780int modalGainOpt::processImage( void *curr_src, const pcGainFactShmimT &dummy )
1781{
1782 static_cast<void>( dummy );
1783
1784 bool change = false;
1785
1787
1788 std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
1789
1790 if( w != m_pcGainFacts.size() )
1791 {
1792 m_updating = true;
1793 lock.lock();
1794 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
1795
1796 change = true;
1797 m_pcGainFacts.resize( w );
1798 }
1799
1800 float *g = static_cast<float *>( curr_src );
1801
1802 for( uint32_t n = 0; n < w; ++n )
1803 {
1804 if( change || m_pcGainFacts[n] != g[n] )
1805 {
1806 if( !change )
1807 {
1808 m_updating = true;
1809 lock.lock();
1810 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
1811 change = true;
1812 }
1813
1814 m_pcGainFacts[n] = g[n];
1815 }
1816 }
1817
1818 if( change )
1819 {
1820 if( m_loop )
1821 {
1822 m_sinceChange = -1;
1823 }
1824
1825 if(m_pcOn)
1826 {
1827 int modesOn = 0;
1828
1829 for(size_t n = 0; n < m_pcGainFacts.size(); ++n)
1830 {
1831 if(m_gainFacts[n] > 0)
1832 {
1833 ++modesOn;
1834 }
1835 }
1836
1838 }
1839
1840 m_updating = false;
1841 std::cerr << "got pc gains: " << m_pcGainFacts.size() << "\n";
1842
1843 lock.unlock();
1844 }
1845
1846 return 0;
1847}
1848
1850{
1851 static_cast<void>( dummy );
1852
1854 {
1855 return log<software_error, -1>( { __FILE__, __LINE__, "got pcMultcoeffs with height not 1" } );
1856 }
1857
1858 return 0;
1859}
1860
1861int modalGainOpt::processImage( void *curr_src, const pcMultFactShmimT &dummy )
1862{
1863 static_cast<void>( dummy );
1864
1865 bool change = false;
1866
1868
1869 std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
1870
1871 if( w != m_pcMultFacts.size() )
1872 {
1873 m_updating = true;
1874 lock.lock();
1875 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
1876
1877 change = true;
1878 m_pcMultFacts.resize( w );
1879 }
1880
1881 float *m = static_cast<float *>( curr_src );
1882
1883 for( uint32_t n = 0; n < w; ++n )
1884 {
1885 if( change || m_pcMultFacts[n] != m[n] )
1886 {
1887 if( !change )
1888 {
1889 m_updating = true;
1890 lock.lock();
1891 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
1892
1893 change = true;
1894 }
1895
1896 m_pcMultFacts[n] = m[n];
1897 }
1898 }
1899
1900 if( change )
1901 {
1902 if( m_loop )
1903 {
1904 m_sinceChange = -1;
1905 }
1906
1907 m_updating = false;
1908 m_pcgoptUpdated = true;
1909
1910 lock.unlock();
1911 std::cerr << "got mcs: " << m_multFacts.size() << "\n";
1912 }
1913
1914 return 0;
1915}
1916
1918{
1919 static_cast<void>( dummy );
1920
1922 {
1923 return log<software_error, -1>( { __FILE__, __LINE__, "got numpccoeff's with height not 2" } );
1924 }
1925
1926 std::cerr << "numpccoeffShmimMonitorT::allocate\n";
1927 return 0;
1928}
1929
1930int modalGainOpt::processImage( void *curr_src, const numpccoeffShmimT &dummy )
1931{
1932 static_cast<void>( dummy );
1933
1934 bool change = false;
1935
1937
1938 std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
1939
1940 if( w != m_Na.size() || w != m_Nb.size() || w != m_regCounter.size() || w != m_regScale.size() )
1941 {
1942 m_updating = true;
1943 lock.lock();
1944 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
1945
1946 change = true;
1947 m_Na.resize( w );
1948 m_Nb.resize( w );
1949
1950 m_regCounter.resize( w );
1951
1952 // Initialize the regCounter
1953 int nc = 0;
1954
1955 for( size_t n = 0; n < m_regCounter.size(); ++n )
1956 {
1957 m_regCounter[n] = nc;
1958 ++nc;
1959
1960 if( nc >= m_nRegCycles )
1961 {
1962 nc = 0;
1963 }
1964 }
1965
1966 m_regScale.resize( w, -999 );
1967 m_gmaxLP.resize( w, 0 );
1968 }
1969
1970 mx::improc::eigenMap<uint32_t> Npc( reinterpret_cast<uint32_t *>( curr_src ), w, 2 );
1971
1972 for( uint32_t n = 0; n < w; ++n )
1973 {
1974 if( change || m_Na[n] != Npc( n, 0 ) || m_Nb[n] != Npc( n, 1 ) )
1975 {
1976 if( !change )
1977 {
1978 m_updating = true;
1979 lock.lock();
1980 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
1981
1982 change = true;
1983 }
1984
1985 m_Na[n] = Npc( n, 0 );
1986 m_Nb[n] = Npc( n, 1 );
1987 }
1988 }
1989
1990 if( change )
1991 {
1992 if( m_loop )
1993 {
1994 m_sinceChange = -1;
1995 }
1996
1997 m_updating = false;
1998 m_goptUpdated = true;
1999
2000 lock.unlock();
2001 std::cerr << "got num pc coeffs: " << m_Na.size() << "\n";
2002 }
2003
2004 return 0;
2005}
2006
2008{
2009 static_cast<void>( dummy );
2010
2011 return 0;
2012}
2013
2014int modalGainOpt::processImage( void *curr_src, const acoeffShmimT &dummy )
2015{
2016 static_cast<void>( dummy );
2017
2018 bool change = false;
2019
2020 std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
2021
2024
2025 // If there's a size change we lock
2026 if( w - 1 != m_as.rows() || h != m_as.cols() || h != m_NaCurrent.size() )
2027 {
2028 m_updating = true;
2029 lock.lock();
2030 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
2031
2032 change = true;
2033 m_NaCurrent.resize( h );
2034 m_as.resize( w - 1, h );
2035 }
2036
2037 eigenMap<float> ac( reinterpret_cast<float *>( curr_src ), w, h );
2038
2039 for( uint32_t cc = 0; cc < h; ++cc )
2040 {
2041 if( change || m_NaCurrent[cc] != ac( 0, cc ) )
2042 {
2043 if( !change )
2044 {
2045 m_updating = true;
2046 lock.lock();
2047 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
2048
2049 change = true;
2050 }
2051
2052 m_NaCurrent[cc] = ac( 0, cc );
2053 }
2054
2055 for( uint32_t rr = 1; rr < w; ++rr )
2056 {
2057 if( change || m_as( rr - 1, cc ) != ac( rr, cc ) )
2058 {
2059 if( !change )
2060 {
2061 m_updating = true;
2062 lock.lock();
2063 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
2064
2065 change = true;
2066 }
2067
2068 m_as( rr - 1, cc ) = ac( rr, cc );
2069 }
2070 }
2071 }
2072
2073 if( change )
2074 {
2075 if( m_loop && m_pcOn )
2076 {
2077 m_sinceChange = -1;
2078 }
2079
2080 m_updating = false;
2081 m_pcgoptUpdated = true;
2082
2083 lock.unlock();
2084 std::cerr << "got a coeffs: " << w << ' ' << h << ' ' << m_NaCurrent.size() << "\n";
2085 }
2086
2087 return 0;
2088}
2089
2091{
2092 static_cast<void>( dummy );
2093
2094 return 0;
2095}
2096
2097int modalGainOpt::processImage( void *curr_src, const bcoeffShmimT &dummy )
2098{
2099 static_cast<void>( dummy );
2100
2101 bool change = false;
2102
2103 std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
2104
2107
2108 // If there's a size change we lock
2109 if( w - 1 != m_bs.rows() || h != m_bs.cols() || h != m_NbCurrent.size() )
2110 {
2111 m_updating = true;
2112 lock.lock();
2113 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
2114
2115 change = true;
2116
2117 m_NbCurrent.resize( h );
2118 m_bs.resize( w - 1, h );
2119 }
2120
2121 eigenMap<float> bc( reinterpret_cast<float *>( curr_src ), w, h );
2122
2123 for( uint32_t cc = 0; cc < h; ++cc )
2124 {
2125 if( change || m_NbCurrent[cc] != bc( 0, cc ) )
2126 {
2127 if( !change )
2128 {
2129 m_updating = true;
2130 lock.lock();
2131 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
2132
2133 change = true;
2134 }
2135
2136 m_NbCurrent[cc] = bc( 0, cc );
2137 }
2138
2139 for( uint32_t rr = 1; rr < w; ++rr )
2140 {
2141 if( change || m_bs( rr - 1, cc ) != bc( rr, cc ) )
2142 {
2143 if( !change )
2144 {
2145 m_updating = true;
2146 lock.lock();
2147 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
2148
2149 change = true;
2150 }
2151
2152 m_bs( rr - 1, cc ) = bc( rr, cc );
2153 }
2154 }
2155 }
2156
2157 if( change )
2158 {
2159 if( m_loop && m_pcOn )
2160 {
2161 m_sinceChange = -1;
2162 }
2163
2164 m_updating = false;
2165 m_pcgoptUpdated = true;
2166
2167 std::cerr << "got b coeffs: " << w << ' ' << h << ' ' << m_NbCurrent.size() << "\n";
2168
2169 lock.unlock();
2170 }
2171
2172 return 0;
2173}
2174
2176{
2177 static_cast<void>( dummy );
2178
2179 return 0;
2180}
2181
2182int modalGainOpt::processImage( void *curr_src, const gainCalShmimT &dummy )
2183{
2184 static_cast<void>( dummy );
2185
2187 {
2188 return log<software_error, -1>( { __FILE__, __LINE__, "got gainCals with height not 1" } );
2189 }
2190
2191 bool change = false;
2192
2194
2195 std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
2196
2197 if( w != m_gainCals.size() )
2198 {
2199 m_updating = true;
2200 lock.lock();
2201
2202 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
2203
2204 change = true;
2205 m_gainCals.resize( w );
2206 }
2207
2208 float *g = static_cast<float *>( curr_src );
2209
2210 for( uint32_t n = 0; n < w; ++n )
2211 {
2212 if( change || m_gainCals[n] != g[n] )
2213 {
2214 if( !change )
2215 {
2216 m_updating = true;
2217 lock.lock();
2218 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
2219
2220 change = true;
2221 }
2222
2223 m_gainCals[n] = g[n];
2224 }
2225 }
2226
2227 if( change )
2228 {
2229 m_sinceChange = -1;
2230 m_updating = false;
2231 std::cerr << "got gainCals: " << m_gainCals.size() << "\n";
2232 lock.unlock();
2233 }
2234
2235 return 0;
2236}
2237
2239{
2240 static_cast<void>( dummy );
2241
2242 return 0;
2243}
2244
2245int modalGainOpt::processImage( void *curr_src, const gainCalFactShmimT &dummy )
2246{
2247 static_cast<void>( dummy );
2248
2250 {
2251 return log<software_error, -1>( { __FILE__, __LINE__, "got gainCalFacts with height not 1" } );
2252 }
2253
2254 bool change = false;
2255
2257
2258 std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
2259
2260 if( w != m_gainCalFacts.size() )
2261 {
2262 m_updating = true;
2263 lock.lock();
2264 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
2265
2266 change = true;
2267 m_gainCalFacts.resize( w );
2268 }
2269
2270 float *g = static_cast<float *>( curr_src );
2271
2272 for( uint32_t n = 0; n < w; ++n )
2273 {
2274 if( change || m_gainCalFacts[n] != g[n] )
2275 {
2276 if( !change )
2277 {
2278 m_updating = true;
2279 lock.lock();
2280 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
2281
2282 change = true;
2283 }
2284
2285 m_gainCalFacts[n] = g[n];
2286 }
2287 }
2288
2289 if( change )
2290 {
2291 m_sinceChange = -1;
2292 m_updating = false;
2293 std::cerr << "got gainCalsFacts: " << m_gainCalFacts.size() << "\n";
2294 lock.unlock();
2295 }
2296
2297 return 0;
2298}
2299
2301{
2302 static_cast<void>( dummy );
2303
2304 return 0;
2305}
2306
2307int modalGainOpt::processImage( void *curr_src, const tauShmimT &dummy )
2308{
2309 static_cast<void>( dummy );
2310
2312 {
2313 return log<software_error, -1>( { __FILE__, __LINE__, "got tau with height not 1" } );
2314 }
2315
2316 bool change = false;
2317
2319
2320 std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
2321
2322 if( w != m_taus.size() )
2323 {
2324 m_updating = true;
2325 lock.lock();
2326 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
2327
2328 change = true;
2329 m_taus.resize( w );
2330 }
2331
2332 float *t = static_cast<float *>( curr_src );
2333
2334 for( uint32_t n = 0; n < w; ++n )
2335 {
2336 if( change || m_taus[n] != t[n] )
2337 {
2338 if( !change )
2339 {
2340 m_updating = true;
2341 lock.lock();
2342 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
2343
2344 change = true;
2345 }
2346
2347 m_taus[n] = t[n];
2348 }
2349 }
2350
2351 if( change )
2352 {
2353 m_sinceChange = -1;
2354 m_updating = false;
2355 m_goptUpdated = true;
2356 std::cerr << "got taus: " << m_taus.size() << "\n";
2357 lock.unlock();
2358 }
2359 return 0;
2360}
2361
2363{
2364 static_cast<void>( dummy );
2365
2366 return 0;
2367}
2368
2369int modalGainOpt::processImage( void *curr_src, const noiseShmimT &dummy )
2370{
2371 static_cast<void>( dummy );
2372
2374 {
2375 return log<software_error, -1>( { __FILE__, __LINE__, "got tau with width not 3" } );
2376 }
2377
2378 bool change = false;
2379
2381
2382 std::unique_lock<std::mutex> lock( m_goptMutex, std::defer_lock );
2383
2384 if( h != m_noiseParams.cols() )
2385 {
2386 m_updating = true;
2387 lock.lock();
2388 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
2389
2390 change = true;
2391 m_noiseParams.resize( 3, h );
2392 }
2393
2394 mx::improc::eigenMap<float> np( static_cast<float *>( curr_src ), 3, h );
2395
2396 for( uint32_t n = 0; n < h; ++n )
2397 {
2398 if( change || m_noiseParams( 0, n ) != np( 0, n ) || m_noiseParams( 1, n ) != np( 1, n ) ||
2399 m_noiseParams( 2, n ) != np( 2, n ) )
2400 {
2401 if( !change )
2402 {
2403 m_updating = true;
2404 lock.lock();
2405 m_updating = true; // Make sure it didn't get set to false by thread that had the lock
2406
2407 change = true;
2408 }
2409
2410 m_noiseParams.col( n ) = np.col( n );
2411 }
2412 }
2413
2414 if( change )
2415 {
2416 m_sinceChange = -1;
2417 m_updating = false;
2418 m_goptUpdated = true;
2419 std::cerr << "got noise params: " << m_noiseParams.rows() << " x " << m_noiseParams.cols() << "\n";
2420 lock.unlock();
2421 }
2422 return 0;
2423}
2424
2426{
2427 static_cast<void>( dummy );
2428
2429 std::cerr << "Got WFS avg: " << wfsavgShmimMonitorT::m_width << " x " << wfsavgShmimMonitorT::m_height << '\n';
2430 return 0;
2431}
2432
2433int modalGainOpt::processImage( void *curr_src, const wfsavgShmimT &dummy )
2434{
2435 static_cast<void>( dummy );
2436
2437 m_wfsavg = mx::improc::eigenMap<float>(
2439
2440 if( m_wfsavg.rows() == m_wfsmask.rows() && m_wfsavg.cols() == m_wfsmask.cols() )
2441 {
2442 m_counts = ( m_wfsavg * m_wfsmask ).sum();
2443
2444 // std::cerr << "counts: " << m_counts << '\n';
2445 }
2446
2447 return 0;
2448}
2449
2451{
2452 static_cast<void>( dummy );
2453
2454 std::cerr << "Got WFS mask: " << wfsmaskShmimMonitorT::m_width << " x " << wfsmaskShmimMonitorT::m_height << '\n';
2455 return 0;
2456}
2457
2458int modalGainOpt::processImage( void *curr_src, const wfsmaskShmimT &dummy )
2459{
2460 static_cast<void>( dummy );
2461
2462 m_wfsmask = mx::improc::eigenMap<float>(
2464
2465 m_npix = m_wfsmask.sum();
2466
2467 if( m_wfsavg.rows() == m_wfsmask.rows() && m_wfsavg.cols() == m_wfsmask.cols() )
2468 {
2469 m_counts = ( m_wfsavg * m_wfsmask ).sum();
2470 }
2471
2472 return 0;
2473}
2474
2476{
2477 static std::vector<bool> logged( 50, false );
2478
2479 int L = 0;
2480 if( m_clPSDs.rows() == 0 || m_clPSDs.cols() == 0 ) // somehow here without any data
2481 {
2482 if( !logged[L] )
2483 {
2484 log<software_error>( { __FILE__, __LINE__, "PSDs have not been updated" } );
2485 }
2486 logged[L] = true;
2487 return -1;
2488 }
2489 logged[L++] = false;
2490
2491 if( static_cast<size_t>( m_clPSDs.rows() ) != m_freq.size() )
2492 {
2493 if( !logged[L] )
2494 {
2495 log<software_error>( { __FILE__, __LINE__, "PSDs and freq size mismatch" } );
2496 }
2497 logged[L] = true;
2498 return -1;
2499 }
2500 logged[L++] = false;
2501
2502 if( m_nModes != m_gainFacts.size() )
2503 {
2504 if( !logged[L] )
2505 {
2506 log<software_error>( { __FILE__, __LINE__, "PSDs and gains number of modes mismatch" } );
2507 }
2508 logged[L] = true;
2509 return -1;
2510 }
2511 logged[L++] = false;
2512
2513 if( m_nModes != m_multFacts.size() )
2514 {
2515 if( !logged[L] )
2516 {
2517 log<software_error>( { __FILE__, __LINE__, "PSDs and mult coeffs number of modes mismatch" } );
2518 }
2519 logged[L] = true;
2520 return -1;
2521 }
2522 logged[L++] = false;
2523
2524 if( m_nModes != m_gainCals.size() )
2525 {
2526 if( !logged[L] )
2527 {
2528 log<software_error>( { __FILE__, __LINE__, "PSDs and gain cals number of modes mismatch" } );
2529 }
2530 logged[L] = true;
2531 return -1;
2532 }
2533 logged[L++] = false;
2534
2535 if( m_nModes != m_gainCalFacts.size() )
2536 {
2537 if( !logged[L] )
2538 {
2539 log<software_error>( { __FILE__, __LINE__, "PSDs and gain cal facts number of modes mismatch" } );
2540 }
2541 logged[L] = true;
2542 return -1;
2543 }
2544 logged[L++] = false;
2545
2546 if( m_nModes != m_taus.size() )
2547 {
2548 if( !logged[L] )
2549 {
2550 log<software_error>( { __FILE__, __LINE__, "Loop taus have not been set" } );
2551 }
2552 logged[L] = true;
2553 return -1;
2554 }
2555 logged[L++] = false;
2556
2557 /*if( m_clPSDs.cols() != m_noiseParams.cols() || m_noiseParams.rows() != 3 )
2558 {
2559 if( !logged[L] )
2560 {
2561 log<software_error>( { __FILE__, __LINE__, "noise params have not been set" } );
2562 }
2563 logged[L] = true;
2564 return -1;
2565 }
2566 logged[L++] = false;*/
2567
2568 if( m_fps <= 0 )
2569 {
2570 if( !logged[L] )
2571 {
2572 log<software_error>( { __FILE__, __LINE__, "Loop fps has not been set" } );
2573 }
2574 logged[L] = true;
2575 return -1;
2576 }
2577 logged[L++] = false;
2578
2579 if( m_olPSDStream == nullptr )
2580 {
2581 if( !logged[L] )
2582 {
2583 log<software_error>( { __FILE__, __LINE__, "m_olPSDStream is not allocated" } );
2584 }
2585 logged[L] = true;
2586 return -1;
2587 }
2588 logged[L++] = false;
2589
2590 if( m_noisePSDStream == nullptr )
2591 {
2592 if( !logged[L] )
2593 {
2594 log<software_error>( { __FILE__, __LINE__, "m_noisePSDStream is not allocated" } );
2595 }
2596 logged[L] = true;
2597 return -1;
2598 }
2599 logged[L++] = false;
2600
2601 if( m_clXferCurrentStream == nullptr )
2602 {
2603 if( !logged[L] )
2604 {
2605 log<software_error>( { __FILE__, __LINE__, "m_clXferCurrentStream is not allocated" } );
2606 }
2607 logged[L] = true;
2608 return -1;
2609 }
2610 logged[L++] = false;
2611
2612 if( m_clXferSIStream == nullptr )
2613 {
2614 if( !logged[L] )
2615 {
2616 log<software_error>( { __FILE__, __LINE__, "m_clXferSIStream is not allocated" } );
2617 }
2618 logged[L] = true;
2619 return -1;
2620 }
2621 logged[L++] = false;
2622
2623 if( m_optGainStream == nullptr )
2624 {
2625 if( !logged[L] )
2626 {
2627 log<software_error>( { __FILE__, __LINE__, "optGainsStream is not allocated" } );
2628 }
2629 logged[L] = true;
2630 return -1;
2631 }
2632 logged[L++] = false;
2633
2634 if( m_optGainSIStream == nullptr )
2635 {
2636 if( !logged[L] )
2637 {
2638 log<software_error>( { __FILE__, __LINE__, "optGainsStream SI is not allocated" } );
2639 }
2640 logged[L] = true;
2641 return -1;
2642 }
2643 logged[L++] = false;
2644
2645 // Check the PC shmims that we don't automatically create
2646 if( m_Na.size() != m_nModes || m_NaCurrent.size() != m_nModes || (size_t)m_as.cols() != m_nModes ||
2647 m_Nb.size() != m_nModes || m_NbCurrent.size() != m_nModes || (size_t)m_bs.cols() != m_nModes ||
2648 m_pcGainFacts.size() != m_nModes || m_pcMultFacts.size() != m_nModes )
2649 {
2650
2651 if( allocatePCShmims() < 0 )
2652 {
2653 log<software_error>( { __FILE__, __LINE__, "error allocating PC shmims" } );
2654 }
2655
2656 if( m_Na.size() != m_nModes || m_NaCurrent.size() != m_nModes || (size_t)m_as.cols() != m_nModes ||
2657 m_Nb.size() != m_nModes || m_NbCurrent.size() != m_nModes || (size_t)m_bs.cols() != m_nModes ||
2658 m_pcGainFacts.size() != m_nModes || m_pcMultFacts.size() != m_nModes )
2659 {
2660
2661 if( !logged[L] )
2662 {
2663 log<software_error>( { __FILE__, __LINE__, "PC shmims not allcoated" } );
2664 }
2665 logged[L] = true;
2666 return -1;
2667 }
2668 else
2669 {
2670 logged[L] = false;
2671 }
2672 }
2673 else
2674 {
2675 logged[L] = false;
2676 }
2677 ++L;
2678
2679 if( m_clXferLPStream == nullptr )
2680 {
2681 if( !logged[L] )
2682 {
2683 log<software_error>( { __FILE__, __LINE__, "m_clXferLPStream is not allocated" } );
2684 }
2685 logged[L] = true;
2686 return -1;
2687 }
2688 logged[L++] = false;
2689
2690 if( m_optGainLPStream == nullptr )
2691 {
2692 if( !logged[L] )
2693 {
2694 log<software_error>( { __FILE__, __LINE__, "m_optGainLPStream is not allocated" } );
2695 }
2696 logged[L] = true;
2697 return -1;
2698 }
2699 logged[L++] = false;
2700
2701 if( m_nModes != m_optGainLP.size() )
2702 {
2703 if( !logged[L] )
2704 {
2705 log<software_error>( { __FILE__, __LINE__, "m_optGainLP is not allocated" } );
2706 }
2707 logged[L] = true;
2708 return -1;
2709 }
2710 logged[L++] = false;
2711
2712 return 0;
2713}
2714
2716{
2717 float mc = m_noiseParams( 1, n ) * m_counts / m_emg;
2718
2719 float snr2 = ( mc * mc ) / ( mc + m_npix * pow( m_noiseParams( 2, n ) / m_emg, 2 ) );
2720
2721 return 0.05 * m_noiseParams( 0, n ) / snr2;
2722}
2723
2728
2730{
2732
2733 while( m_goptThreadInit == true && shutdown() == 0 )
2734 {
2735 sleep( 1 );
2736 }
2737
2738 while( shutdown() == 0 )
2739 {
2740 timespec ts;
2741 XWC_SEM_WAIT_TS_RETVOID( ts, 1, 0 );
2742
2743 if( sem_timedwait( &m_goptSemaphore, &ts ) == 0 )
2744 {
2745 std::lock_guard<std::mutex> lock( m_goptMutex );
2746
2747 if( checkSizes() < 0 )
2748 {
2749 std::cerr << "check sizes failed\n";
2750 continue; // we just wait
2751 }
2752
2753 // m_doPCCalcs = false;
2754
2756 {
2757 if( m_goptCurrent.size() != m_gainFacts.size() )
2758 {
2759 m_freqUpdated = true; // force freq update in this case
2760 }
2761
2762 std::cerr << "updating gopt structures\n";
2763
2764 m_goptCurrent.resize( m_gainFacts.size() );
2765 m_goptSI.resize( m_gainFacts.size() );
2766 m_goptLP.resize( m_gainFacts.size() );
2767 m_linPred.resize( m_gainFacts.size() );
2768
2769 for( size_t n = 0; n < m_goptCurrent.size(); ++n )
2770 {
2771 m_goptCurrent[n].Ti( 1.0 / m_fps );
2772 m_goptCurrent[n].tau( m_taus[n] );
2773
2774 m_goptSI[n].Ti( 1.0 / m_fps );
2775 m_goptSI[n].tau( m_taus[n] );
2776
2777 m_goptLP[n].Ti( 1.0 / m_fps );
2778 m_goptLP[n].tau( m_taus[n] );
2779
2780 if( !m_pcOn )
2781 {
2782 m_goptCurrent[n].setLeakyIntegrator( m_mult * m_multFacts[n] );
2783 }
2784 else
2785 {
2786 std::vector<float> ta( m_NaCurrent[n] );
2787 for( size_t m = 0; m < ta.size(); ++m )
2788 {
2789 ta[m] = m_as( m, n );
2790 }
2791 m_goptCurrent[n].a( ta );
2792
2793 std::vector<float> tb( m_NbCurrent[n] );
2794 for( size_t m = 0; m < tb.size(); ++m )
2795 {
2796 tb[m] = m_bs( m, n );
2797 }
2798 m_goptCurrent[n].b( tb );
2799
2800 m_goptCurrent[n].remember( m_pcMult * m_pcMultFacts[n] );
2801 }
2802
2803 m_goptSI[n].setLeakyIntegrator( m_mult * m_multFacts[n] );
2804
2805 if( m_freqUpdated )
2806 {
2807 m_goptCurrent[n].f( m_freq );
2808 m_goptSI[n].f( m_freq );
2809 m_goptLP[n].f( m_freq );
2810 }
2811
2812 m_gmaxSI[n] = m_goptSI[n].maxStableGain();
2813 }
2814
2815 m_goptUpdated = false;
2816 m_pcgoptUpdated = false;
2817 m_freqUpdated = false;
2818
2819 std::cerr << "done.\n";
2820 }
2821
2823 if( m_updating )
2824 {
2825 continue;
2826 }
2827
2828 timePointT t0 = std::chrono::steady_clock::now();
2829
2831
2832 int off = 0;
2833 int offLP = 0;
2834
2835#pragma omp parallel for num_threads( 15 )
2836 for( size_t n = 0; n < m_goptCurrent.size(); ++n )
2837 {
2838 if( m_updating || m_shutdown )
2839 {
2840 continue; // don't break b/c of omp
2841 }
2842
2843 if( !m_pcOn )
2844 {
2846
2847 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
2848 {
2849 m_clXferCurrent( f, n ) =
2851 }
2852 }
2853 else
2854 {
2855 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
2856 {
2857 m_clXferCurrent( f, n ) =
2859 }
2860 }
2861
2863 // Calculate the OL PSD with the current gopt (PC or SI)
2865 if( !m_loop )
2866 {
2868 for( size_t f = 1; f < m_goptCurrent[n].f_size(); ++f )
2869 {
2870 m_olPSDs[n][f] = m_clPSDs( f, n ) / og2;
2871 }
2872 }
2873 else
2874 {
2876 for( size_t f = 1; f < m_goptCurrent[n].f_size(); ++f )
2877 {
2878 m_olPSDs[n][f] = ( m_clPSDs( f, n ) / og2 ) / m_clXferCurrent( f, n );
2879 }
2880 }
2881
2883
2884 m_olPSDs[n][0] = m_olPSDs[n][1];
2885
2886 bool flagOff = false;
2887 float extrap = 0;
2888
2889 // Calculate the noise as the 25th percentile in log10
2890 // this is to avoid spikes that make the noise too high
2891 size_t f0 = 0.5 * m_goptCurrent[n].f_size();
2892 size_t f1 = m_goptCurrent[n].f_size();
2893
2894 std::vector<float> npsd( f1 - f0 );
2895 for( size_t f = f0; f < f1; ++f )
2896 {
2897 npsd[f - f0] = log10( m_olPSDs[n][f] );
2898 }
2899 float pct = 0.25;
2900
2902 if( n < 2 )
2903 {
2904 pct = 0.05;
2905 }
2906
2907 auto nth = npsd.begin() + pct * ( f1 - f0 );
2908 std::nth_element( npsd.begin(), nth, npsd.end() );
2909
2911
2912 float noise = pow( 10, *nth );
2913 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
2914 {
2915 m_nPSDs[n][f] = noise;
2916 }
2917
2918 if( m_extrapOL )
2919 {
2920 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
2921 {
2922 m_olPSDs[n][f] = m_olPSDs[n][f] - m_nPSDs[n][f];
2923 }
2924
2926
2927 // Calculate an average extrapolation point referenced to 1 Hz
2928
2929 extrap = 0;
2930 int nexp = 0;
2931 int noff = 0;
2932 for( size_t f = 1; f < 0.05 * m_freq.size(); ++f )
2933 {
2934 // This is a threshold for "too noisy"
2935 ///\todo make configurable
2936 if( m_olPSDs[n][f] <= 0.1 * m_nPSDs[n][f] )
2937 {
2938 ++noff;
2939 continue;
2940 }
2941 extrap += log10( m_olPSDs[n][f] * pow( m_freq[f] / m_freq[1], 8. / 3. ) );
2942 ++nexp;
2943 }
2944
2945 extrap = pow( 10, extrap / nexp );
2946
2948 if( noff > 0.5 * ( 0.05 * m_freq.size() - 1 ) && n > 1 )
2949 {
2950 flagOff = true;
2951 }
2952 }
2953
2954 // flagOff = false;
2955
2957
2958 if( flagOff )
2959 {
2961 #pragma omp critical
2962 {
2963 ++off;
2964 }
2965
2966 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
2967 {
2968 m_olPSDs[n][f] = m_nPSDs[n][f];
2969 }
2970
2971 m_modeVarOL[n] = mx::sigproc::psdVar( m_freq, m_olPSDs[n] );
2972
2973 m_optGainSI[n] = 0;
2975
2976 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
2977 {
2978 m_clXferSI( f, n ) = 1;
2979 }
2980
2981 m_timesOnSI[n] = 0;
2982 }
2983 else
2984 {
2986
2987 if( m_extrapOL )
2988 {
2989 std::vector<float> tosmooth( m_nFreq );
2990
2991 for( size_t f = 0; f < m_nFreq; ++f )
2992 {
2993 if( m_olPSDs[n][f] < 0 )
2994 {
2995 tosmooth[f] = extrap * pow( m_freq[1] / m_freq[f], 8. / 3. );
2996 }
2997 else
2998 {
2999 tosmooth[f] = m_olPSDs[n][f];
3000 }
3001 }
3002
3003 std::vector<float> l10( m_nFreq ), smol( m_nFreq );
3004 std::vector<int> smw( m_nFreq );
3005 smw[0] = 2;
3006 smw[1] = 2;
3007 l10[0] = log10( tosmooth[0] );
3008 l10[1] = log10( tosmooth[1] );
3009
3010 for( size_t f = 2; f < smw.size(); ++f )
3011 {
3012 smw[f] = 2 + static_cast<float>( f ) / 10;
3013 l10[f] = log10( tosmooth[f] );
3014 }
3015
3016 mx::math::vectorSmoothMean( smol, l10, smw );
3017
3018 for( size_t f = 0; f < m_nFreq; ++f )
3019 {
3020 smol[f] = pow( 10, smol[f] );
3021 }
3022
3023 for( size_t f = 0; f < m_nFreq; ++f )
3024 {
3025 if( m_olPSDs[n][f] < m_nPSDs[n][f] )
3026 {
3027 m_olPSDs[n][f] = smol[f];
3028 }
3029 }
3030 }
3031
3033 m_modeVarOL[n] = mx::sigproc::psdVar( m_freq, m_olPSDs[n] );
3034
3035 m_optGainSI[n] =
3036 m_goptSI[n].optGainOpenLoop( m_modeVarSI[n], m_olPSDs[n], m_nPSDs[n], m_gmaxSI[n], false );
3037
3038 if( ( m_modeVarSI[n] - m_modeVarOL[n] ) / m_modeVarOL[n] > -0.001 )
3039 {
3040 #pragma omp critical
3041 {
3042 ++off;
3043 }
3044
3046 m_optGainSI[n] = 0;
3048
3049 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
3050 {
3051 m_clXferSI( f, n ) = 1;
3052 }
3053
3054 m_timesOnSI[n] = 0;
3055 }
3056 else if( m_timesOnSI[n] < 5 )
3057 {
3058 #pragma omp critical
3059 {
3060 ++off;
3061 }
3062
3064 // Would be on, but we debounce
3065 m_optGainSI[n] = 0;
3067
3068 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
3069 {
3070 m_clXferSI( f, n ) = 1;
3071 }
3072
3073 ++m_timesOnSI[n];
3074 }
3075 else
3076 {
3078 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
3079 {
3080 m_clXferSI( f, n ) = m_goptSI[n].clETF2( f, m_optGainSI[n] );
3081 }
3082
3083 ++m_timesOnSI[n];
3084 }
3085 }
3086
3087 if( m_doPCCalcs && !flagOff )
3088 {
3090 if( m_regScale[n] == -999 || m_regCounter[n] >= m_nRegCycles )
3091 {
3093 float min_sc;
3094 float gmax_lp = 0;
3095
3097 m_optGainLP[n],
3098 m_modeVarLP[n],
3099 min_sc,
3100 m_goptLP[n],
3101 m_olPSDs[n],
3102 m_nPSDs[n],
3103 m_Na[n] ) < 0 )
3104 {
3106
3107 m_optGainLP[n] = 0;
3109
3110 ///\todo what to do about coeffs?
3111 }
3112
3114
3115 if( m_regScale[n] == -999 )
3116 {
3119 }
3120 else
3121 {
3123 m_regCounter[n] = 0;
3124 }
3125
3126 m_regScale[n] = min_sc;
3127 m_gmaxLP[n] = gmax_lp;
3128 }
3129 else
3130 {
3132 // use pre-regularized version
3133 float psdReg = m_olPSDs[n][0];
3135 m_olPSDs[n], m_nPSDs[n], psdReg * pow( 10, -m_regScale[n] / 10 ), m_Na[n] ) < 0 )
3136 {
3137 m_optGainLP[n] = 0;
3139
3140 ///\todo what to do about coeffs?
3141 }
3142 else
3143 {
3144 m_goptLP[n].a( m_linPred[n].m_lp.m_c );
3145 m_goptLP[n].b( m_linPred[n].m_lp.m_c );
3146
3147 m_optGainLP[n] = m_goptLP[n].optGainOpenLoop(
3148 m_modeVarLP[n], m_olPSDs[n], m_nPSDs[n], m_gmaxLP[n], false );
3149 }
3150 ++m_regCounter[n];
3151 }
3152
3154
3155 /*if( ( m_modeVarLP[n] - m_modeVarOL[n] ) / m_modeVarOL[n] > -0.001 )
3156 {
3157 m_optGainLP[n] = 0;
3158 m_modeVarLP[n] = m_modeVarOL[n];
3159
3160 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
3161 {
3162 m_clXferLP( f, n ) = 1;
3163 }
3164
3165 m_timesOnLP[n] = 0;
3166 }
3167 else*/
3168 if( ( m_modeVarLP[n] - m_modeVarSI[n] ) / m_modeVarSI[n] > -0.001 )
3169 {
3170 #pragma omp critical
3171 {
3172 ++offLP;
3173 }
3174
3175
3179
3180 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
3181 {
3182 m_clXferLP( f, n ) = m_clXferSI( f, n );
3183 }
3184
3185 m_timesOnLP[n] = 0;
3186 }
3187 else if( m_timesOnLP[n] < 5 )
3188 {
3189 #pragma omp critical
3190 {
3191 ++offLP;
3192 }
3193
3194
3198
3199 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
3200 {
3201 m_clXferLP( f, n ) = m_clXferSI( f, n );
3202 }
3203
3204 ++m_timesOnLP[n];
3205 }
3206 else
3207 {
3209 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
3210 {
3211 m_clXferLP( f, n ) = m_goptLP[n].clETF2( f, m_optGainLP[n] );
3212 }
3213
3214 ++m_timesOnLP[n];
3215 }
3216 }
3217 else
3218 {
3219 #pragma omp critical
3220 {
3221 ++offLP;
3222 }
3223
3225 m_optGainLP[n] = 0;
3226
3227 ++m_regCounter[n];
3228
3229 for( size_t f = 0; f < m_goptCurrent[n].f_size(); ++f )
3230 {
3231 m_clXferLP( f, n ) = 1;
3232 }
3233
3234 m_timesOnLP[n] = 0;
3235 }
3236
3238 }
3239
3241
3244
3245
3246
3247
3248 if( m_updating )
3249 {
3250 continue; // don't break b/c of omp
3251 }
3252
3253 timePointT t1 = std::chrono::steady_clock::now();
3254 durationT dt = t1 - t0;
3255
3256 std::cerr << "Optimization took " << dt.count() << " seconds\n";
3257
3258 /*float totVar = 0;
3259 for( size_t n = 0; n < m_modeVarSI.size(); ++n )
3260 {
3261 totVar += m_modeVarSI[n];
3262 }*/
3263
3264 // std::cerr << "total variance: " << totVar << '\n';
3265
3266 float *f = m_optGainStream->array.F;
3267 float *fSI = m_optGainSIStream->array.F;
3268 float *fmaxSI = m_maxGainSIStream->array.F;
3269 float *fLP = m_optGainLPStream->array.F;
3270 float *fmaxLP = m_optGainLPStream->array.F;
3271
3272 mx::improc::eigenMap<float> mvs( m_modevarStream->array.F, 3, m_modeVarSI.size() );
3273
3274 m_optGainStream->md->write = 1;
3275 m_optGainSIStream->md->write = 1;
3276 m_maxGainSIStream->md->write = 1;
3277 m_optGainLPStream->md->write = 1;
3278 m_maxGainLPStream->md->write = 1;
3279 m_modevarStream->md->write = 1;
3280
3281 for( size_t n = 0; n < m_optGainSI.size(); ++n )
3282 {
3283 // if( m_timesOnSI[n] > 5 )
3284 {
3286 fSI[n] = f[n];
3288 }
3289
3290 // if( m_timesOnLP[n] > 5 )
3291 {
3294 }
3295
3296 mvs( 0, n ) = m_modeVarOL[n];
3297 mvs( 1, n ) = m_modeVarSI[n];
3298 mvs( 2, n ) = m_modeVarLP[n];
3299 }
3300
3307
3308 if( m_autoUpdate || m_updateOnce || m_dump )
3309 {
3310 float *f = gainFactShmimMonitorT::m_imageStream.array.F;
3311
3313 if( m_dump )
3314 {
3315 for( size_t n = 0; n < m_nModes; ++n )
3316 {
3317 // if( m_timesOnSI[n] > 5 )
3318 {
3320 }
3321 }
3322 }
3323 else
3324 {
3325 for( size_t n = 0; n < m_nModes; ++n )
3326 {
3327 // if( m_timesOnSI[n] > 5 )
3328 {
3329 f[n] = f[n] + m_gainGain *
3331 f[n] );
3332 }
3333 }
3334 }
3335
3337
3338 if( m_doPCCalcs )
3339 {
3341 float *fa = acoeffShmimMonitorT::m_imageStream.array.F;
3342 float *fb = bcoeffShmimMonitorT::m_imageStream.array.F;
3343
3347
3348 if( m_dump )
3349 {
3350 for( size_t n = 0; n < m_optGainLP.size(); ++n )
3351 {
3352 // if( m_timesOnLP[n] > 5 )
3353 {
3355
3356 // To be safe we treat this as if Na and Nb can be different, but they can't be.
3357 fa[n] = m_Na[n];
3358 fb[n] = m_Nb[n];
3359 for( uint32_t k = 0; k < m_Na[n]; ++k )
3360 {
3361 fa[1 + k] = m_goptLP[n].a()[k];
3362 }
3363 for( uint32_t k = m_Na[n]; k < acoeffShmimMonitorT::m_width - 1; ++k )
3364 {
3365 fa[1 + k] = 0;
3366 }
3367
3368 for( uint32_t k = 0; k < m_Nb[n]; ++k )
3369 {
3370 fb[1 + k] = m_goptLP[n].b()[k];
3371 }
3372 for( uint32_t k = m_Nb[n]; k < bcoeffShmimMonitorT::m_width - 1; ++k )
3373 {
3374 fb[1 + k] = 0;
3375 }
3376 }
3377 }
3378 }
3379 else
3380 {
3381 for( size_t n = 0; n < m_optGainSI.size(); ++n )
3382 {
3383 // if( m_timesOnLP[n] > 5 )
3384 {
3385 fpc[n] = fpc[n] +
3386 m_gainGain *
3388 fpc[n] );
3389
3390 // To be safe we treat this as if Na and Nb can be different, but they can't be.
3391 fa[n] = m_Na[n];
3392 fb[n] = m_Nb[n];
3393 for( uint32_t k = 0; k < m_Na[n]; ++k )
3394 {
3395 fa[1 + k] = fa[1 + k] + m_gainGain * ( m_goptLP[n].a()[k] - fa[1 + k] );
3396 }
3397 for( uint32_t k = m_Na[n]; k < acoeffShmimMonitorT::m_width - 1; ++k )
3398 {
3399 fa[1 + k] = 0;
3400 }
3401
3402 for( uint32_t k = 0; k < m_Nb[n]; ++k )
3403 {
3404 fb[1 + k] = fb[1 + k] + m_gainGain * ( m_goptLP[n].b()[k] - fb[1 + k] );
3405 }
3406 for( uint32_t k = m_Nb[n]; k < bcoeffShmimMonitorT::m_width - 1; ++k )
3407 {
3408 fb[1 + k] = 0;
3409 }
3410 }
3411 }
3412 }
3413
3417 }
3418
3419 if( m_dump )
3420 {
3421 log<text_log>( "gains updated by dump", logPrio::LOG_NOTICE );
3422 m_dump = false;
3423 }
3424 else if( m_updateOnce && !m_autoUpdate )
3425 {
3426 log<text_log>( "gains updated once", logPrio::LOG_NOTICE );
3427 }
3428
3429 m_updateOnce = false;
3430 }
3431
3432 if( m_loop & m_autoUpdate )
3433 {
3434 m_sinceChange = -1;
3435 }
3436
3437 // Update OL PSDs and Transfer Functions
3438 m_olPSDStream->md->write = 1;
3439 m_noisePSDStream->md->write = 1;
3440 m_clXferCurrentStream->md->write = 1;
3441 m_clXferSIStream->md->write = 1;
3442 m_clXferLPStream->md->write = 1;
3443
3444 for( size_t q = 0; q < m_olPSDs.size(); ++q )
3445 {
3446 memcpy( m_olPSDStream->array.F + q * m_olPSDs[0].size(),
3447 m_olPSDs[q].data(),
3448 m_olPSDs[0].size() * sizeof( float ) );
3449
3450 // m_noisePSDStream->array.F[q] = m_nPSDs[q][0];
3451 memcpy( m_noisePSDStream->array.F + q * m_nPSDs[0].size(),
3452 m_nPSDs[q].data(),
3453 m_nPSDs[0].size() * sizeof( float ) );
3454 }
3455
3456 memcpy( m_clXferCurrentStream->array.F,
3457 m_clXferCurrent.data(),
3458 m_clXferCurrent.rows() * m_clXferCurrent.cols() * sizeof( float ) );
3459 memcpy(
3460 m_clXferSIStream->array.F, m_clXferSI.data(), m_clXferSI.rows() * m_clXferSI.cols() * sizeof( float ) );
3461 memcpy(
3462 m_clXferLPStream->array.F, m_clXferLP.data(), m_clXferLP.rows() * m_clXferLP.cols() * sizeof( float ) );
3463
3469 }
3470 else
3471 {
3472 /* Check for why we timed out */
3473 /* ETIMEDOUT just means keep waiting */
3474 if( errno == ETIMEDOUT )
3475 {
3476 // Could Update gopts if needed (requires size checks and requires mutex lock)
3477 // Probably not worth it for pred. control anyway.
3478 continue;
3479 }
3480
3481 /* EINTER probably indicates time to shutdown, loop wil exit if m_shutdown is set */
3482 if( errno == EINTR )
3483 {
3484 continue;
3485 }
3486
3487 /*Otherwise, report an error.*/
3488 log<software_error>( { __FILE__, __LINE__, errno, "sem_timedwait" } );
3489 break;
3490 }
3491 }
3492}
3493
3494INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_autoUpdate )( const pcf::IndiProperty &ipRecv )
3495{
3496 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_autoUpdate, ipRecv );
3497
3498 if( ipRecv.find( "toggle" ) )
3499 {
3500 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On )
3501 {
3502 if( !m_autoUpdate )
3503 {
3504 log<text_log>( "updating gains", logPrio::LOG_NOTICE );
3505 }
3506 m_autoUpdate = true;
3507 }
3508 else
3509 {
3510 if( m_autoUpdate )
3511 {
3512 log<text_log>( "stopped updating gains", logPrio::LOG_NOTICE );
3513 }
3514 m_autoUpdate = false;
3515 }
3516 }
3517
3518 return 0;
3519}
3520
3521INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_updateOnce )( const pcf::IndiProperty &ipRecv )
3522{
3523 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_updateOnce, ipRecv );
3524
3525 if( ipRecv.find( "request" ) )
3526 {
3527 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On )
3528 {
3529 m_updateOnce = true;
3530 }
3531 else
3532 {
3533 m_updateOnce = false;
3534 }
3535 }
3536
3537 return 0;
3538}
3539
3540INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_dump )( const pcf::IndiProperty &ipRecv )
3541{
3542 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_dump, ipRecv );
3543
3544 if( ipRecv.find( "request" ) )
3545 {
3546 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On )
3547 {
3548 m_dump = true;
3549 }
3550 else
3551 {
3552 m_dump = false;
3553 }
3554 }
3555
3556 return 0;
3557}
3558
3559INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_opticalGain )( const pcf::IndiProperty &ipRecv )
3560{
3561 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_opticalGain, ipRecv );
3562
3563 float target;
3564 if( indiTargetUpdate( m_indiP_opticalGain, target, ipRecv, true ) < 0 )
3565 {
3566 log<software_error>( { __FILE__, __LINE__ } );
3567 return -1;
3568 }
3569
3570 m_opticalGain = target;
3571
3572 return 0;
3573}
3574
3575INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_opticalGainUpdate )( const pcf::IndiProperty &ipRecv )
3576{
3577 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_opticalGainUpdate, ipRecv );
3578
3579 if(ipRecv.find("toggle"))
3580 {
3581 if(ipRecv["toggle"].getSwitchState() == pcf::IndiElement::Off)
3582 {
3583 m_opticalGainUpdate = false;
3584 }
3585 else
3586 {
3587 m_opticalGainUpdate = true;
3588
3589 if(m_opticalGainSource > 0 && m_opticalGainSource < 1)
3590 {
3591 m_opticalGain = m_opticalGainSource;
3592 }
3593 }
3594 }
3595
3596 return 0;
3597}
3598
3599INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_opticalGainSource )( const pcf::IndiProperty &ipRecv )
3600{
3601 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_opticalGainSource, ipRecv );
3602
3603 if( ipRecv.find( m_opticalGainElement ) )
3604 {
3605 float opticalg = ipRecv[m_opticalGainElement].get<float>();
3606
3607 opticalg = (floor(opticalg * 100 + 0.5))/100.;
3608
3609 if(opticalg > 0 && opticalg < 1)
3610 {
3611 m_opticalGainSource = opticalg;
3612 }
3613
3614 if(m_opticalGainUpdate)
3615 {
3616 m_opticalGain = m_opticalGainSource;
3617 }
3618 }
3619 return 0;
3620}
3621
3622INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_gainGain )( const pcf::IndiProperty &ipRecv )
3623{
3624 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_gainGain, ipRecv );
3625
3626 float target;
3627 if( indiTargetUpdate( m_indiP_gainGain, target, ipRecv, true ) < 0 )
3628 {
3629 log<software_error>( { __FILE__, __LINE__ } );
3630 return -1;
3631 }
3632
3633 m_gainGain = target;
3634
3635 return 0;
3636}
3637
3638INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_emg )( const pcf::IndiProperty &ipRecv )
3639{
3640 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_emg, ipRecv );
3641
3642 if( ipRecv.find( "current" ) )
3643 {
3644 float emg = ipRecv["current"].get<float>();
3645
3646 if( emg != m_emg )
3647 {
3648 m_emg = emg;
3649 std::cerr << "Got EMG: " << m_emg << '\n';
3650 }
3651 }
3652 return 0;
3653}
3654
3655INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_psdTime )( const pcf::IndiProperty &ipRecv )
3656{
3657 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_psdTime, ipRecv );
3658
3659 if( ipRecv.find( "current" ) )
3660 {
3661 float psdTime = ipRecv["current"].get<float>();
3662
3663 if( psdTime != m_psdTime )
3664 {
3665 m_updating = true;
3666 std::lock_guard<std::mutex> lock( m_goptMutex );
3667 m_updating = true;
3668
3669 m_psdTime = psdTime;
3670
3671 m_sinceChange = -1;
3672 m_updating = false;
3673
3674 std::cerr << "Got psdTime: " << m_psdTime << '\n';
3675 }
3676 }
3677 return 0;
3678}
3679
3680INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_psdAvgTime )( const pcf::IndiProperty &ipRecv )
3681{
3682 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_psdAvgTime, ipRecv );
3683
3684 if( ipRecv.find( "current" ) )
3685 {
3686 float psdAvgTime = ipRecv["current"].get<float>();
3687
3688 if( psdAvgTime != m_psdAvgTime )
3689 {
3690 m_updating = true;
3691 std::lock_guard<std::mutex> lock( m_goptMutex );
3692 m_updating = true;
3693
3694 m_psdAvgTime = psdAvgTime;
3695
3696 m_sinceChange = -1;
3697 m_updating = false;
3698
3699 std::cerr << "Got psdAvgTime: " << m_psdAvgTime << '\n';
3700 }
3701 }
3702
3703 return 0;
3704}
3705
3706INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_loop )( const pcf::IndiProperty &ipRecv )
3707{
3708 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_loop, ipRecv );
3709
3710 if( ipRecv.find( "toggle" ) )
3711 {
3712 bool state;
3713
3714 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On )
3715 {
3716 state = true;
3717 }
3718 else
3719 {
3720 state = false;
3721 }
3722
3723 if( state != m_loop )
3724 {
3725 m_updating = true;
3726 std::lock_guard<std::mutex> lock( m_goptMutex );
3727 m_updating = true;
3728
3729 m_loop = state;
3730
3731 if( !m_loop )
3732 {
3733 m_autoUpdate = false;
3734 m_dump = false;
3735 }
3736
3737 m_sinceChange = -1;
3738 m_updating = false;
3739 std::cerr << "Got loop: " << m_loop << '\n';
3740 }
3741 }
3742
3743 return 0;
3744}
3745
3746INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_siGain )( const pcf::IndiProperty &ipRecv )
3747{
3748 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_siGain, ipRecv );
3749
3750 if( ipRecv.find( "current" ) )
3751 {
3752 float gain = ipRecv["current"].get<float>();
3753
3754 if( gain != m_gain && !m_pcOn )
3755 {
3756 m_updating = true;
3757 std::lock_guard<std::mutex> lock( m_goptMutex );
3758 m_updating = true;
3759
3760 m_gain = gain;
3761
3762 if( m_loop )
3763 {
3764 m_sinceChange = -1;
3765 }
3766
3767 m_updating = false;
3768
3769 std::cerr << "Got gain: " << m_gain << '\n';
3770 }
3771 else
3772 {
3773 m_gain = gain; // for the m_pcOn case
3774 }
3775 }
3776
3777 return 0;
3778}
3779
3780INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_siMult )( const pcf::IndiProperty &ipRecv )
3781{
3782 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_siMult, ipRecv );
3783
3784 if( ipRecv.find( "current" ) )
3785 {
3786 float mc = ipRecv["current"].get<float>();
3787
3788 if( mc != m_mult && !m_pcOn )
3789 {
3790 m_updating = true;
3791 std::lock_guard<std::mutex> lock( m_goptMutex );
3792 m_updating = true;
3793
3794 m_mult = mc;
3795
3796 if( m_loop )
3797 {
3798 m_sinceChange = -1;
3799 }
3800
3801 m_goptUpdated = true;
3802 m_updating = false;
3803 std::cerr << "Got mc: " << m_mult << '\n';
3804 }
3805 else
3806 {
3807 m_mult = mc; // for the m_pcOn case
3808 }
3809 }
3810
3811 return 0;
3812}
3813
3814INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_pcGain )( const pcf::IndiProperty &ipRecv )
3815{
3816 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_pcGain, ipRecv );
3817
3818 if( ipRecv.find( "current" ) )
3819 {
3820 float gain = ipRecv["current"].get<float>();
3821
3822 if( gain != m_pcGain && m_pcOn )
3823 {
3824 m_updating = true;
3825 std::lock_guard<std::mutex> lock( m_goptMutex );
3826 m_updating = true;
3827
3828 m_pcGain = gain;
3829
3830 if( m_loop )
3831 {
3832 m_sinceChange = -1;
3833 }
3834
3835 m_updating = false;
3836
3837 std::cerr << "Got pc gain: " << m_pcGain << '\n';
3838 }
3839 else
3840 {
3841 m_pcGain = gain; // for the !m_pcOn case
3842 }
3843 }
3844
3845 return 0;
3846}
3847
3848INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_pcMult )( const pcf::IndiProperty &ipRecv )
3849{
3850 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_pcMult, ipRecv );
3851
3852 if( ipRecv.find( "current" ) )
3853 {
3854 float mc = ipRecv["current"].get<float>();
3855
3856 if( mc != m_pcMult && m_pcOn )
3857 {
3858 m_updating = true;
3859 std::lock_guard<std::mutex> lock( m_goptMutex );
3860 m_updating = true;
3861
3862 m_pcMult = mc;
3863
3864 if( m_loop )
3865 {
3866 m_sinceChange = -1;
3867 }
3868
3869 m_pcgoptUpdated = true;
3870 m_updating = false;
3871 std::cerr << "Got pc mc: " << m_pcMult << '\n';
3872 }
3873 else
3874 {
3875 m_pcMult = mc; // for the !m_pcOn case
3876 }
3877 }
3878
3879 return 0;
3880}
3881
3882INDI_SETCALLBACK_DEFN( modalGainOpt, m_indiP_pcOn )( const pcf::IndiProperty &ipRecv )
3883{
3884 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_pcOn, ipRecv );
3885
3886 if( ipRecv.find( "toggle" ) )
3887 {
3888 bool state;
3889
3890 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On )
3891 {
3892 state = true;
3893 }
3894 else
3895 {
3896 state = false;
3897 }
3898
3899 if( state != m_pcOn )
3900 {
3901 m_updating = true;
3902 std::lock_guard<std::mutex> lock( m_goptMutex );
3903 m_updating = true;
3904
3905 m_pcOn = state;
3906
3907 m_sinceChange = -1;
3908 m_updating = false;
3909 std::cerr << "Got pcOn: " << std::boolalpha << m_pcOn << '\n';
3910 }
3911 }
3912
3913 return 0;
3914}
3915
3916INDI_NEWCALLBACK_DEFN( modalGainOpt, m_indiP_extrapOL )( const pcf::IndiProperty &ipRecv )
3917{
3918 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_extrapOL, ipRecv );
3919
3920 if( ipRecv.find( "toggle" ) )
3921 {
3922 int ext;
3923
3924 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On )
3925 {
3926 ext = true;
3927 }
3928 else
3929 {
3930 ext = false;
3931 }
3932
3933 if( ext != m_extrapOL )
3934 {
3935 m_updating = true;
3936 std::lock_guard<std::mutex> lock( m_goptMutex );
3937 m_updating = true;
3938
3939 m_extrapOL = ext;
3940
3941 m_sinceChange = -1;
3942 m_updating = false;
3943 std::cerr << "Got extrap: " << m_extrapOL << '\n';
3944 }
3945 }
3946
3947 return 0;
3948}
3949} // namespace app
3950} // namespace MagAOX
3951
3952#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 MagAO-X applications.
Definition MagAOXApp.hpp:73
stateCodes::stateCodeT state()
Get the current state code.
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.
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.
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.
pcf::IndiProperty m_indiP_emg
std::vector< mx::AO::analysis::clGainOpt< float > > m_goptCurrent
Each mode gets its own gain optimizer.
eigenImage< float > m_wfsavg
pcf::IndiProperty m_indiP_gainGain
bool m_opticalGainUpdate
Flag controlling whether optical gain is automatically updated;.
std::vector< uint32_t > m_NbCurrent
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_updateOnce)
dev::shmimMonitor< modalGainOpt, numpccoeffShmimT > numpccoeffShmimMonitorT
mx::improc::eigenImage< float > m_clXferCurrent
~modalGainOpt() noexcept
D'tor, declared and defined for noexcept.
std::vector< float > m_modeVarCL
IMAGE * m_clXferLPStream
The ImageStreamIO shared memory buffer to publish the LP ETF.
dev::shmimMonitor< modalGainOpt, wfsmaskShmimT > wfsmaskShmimMonitorT
std::vector< int > m_regCounter
Counters to track when this mode was last regularized.
std::vector< float > m_gmaxLP
The previously calculated maximum gains for LP.
std::vector< float > m_pcGainFacts
std::vector< mx::AO::analysis::clGainOpt< float > > m_goptLP
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)
dev::shmimMonitor< modalGainOpt, pcMultFactShmimT > pcMultFactShmimMonitorT
std::vector< float > m_taus
dev::shmimMonitor< modalGainOpt, gainCalShmimT > gainCalShmimMonitorT
int allocate(const psdShmimT &)
std::vector< int > m_timesOnLP
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_dump)
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_autoUpdate
int m_loopNum
The number of the loop. Used to set shmim names, as in aolN_mgainfact.
std::vector< float > m_gainCalFacts
pcf::IndiProperty m_indiP_dump
std::vector< float > m_gainFacts
dev::shmimMonitor< modalGainOpt, bcoeffShmimT > bcoeffShmimMonitorT
int checkSizes()
Check that all sizes and allocations have occurred.
int m_goptThreadPrio
Priority of the gain optimization thread.
pcf::IndiProperty m_indiP_opticalGainUpdate
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_pcOn)
std::vector< float > m_optGainLP
sem_t m_goptSemaphore
Semaphore used to synchronize the psdShmim thread and the gopt thread.
IMAGE * m_optGainLPStream
The ImageStreamIO shared memory buffer to publish the LP optimal gains.
std::string m_goptThreadCpuset
The cpuset to use for the gain optimization thread.
pcf::IndiProperty m_indiP_loop
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_siGain)
mx::improc::eigenImage< float > m_clPSDs
dev::shmimMonitor< modalGainOpt, wfsavgShmimT > wfsavgShmimMonitorT
std::vector< float > m_gmaxSI
The previously calculated maximum gains for LP.
pcf::IndiProperty m_indiP_siMult
pcf::IndiProperty m_indiP_pcOn
IMAGE * m_olPSDStream
The ImageStreamIO shared memory buffer to publish the open loop PSDs.
IMAGE * m_clXferSIStream
The ImageStreamIO shared memory buffer to publish the SI ETF.
std::vector< std::vector< float > > m_olPSDs
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_loop)
eigenImage< float > m_wfsmask
pcf::IndiProperty m_indiP_modesOn
bool m_goptUpdated
Tracks if a parameter has updated requiring updates to the m_gopt entries.
mx::improc::eigenImage< float > m_clXferLP
dev::shmimMonitor< modalGainOpt, freqShmimT > freqShmimMonitorT
std::string m_loopName
The name of the loop control INDI device name.
std::chrono::duration< double > durationT
dev::shmimMonitor< modalGainOpt, gainFactShmimT > gainFactShmimMonitorT
IMAGE * m_maxGainLPStream
The ImageStreamIO shared memory buffer to publish the LP max gains.
bool m_updateOnce
Flag to trigger a single update with gain.
pcf::IndiProperty m_indiP_updateOnce
dev::shmimMonitor< modalGainOpt, tauShmimT > tauShmimMonitorT
eigenImage< float > m_noiseParams
std::vector< mx::AO::analysis::clAOLinearPredictor< float > > m_linPred
pcf::IndiProperty m_goptThreadProp
The property to hold the gain optimization thread details.
static void goptThreadStart(modalGainOpt *p)
Gain Optimization thread starter function.
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_psdAvgTime)
eigenImage< float > m_bs
bool m_dump
Flag to trigger a single update with no gain.
mx::improc::eigenImage< float > m_clXferSI
pcf::IndiProperty m_indiP_psdAvgTime
std::vector< float > m_modeVarLP
IMAGE * m_optGainStream
The ImageStreamIO shared memory buffer to publish the optimal gains.
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_opticalGainSource)
std::vector< float > m_optGainSI
IMAGE * m_optGainSIStream
The ImageStreamIO shared memory buffer to publish the SI optimal gains.
IMAGE * m_clXferCurrentStream
The ImageStreamIO shared memory buffer to publish the SI ETF.
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapOL)
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_psdTime)
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
std::vector< float > m_gainCals
virtual int appStartup()
Startup function.
std::thread m_goptThread
The gain optimization thread.
void goptThreadExec()
Gain optimization thread function.
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_opticalGain)
pcf::IndiProperty m_indiP_opticalGain
dev::shmimMonitor< modalGainOpt, psdShmimT > psdShmimMonitorT
bool m_updating
Flag used to indicate to the goptThread that it should stop calculations ASAP.
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
std::vector< float > m_pcMultFacts
std::mutex m_goptMutex
Mutex for synchronizing updates.
dev::shmimMonitor< modalGainOpt, multFactShmimT > multFactShmimMonitorT
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_siMult)
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_emg)
bool m_autoUpdate
Flag controlling whether gains are automatically updated.
dev::shmimMonitor< modalGainOpt, gainCalFactShmimT > gainCalFactShmimMonitorT
std::vector< uint32_t > m_NaCurrent
std::vector< int > m_timesOnSI
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_pcMult)
IMAGE * m_modevarStream
The ImageStreamIO shared memory buffer to publish the LP optimal gains.
int m_extrapOL
Which extrapolation method to use for the OL PSD. 0 is none. The only other option is 1.
std::vector< float > m_multFacts
dev::shmimMonitor< modalGainOpt, acoeffShmimT > acoeffShmimMonitorT
std::vector< float > m_regScale
The regularization scale factors for each mode.
bool m_pcgoptUpdated
Tracks if a parameter has updated requiring updates to the m_gopt entries.
pcf::IndiProperty m_indiP_opticalGainSource
std::vector< uint32_t > m_Nb
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_opticalGainUpdate)
std::vector< std::vector< float > > m_nPSDs
IMAGE * m_maxGainSIStream
The ImageStreamIO shared memory buffer to publish the SI max gains.
float m_gainGain
The gain to use for closed-loop gain updates. Default is 0.1.
pcf::IndiProperty m_indiP_pcGain
std::vector< mx::AO::analysis::clGainOpt< float > > m_goptSI
dev::shmimMonitor< modalGainOpt, noiseShmimT > noiseShmimMonitorT
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_pcGain)
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_gainGain)
std::vector< uint32_t > m_Na
pcf::IndiProperty m_indiP_extrapOL
pcf::IndiProperty m_indiP_psdTime
int m_nRegCycles
How often to regularize each mode.
pcf::IndiProperty m_indiP_pcMult
#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 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.
@ OPERATING
The device is operating, other than homing.
#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
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
const pcf::IndiProperty & ipRecv
std::unique_lock< std::mutex > lock(m_indiMutex)
Definition dm.hpp:26
static constexpr logPrioT LOG_NOTICE
A normal but significant condition.
#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()
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()
static std::string indiPrefix()
static std::string configSection()
static std::string configSection()
static std::string indiPrefix()
static std::string indiPrefix()
static std::string configSection()
Software CRITICAL log entry.
Software ERR log entry.