API
 
Loading...
Searching...
No Matches
modalFilter.hpp
Go to the documentation of this file.
1/** \file modalFilter.hpp
2 * \brief The MagAO-X modal filter header file
3 *
4 * \ingroup modalFilter_files
5 */
6
7#ifndef modalFilter_hpp
8#define modalFilter_hpp
9
10#include <mutex>
11#include <shared_mutex>
12
13#include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
14#include "../../magaox_git_version.h"
15
16#include <mx/sigproc/circularBuffer.hpp>
17
18/** \defgroup modalFilter
19 * \brief The MagAO-X application to perform modal filtering
20 *
21 * <a href="../handbook/operating/software/apps/modalFilter.html">Application Documentation</a>
22 *
23 * \ingroup apps
24 *
25 */
26
27/** \defgroup modalFilter_files
28 * \ingroup modalFilter
29 */
30
31namespace MagAOX
32{
33namespace app
34{
35
37{
38 static std::string configSection()
39 {
40 return "gainFactShmim";
41 };
42
43 static std::string indiPrefix()
44 {
45 return "gainFact";
46 };
47};
48
50{
51 static std::string configSection()
52 {
53 return "multFactShmim";
54 };
55
56 static std::string indiPrefix()
57 {
58 return "multFact";
59 };
60};
61
63{
64 static std::string configSection()
65 {
66 return "pcGainFactShmim";
67 };
68
69 static std::string indiPrefix()
70 {
71 return "pcGainFact";
72 };
73};
74
76{
77 static std::string configSection()
78 {
79 return "pcMultFactShmim";
80 };
81
82 static std::string indiPrefix()
83 {
84 return "pcMultFact";
85 };
86};
87
89{
90 static std::string configSection()
91 {
92 return "acoeffShmim";
93 };
94
95 static std::string indiPrefix()
96 {
97 return "acoeff";
98 };
99};
100
102{
103 static std::string configSection()
104 {
105 return "bcoeffShmim";
106 };
107
108 static std::string indiPrefix()
109 {
110 return "bcoeff";
111 };
112};
113
115{
116 static std::string configSection()
117 {
118 return "modevalShmim";
119 };
120
121 static std::string indiPrefix()
122 {
123 return "modeval";
124 };
125};
126
127/// The MagAO-X modal filter
128/**
129 * \ingroup modalFilter
130 */
131class modalFilter : public MagAOXApp<true>,
132 dev::shmimMonitor<modalFilter, gainFactShmimT>,
133 dev::shmimMonitor<modalFilter, multFactShmimT>,
134 dev::shmimMonitor<modalFilter, pcGainFactShmimT>,
135 dev::shmimMonitor<modalFilter, pcMultFactShmimT>,
136 dev::shmimMonitor<modalFilter, acoeffShmimT>,
137 dev::shmimMonitor<modalFilter, bcoeffShmimT>,
138 dev::shmimMonitor<modalFilter, modevalShmimT>,
139 dev::frameGrabber<modalFilter>,
140 dev::telemeter<modalFilter>
141{
142
143 // Give the test harness access.
144 friend class modalFilter_test;
145
153 friend class dev::frameGrabber<modalFilter>;
154 friend class dev::telemeter<modalFilter>;
155
165
166 static constexpr bool c_frameGrabber_flippable = false; /**< app:dev config to tell framegrabber these images
167 can not be flipped*/
168
169 protected:
170 /** \name Configurable Parameters
171 *@{
172 */
173
174 std::string m_fpsDevice; ///< Device name for getting fps to set circular buffer length.
175 std::string m_fpsProperty{ "fps" }; ///< Property name for getting fps to set circular buffer length.
176 std::string m_fpsElement{ "current" }; ///< Element name for getting fps to set circular buffer length.
177
178 float m_fpsTol{ 0 }; ///< The tolerance for detecting a change in FPS.
179
180 int m_loopNum{ 1 }; ///< The number of the loop. Used to set shmim names, as in aolN_mgainfact. Default is 1.
181
182 std::string m_loopName{ "ho" }; ///< The name of the loop control INDI device name. Defalt is "ho".
183
184 int32_t m_modevalCBLength{ 1000 }; ///< The length of the modeval circular buffers. Default is 1000 entries.
185
186 ///@}
187
188 float m_fps{ 0 };
189
190 bool m_loop{ false };
191
192 float m_gain{ 0 };
193
194 float m_mc{ 1 };
195
196 bool m_pcOn{ false };
197
198 float m_pcGain{ 0 };
199
200 float m_pcMc{ 1 };
201
202 std::vector<float> m_gainfacts;
203
204 std::vector<float> m_multfacts;
205
206 std::vector<float> m_pcGainfacts;
207
208 std::vector<float> m_pcMultfacts;
209
210 std::vector<int> m_Na;
211
212 std::vector<int> m_Nb;
213
215
217
219
220 mx::sigproc::circularBufferIndex<std::vector<float>, int32_t> m_modevalWFS;
221
222 mx::sigproc::circularBufferIndex<std::vector<float>, int32_t> m_modevalDM;
223
224 sem_t m_filtSem; ///< Semaphore used to signal that fresh modevals are waiting to be filtered
225
226 bool m_sizesMatch{ false }; ///< Flag indicating that all sizes are consistent
227
228 bool m_pcSizesMatch{ false }; ///< Flag indicating that all sizes are consistent
229
230 std::shared_mutex m_filtMutex; ///< Mutex for locking access to filter parameters
231
232 timespec m_atime; ///< The acq time of the WFS modevals
233 public:
234 /// Default c'tor.
235 modalFilter();
236
237 /// D'tor, declared and defined for noexcept.
239 {
240 }
241
242 virtual void setupConfig();
243
244 /// Implementation of loadConfig logic, separated for testing.
245 /** This is called by loadConfig().
246 */
247 int loadConfigImpl( mx::app::appConfigurator &_config /**< [in] an application configuration
248 from which to load values*/ );
249
250 virtual void loadConfig();
251
252 /// Startup function
253 /**
254 *
255 */
256 virtual int appStartup();
257
258 /// Implementation of the FSM for modalFilter.
259 /**
260 * \returns 0 on no critical error
261 * \returns -1 on an error requiring shutdown
262 */
263 virtual int appLogic();
264
265 /// Shutdown the app.
266 /**
267 *
268 */
269 virtual int appShutdown();
270
271 int allocate( const gainFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
272 );
273
274 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
275 const gainFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
276 );
277
278 int allocate( const multFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
279 );
280
281 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
282 const multFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
283 );
284
285 int allocate( const pcGainFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
286 );
287
288 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
289 const pcGainFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
290 );
291
292 int allocate( const pcMultFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
293 );
294
295 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
296 const pcMultFactShmimT & ///< [in] tag to differentiate shmimMonitor parents.
297 );
298
299 int allocate( const acoeffShmimT & ///< [in] tag to differentiate shmimMonitor parents.
300 );
301
302 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
303 const acoeffShmimT & ///< [in] tag to differentiate shmimMonitor parents.
304 );
305
306 int allocate( const bcoeffShmimT & ///< [in] tag to differentiate shmimMonitor parents.
307 );
308
309 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
310 const bcoeffShmimT & ///< [in] tag to differentiate shmimMonitor parents.
311 );
312
313 int allocate( const modevalShmimT & ///< [in] tag to differentiate shmimMonitor parents.
314 );
315
316 int processImage( void *curr_src, ///< [in] pointer to the start of the current frame
317 const modevalShmimT & ///< [in] tag to differentiate shmimMonitor parents.
318 );
319
320 /** \name frameGrabber interface
321 * @{
322 */
323
324 /// Implementation of the framegrabber configureAcquisition interface
325 /**
326 *
327 * \returns 0 on success
328 * \returns -1 on error
329 */
331
332 /// Implementation of the frameGrabber fps interface
333 /** Just returns the value of m_fps
334 */
335 float fps();
336
337 /// Implementation of the framegrabber startAcquisition interface
338 /**
339 *
340 * \returns 0 on success
341 * \returns -1 on error
342 */
343 int startAcquisition();
344
345 /// Implementation of the framegrabber acquireAndCheckValid interface
346 /**
347 *
348 * \returns 0 on success
349 * \returns -1 on error
350 */
352
353 /// Implementation of the framegrabber loadImageIntoStream interface
354 /**
355 *
356 * \returns 0 on success
357 * \returns -1 on error
358 */
359 int loadImageIntoStream( void *dest /**< [in] */ );
360
361 /// Implementation of the framegrabber reconfig interface
362 /**
363 * \returns 0 on success
364 * \returns -1 on error
365 */
366 int reconfig();
367
368 ///@}
369
370 void checkSizes();
371
372 /** \name Telemeter Interface
373 *
374 * @{
375 */
376 int checkRecordTimes();
377
378 int recordTelem( const telem_fgtimings * );
379
380 ///@}
381
382 /** \name INDI
383 * @{
384 */
385
386 pcf::IndiProperty m_indiP_fpsSource;
387
388 pcf::IndiProperty m_indiP_loop;
389
390 pcf::IndiProperty m_indiP_gain;
391
392 pcf::IndiProperty m_indiP_mult;
393
394 pcf::IndiProperty m_indiP_pcGain;
395
396 pcf::IndiProperty m_indiP_pcMult;
397
398 pcf::IndiProperty m_indiP_pcOn;
399
401
403
405
407
409
411
413
414 ///@}
415};
416
429
431{
432 config.add( "circBuff.fpsDevice",
433 "",
434 "circBuff.fpsDevice",
435 argType::Required,
436 "circBuff",
437 "fpsDevice",
438 false,
439 "string",
440 "Device name for getting fps to set circular buffer length." );
441 config.add( "circBuff.fpsProperty",
442 "",
443 "circBuff.fpsProperty",
444 argType::Required,
445 "circBuff",
446 "fpsProperty",
447 false,
448 "string",
449 "Property name for getting fps to set circular buffer length. Default is 'fps'." );
450 config.add( "circBuff.fpsElement",
451 "",
452 "circBuff.fpsElement",
453 argType::Required,
454 "circBuff",
455 "fpsElement",
456 false,
457 "string",
458 "Property name for getting fps to set circular buffer length. Default is 'current'." );
459 config.add( "circBuff.fpsTol",
460 "",
461 "circBuff.fpsTol",
462 argType::Required,
463 "circBuff",
464 "fpsTol",
465 false,
466 "float",
467 "Tolerance for detecting a change in FPS. Default is 0." );
468
469 config.add( "loop.number",
470 "",
471 "loop.number",
472 argType::Required,
473 "loop",
474 "number",
475 false,
476 "int",
477 "The number of the loop. Used to set shmim names, as in aolN_mgainfact. Default is 1." );
478
479 config.add( "loop.name",
480 "",
481 "loop.name",
482 argType::Required,
483 "loop",
484 "name",
485 false,
486 "string",
487 "The name of the loop control INDI device name. Default is \"ho\"." );
488
497 TELEMETER_SETUP_CONFIG( config );
498}
499
500int modalFilter::loadConfigImpl( mx::app::appConfigurator &_config )
501{
502 _config( m_fpsDevice, "circBuff.fpsDevice" );
503 _config( m_fpsProperty, "circBuff.fpsProperty" );
504 _config( m_fpsElement, "circBuff.fpsElement" );
505 _config( m_fpsTol, "circBuff.fpsTol" );
506
507 _config( m_loopNum, "loop.number" );
508 _config( m_loopName, "loop.name" );
509
510 char shmim[1024];
511
512 snprintf( shmim, sizeof( shmim ), "aol%d_mgainfact", m_loopNum );
515
516 snprintf( shmim, sizeof( shmim ), "aol%d_mmultfact", m_loopNum );
519
520 snprintf( shmim, sizeof( shmim ), "aol%d_mpcgainfact", m_loopNum );
523
524 snprintf( shmim, sizeof( shmim ), "aol%d_mpcmultfact", m_loopNum );
527
528 snprintf( shmim, sizeof( shmim ), "aol%d_acoeff", m_loopNum );
531
532 snprintf( shmim, sizeof( shmim ), "aol%d_bcoeff", m_loopNum );
535
536 snprintf( shmim, sizeof( shmim ), "aol%d_modevalWFS", m_loopNum );
539
540 snprintf( shmim, sizeof( shmim ), "aol%d_modevalDM", m_loopNum );
543
545
546 return 0;
547}
548
550{
551 loadConfigImpl( config );
552}
553
555{
556
557 if( sem_init( &m_filtSem, 0, 0 ) < 0 )
558 {
559 return log<software_critical, -1>( { __FILE__, __LINE__, errno, 0, "Initializing filter semaphore" } );
560 }
561
571
572 if( m_fpsDevice == "" )
573 {
574 return log<software_critical, -1>(
575 { __FILE__, __LINE__, "FPS source is not configurated (circBuff.fpsDevice)" } );
576 }
577
579
581 CREATE_REG_INDI_NEW_NUMBERF( m_indiP_gain, "loop_gain", 0, 1, 0.01, "%0.01f", "Gain", "Loop" );
582 CREATE_REG_INDI_NEW_NUMBERF( m_indiP_mult, "loop_multcoeff", 0, 1, 0.01, "%0.01f", "Mult. Coeff.", "Loop" );
583 CREATE_REG_INDI_NEW_NUMBERF( m_indiP_pcGain, "loop_pcgain", 0, 1, 0.01, "%0.01f", "PC Gain", "Loop" );
584 CREATE_REG_INDI_NEW_NUMBERF( m_indiP_pcMult, "loop_pcmultcoeff", 0, 1, 0.01, "%0.01f", "PC Mult. Coeff.", "Loop" );
585
587
589
590 return 0;
591}
592
594{
604
613
614 if( m_loop )
615 {
616 updateSwitchIfChanged( m_indiP_loop, "toggle", pcf::IndiElement::On, INDI_OK );
617 }
618 else
619 {
620 updateSwitchIfChanged( m_indiP_loop, "toggle", pcf::IndiElement::Off, INDI_IDLE );
621 }
622
623 if( m_pcOn )
624 {
625 updateSwitchIfChanged( m_indiP_pcOn, "toggle", pcf::IndiElement::On, INDI_OK );
626 }
627 else
628 {
629 updateSwitchIfChanged( m_indiP_pcOn, "toggle", pcf::IndiElement::Off, INDI_IDLE );
630 }
631
632 updatesIfChanged<float>( m_indiP_gain, { "current", "target" }, { m_gain, m_gain } );
633 updatesIfChanged<float>( m_indiP_mult, { "current", "target" }, { m_mc, m_mc } );
634
635 updatesIfChanged<float>( m_indiP_pcGain, { "current", "target" }, { m_pcGain, m_pcGain } );
636 updatesIfChanged<float>( m_indiP_pcMult, { "current", "target" }, { m_pcMc, m_pcMc } );
637
638 return 0;
639}
640
655
657{
658 static_cast<void>( dummy );
659
661 {
662 return log<software_error, -1>( { __FILE__, __LINE__, "got gainFacts with height not 1" } );
663 }
664
665 // If there's a size change we have to lock
667 {
668 std::shared_lock<std::shared_mutex> lock( m_filtMutex );
669
671
672 checkSizes();
673 }
674
675 return 0;
676}
677
678int modalFilter::processImage( void *curr_src, const gainFactShmimT &dummy )
679{
680 static_cast<void>( dummy );
681
682 // We just update without a lock. Size change handled in allocate.
684 {
685 m_gainfacts[n] = reinterpret_cast<float *>( curr_src )[n];
686 }
687
688 return 0;
689}
690
692{
693 static_cast<void>( dummy );
694
696 {
697 return log<software_error, -1>( { __FILE__, __LINE__, "got multFacts with height not 1" } );
698 }
699
700 // If there's a size change we have to lock
702 {
703 std::shared_lock<std::shared_mutex> lock( m_filtMutex );
704
706
707 checkSizes();
708 }
709
710 return 0;
711}
712
713int modalFilter::processImage( void *curr_src, const multFactShmimT &dummy )
714{
715 static_cast<void>( dummy );
716
717 // We just update without a lock. Size change handled in allocate.
719 {
720 m_multfacts[n] = reinterpret_cast<float *>( curr_src )[n];
721 }
722
723 return 0;
724}
725
727{
728 static_cast<void>( dummy );
729
731 {
732 return log<software_error, -1>( { __FILE__, __LINE__, "got pcGainFacts with height not 1" } );
733 }
734
735 // If there's a size change we have to lock
737 {
738 std::shared_lock<std::shared_mutex> lock( m_filtMutex );
739
741
742 checkSizes();
743 }
744
745 return 0;
746}
747
748int modalFilter::processImage( void *curr_src, const pcGainFactShmimT &dummy )
749{
750 static_cast<void>( dummy );
751
752 // We just update without a lock. Size change handled in allocate.
754 {
755 m_pcGainfacts[n] = reinterpret_cast<float *>( curr_src )[n];
756 }
757
758 return 0;
759}
760
762{
763 static_cast<void>( dummy );
764
766 {
767 return log<software_error, -1>( { __FILE__, __LINE__, "got pcMultFacts with height not 1" } );
768 }
769
770 // If there's a size change we have to lock
772 {
773 std::shared_lock<std::shared_mutex> lock( m_filtMutex );
774
776
777 checkSizes();
778 }
779
780 return 0;
781}
782
783int modalFilter::processImage( void *curr_src, const pcMultFactShmimT &dummy )
784{
785 static_cast<void>( dummy );
786
787 // We just update without a lock. Size change handled in allocate.
789 {
790 m_pcMultfacts[n] = reinterpret_cast<float *>( curr_src )[n];
791 }
792
793 return 0;
794}
795
797{
798 static_cast<void>( dummy );
799
802
803 // If there's a size change we lock
804 if( w - 1 != m_as.rows() || h != m_as.cols() || h != m_Na.size() )
805 {
806 std::shared_lock<std::shared_mutex> lock( m_filtMutex );
807
808 m_Na.resize( h );
809 m_as.resize( w - 1, h );
810
811 checkSizes();
812 }
813
814 return 0;
815}
816
817int modalFilter::processImage( void *curr_src, const acoeffShmimT &dummy )
818{
819 static_cast<void>( dummy );
820
823
824 eigenMap<float> ac( reinterpret_cast<float *>( curr_src ), w, h );
825
826 for( uint32_t cc = 0; cc < h; ++cc )
827 {
828 m_Na[cc] = ac( 0, cc );
829 for( uint32_t rr = 1; rr < w; ++rr )
830 {
831 m_as( rr - 1, cc ) = ac( rr, cc );
832 }
833 }
834
835 std::cerr << "Got pc a-coeffs. Mode 0 has " << m_Na[0] << '\n';
836
837 return 0;
838}
839
841{
842 static_cast<void>( dummy );
843
846
847 // If there's a size change we lock
848 if( w - 1 != m_bs.rows() || h != m_bs.cols() || h != m_Nb.size() )
849 {
850 std::shared_lock<std::shared_mutex> lock( m_filtMutex );
851
852 m_Nb.resize( h );
853 m_bs.resize( w - 1, h );
854
855 checkSizes();
856 }
857
858 std::cerr << "Got pc b-coeffs. Mode 0 has " << m_Nb[0] << '\n';
859
860 return 0;
861}
862
863int modalFilter::processImage( void *curr_src, const bcoeffShmimT &dummy )
864{
865 static_cast<void>( dummy );
866
869
870 eigenMap<float> bc( reinterpret_cast<float *>( curr_src ), w, h );
871
872 for( uint32_t cc = 0; cc < h; ++cc )
873 {
874 m_Nb[cc] = bc( 0, cc );
875 for( uint32_t rr = 1; rr < w; ++rr )
876 {
877 m_bs( rr - 1, cc ) = bc( rr, cc );
878 }
879 }
880 return 0;
881}
882
884{
885 static_cast<void>( dummy );
886
888 {
889 return log<software_error, -1>( { __FILE__, __LINE__, "got modevals with height not 1" } );
890 }
891
892 if( modevalShmimMonitorT::m_width != m_modevalSz ) // This invalidates the whole c.b.
893 {
894 std::shared_lock<std::shared_mutex> lock( m_filtMutex );
895
897 m_modevalWFS.maxEntries( m_modevalCBLength );
898 m_modevalDM.maxEntries( m_modevalCBLength );
899
900 checkSizes();
901 }
902
903 std::cerr << "Allocated modevals: " << modevalShmimMonitorT::m_width << " x " << modevalShmimMonitorT::m_height
904 << '\n';
905 return 0;
906}
907
908int modalFilter::processImage( void *curr_src, const modevalShmimT &dummy )
909{
910 static_cast<void>( dummy );
911
913
914 float *F = reinterpret_cast<float *>( curr_src );
915
916 m_modevalWFS.nextEntry( std::vector<float>( F, F + m_modevalSz ) );
917
918 // Now tell the writer to get going
919 if( sem_post( &m_filtSem ) < 0 )
920 {
921 return log<software_critical, -1>( { __FILE__, __LINE__, errno, 0, "Error posting to filter semaphore" } );
922 }
923
924 return 0;
925}
926
941
943{
944 return m_fps;
945}
946
948{
949 return 0;
950}
951
953{
954 timespec ts;
955
956 XWC_SEM_WAIT_TS( ts, 1, 0 );
957
958 if( sem_timedwait( &m_filtSem, &ts ) != 0 )
959 {
960 /* Check for why we timed out */
961 /* EINTER probably indicates time to shutdown, loop will exit if m_shutdown is set */
962 /* ETIMEDOUT just means keep waiting */
963 if( errno == EINTR || errno == ETIMEDOUT )
964 {
965 return 1;
966 }
967
968 /*Otherwise, report an error.*/
969 return log<software_error, -1>( { __FILE__, __LINE__, errno, "sem_timedwait" } );
970 }
971 else
972 {
973 std::unique_lock<std::shared_mutex> lock( m_filtMutex ); // gotta be the only one
974
975 if( !m_sizesMatch )
976 {
977 return 1;
978 }
979
980 m_modevalDM.nextEntry(); // move to the next entry without modifying what is there
981 m_modevalDM[-1].resize( m_modevalSz ); // needed while growing, no-op once grown
982 if( !m_loop )
983 {
984 for( uint32_t mode = 0; mode < m_modevalSz; ++mode )
985 {
986 m_modevalDM[-1][mode] = 0;
987 }
988 return 1; // we update the cbuff but we don't push to the DM
989 }
990 else
991 {
992 if( !m_pcOn )
993 {
994 for( uint32_t mode = 0; mode < m_modevalSz; ++mode )
995 {
996 // index [0] is 1the latest entry in the circular buffer
997 m_modevalDM[-1][mode] = -1.0 * m_gain * m_gainfacts[mode] * m_modevalWFS[-1][mode] +
998 m_mc * m_multfacts[mode] * m_modevalDM[-2][mode];
999 }
1000 }
1001 else
1002 {
1003 for( uint32_t mode = 0; mode < m_modevalSz; ++mode )
1004 {
1005 float a = 0;
1006 float b = 0;
1007 for(int c = 0; c < m_Na[mode]; ++c)
1008 {
1009 a += m_as(c,mode)*m_modevalWFS[-1-c][mode];
1010 }
1011
1012 for(int c = 0; c < m_Nb[mode]; ++c)
1013 {
1014 b += m_bs(c,mode)*m_modevalDM[-2-c][mode];
1015 }
1016
1017 a = m_modevalWFS[-1][mode];
1018 b = m_modevalDM[-2][mode];
1019 m_modevalDM[-1][mode] = -1.0 * m_pcGain * m_pcGainfacts[mode] * a +
1020 m_pcMc * m_pcMultfacts[mode] * b;
1021 }
1022 }
1023
1025 }
1026 }
1027
1028 return 0;
1029}
1030
1032{
1033
1034 memcpy( dest, m_modevalDM[-1].data(), m_modevalDM[-1].size() * sizeof( float ) );
1035
1036 return 0;
1037}
1038
1040{
1041 return 0;
1042}
1043
1045{
1046 m_sizesMatch = true;
1047 m_pcSizesMatch = true;
1048
1049 if( m_gainfacts.size() != m_modevalSz )
1050 {
1051 m_sizesMatch = false;
1052 }
1053
1054 if( m_multfacts.size() != m_modevalSz )
1055 {
1056 m_sizesMatch = false;
1057 }
1058
1059 if( static_cast<size_t>( m_as.cols() ) != m_modevalSz )
1060 {
1061 m_pcSizesMatch = false;
1062 }
1063
1064 if( static_cast<size_t>( m_bs.cols() ) != m_modevalSz )
1065 {
1066 m_pcSizesMatch = false;
1067 }
1068
1069 if( m_modevalWFS.size() != m_modevalCBLength )
1070 {
1071 m_pcSizesMatch = false;
1072 }
1073
1074 if( m_modevalDM.size() != m_modevalCBLength )
1075 {
1076 m_pcSizesMatch = false;
1077 }
1078}
1079
1084
1086{
1087 return recordFGTimings( true );
1088}
1089
1090INDI_SETCALLBACK_DEFN( modalFilter, m_indiP_fpsSource )( const pcf::IndiProperty &ipRecv )
1091{
1092 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_fpsSource, ipRecv );
1093
1094 if( ipRecv.find( m_fpsElement ) != true ) // this isn't valid
1095 {
1096 log<software_error>( { __FILE__, __LINE__, "No current property in fps source." } );
1097 return 0;
1098 }
1099
1100 std::lock_guard<std::mutex> guard( m_indiMutex );
1101
1102 float fps = ipRecv[m_fpsElement].get<float>();
1103
1104 if( fabs( fps - m_fps ) > m_fpsTol )
1105 {
1106 m_fps = fps;
1107 log<text_log>( "set fps to " + std::to_string( m_fps ), logPrio::LOG_NOTICE );
1108 frameGrabberT::m_reconfig = true;
1109 }
1110
1111 return 0;
1112
1113} // INDI_SETCALLBACK_DEFN(modalFilter, m_indiP_fpsSource)
1114
1115INDI_NEWCALLBACK_DEFN( modalFilter, m_indiP_loop )( const pcf::IndiProperty &ipRecv )
1116{
1117 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_loop, ipRecv );
1118
1119 if( ipRecv.find( "toggle" ) )
1120 {
1121 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On )
1122 {
1123 if( !m_loop )
1124 {
1125 log<loop_closed>();
1126 }
1127 m_loop = true;
1128 }
1129 else
1130 {
1131 if( m_loop )
1132 {
1133 log<loop_open>();
1134 }
1135 m_loop = false;
1136 }
1137 }
1138
1139 return 0;
1140}
1141
1142INDI_NEWCALLBACK_DEFN( modalFilter, m_indiP_gain )( const pcf::IndiProperty &ipRecv )
1143{
1144 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_gain, ipRecv );
1145
1146 float target;
1147 if( indiTargetUpdate( m_indiP_gain, target, ipRecv, true ) < 0 )
1148 {
1149 log<software_error>( { __FILE__, __LINE__ } );
1150 return -1;
1151 }
1152
1153 m_gain = target;
1154
1155 std::cerr << "Got global gain: " << m_gain << '\n';
1156
1157 return 0;
1158}
1159
1160INDI_NEWCALLBACK_DEFN( modalFilter, m_indiP_mult )( const pcf::IndiProperty &ipRecv )
1161{
1162 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_mult, ipRecv );
1163
1164 float target;
1165 if( indiTargetUpdate( m_indiP_mult, target, ipRecv, true ) < 0 )
1166 {
1167 log<software_error>( { __FILE__, __LINE__ } );
1168 return -1;
1169 }
1170
1171 m_mc = target;
1172
1173 std::cerr << "Got global mc: " << m_mc << '\n';
1174
1175 return 0;
1176}
1177
1178INDI_NEWCALLBACK_DEFN( modalFilter, m_indiP_pcGain )( const pcf::IndiProperty &ipRecv )
1179{
1180 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_pcGain, ipRecv );
1181
1182 float target;
1183 if( indiTargetUpdate( m_indiP_pcGain, target, ipRecv, true ) < 0 )
1184 {
1185 log<software_error>( { __FILE__, __LINE__ } );
1186 return -1;
1187 }
1188
1189 m_pcGain = target;
1190
1191 std::cerr << "Got global pc gain: " << m_pcGain << '\n';
1192 return 0;
1193}
1194
1195INDI_NEWCALLBACK_DEFN( modalFilter, m_indiP_pcMult )( const pcf::IndiProperty &ipRecv )
1196{
1197 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_pcMult, ipRecv );
1198
1199 float target;
1200 if( indiTargetUpdate( m_indiP_pcMult, target, ipRecv, true ) < 0 )
1201 {
1202 log<software_error>( { __FILE__, __LINE__ } );
1203 return -1;
1204 }
1205
1206 m_pcMc = target;
1207
1208 std::cerr << "Got global pc mc: " << m_mc << '\n';
1209
1210 return 0;
1211}
1212
1213INDI_NEWCALLBACK_DEFN( modalFilter, m_indiP_pcOn )( const pcf::IndiProperty &ipRecv )
1214{
1215 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_pcOn, ipRecv );
1216
1217 if( ipRecv.find( "toggle" ) )
1218 {
1219 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On )
1220 {
1221
1222 m_pcOn = true;
1223 }
1224 else
1225 {
1226 m_pcOn = false;
1227 }
1228 }
1229
1230 return 0;
1231}
1232
1233} // namespace app
1234} // namespace MagAOX
1235
1236#endif // modalFilter_hpp
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.
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.
timespec m_currImageTimestamp
The timestamp of the current image.
uint32_t m_width
The width of the image, once deinterlaced etc.
uint8_t m_dataType
The ImageStreamIO type code.
uint32_t m_height
The height of the image, once deinterlaced etc.
uint32_t m_width
The width of the images in the stream.
uint32_t m_height
The height of the images in the stream.
The MagAO-X modal filter.
virtual int appLogic()
Implementation of the FSM for modalFilter.
int recordTelem(const telem_fgtimings *)
pcf::IndiProperty m_indiP_fpsSource
std::string m_fpsDevice
Device name for getting fps to set circular buffer length.
INDI_NEWCALLBACK_DECL(modalFilter, m_indiP_mult)
INDI_SETCALLBACK_DECL(modalFilter, m_indiP_fpsSource)
pcf::IndiProperty m_indiP_mult
int acquireAndCheckValid()
Implementation of the framegrabber acquireAndCheckValid interface.
std::vector< float > m_pcGainfacts
pcf::IndiProperty m_indiP_pcMult
std::vector< int > m_Na
dev::shmimMonitor< modalFilter, acoeffShmimT > acoeffShmimMonitorT
sem_t m_filtSem
Semaphore used to signal that fresh modevals are waiting to be filtered.
float fps()
Implementation of the frameGrabber fps interface.
pcf::IndiProperty m_indiP_pcOn
~modalFilter() noexcept
D'tor, declared and defined for noexcept.
int loadImageIntoStream(void *dest)
Implementation of the framegrabber loadImageIntoStream interface.
INDI_NEWCALLBACK_DECL(modalFilter, m_indiP_pcMult)
dev::shmimMonitor< modalFilter, modevalShmimT > modevalShmimMonitorT
std::shared_mutex m_filtMutex
Mutex for locking access to filter parameters.
int allocate(const gainFactShmimT &)
eigenImage< float > m_as
std::string m_loopName
The name of the loop control INDI device name. Defalt is "ho".
dev::telemeter< modalFilter > telemeterT
int32_t m_modevalCBLength
The length of the modeval circular buffers. Default is 1000 entries.
dev::frameGrabber< modalFilter > frameGrabberT
INDI_NEWCALLBACK_DECL(modalFilter, m_indiP_loop)
std::vector< int > m_Nb
mx::sigproc::circularBufferIndex< std::vector< float >, int32_t > m_modevalDM
int startAcquisition()
Implementation of the framegrabber startAcquisition interface.
virtual int appStartup()
Startup function.
static constexpr bool c_frameGrabber_flippable
dev::shmimMonitor< modalFilter, pcMultFactShmimT > pcMultFactShmimMonitorT
pcf::IndiProperty m_indiP_gain
INDI_NEWCALLBACK_DECL(modalFilter, m_indiP_pcOn)
pcf::IndiProperty m_indiP_pcGain
mx::sigproc::circularBufferIndex< std::vector< float >, int32_t > m_modevalWFS
eigenImage< float > m_bs
virtual int appShutdown()
Shutdown the app.
dev::shmimMonitor< modalFilter, gainFactShmimT > gainFactShmimMonitorT
dev::shmimMonitor< modalFilter, multFactShmimT > multFactShmimMonitorT
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
INDI_NEWCALLBACK_DECL(modalFilter, m_indiP_pcGain)
INDI_NEWCALLBACK_DECL(modalFilter, m_indiP_gain)
float m_fpsTol
The tolerance for detecting a change in FPS.
std::vector< float > m_pcMultfacts
std::string m_fpsElement
Element name for getting fps to set circular buffer length.
dev::shmimMonitor< modalFilter, pcGainFactShmimT > pcGainFactShmimMonitorT
pcf::IndiProperty m_indiP_loop
std::vector< float > m_gainfacts
timespec m_atime
The acq time of the WFS modevals.
int reconfig()
Implementation of the framegrabber reconfig interface.
int configureAcquisition()
Implementation of the framegrabber configureAcquisition interface.
int processImage(void *curr_src, const gainFactShmimT &)
dev::shmimMonitor< modalFilter, bcoeffShmimT > bcoeffShmimMonitorT
std::string m_fpsProperty
Property name for getting fps to set circular buffer length.
bool m_sizesMatch
Flag indicating that all sizes are consistent.
std::vector< float > m_multfacts
int m_loopNum
The number of the loop. Used to set shmim names, as in aolN_mgainfact. Default is 1.
bool m_pcSizesMatch
Flag indicating that all sizes are consistent.
modalFilter()
Default c'tor.
#define FRAMEGRABBER_SETUP_CONFIG(cfig)
Call frameGrabberT::setupConfig with error checking for frameGrabber.
#define FRAMEGRABBER_APP_LOGIC
Call frameGrabberT::appLogic with error checking for frameGrabber.
#define FRAMEGRABBER_APP_SHUTDOWN
Call frameGrabberT::appShutdown with error checking for frameGrabber.
#define FRAMEGRABBER_UPDATE_INDI
Call frameGrabberT::updateINDI with error checking for frameGrabber.
#define FRAMEGRABBER_LOAD_CONFIG(cfig)
Call frameGrabberT::loadConfig with error checking for frameGrabber.
#define FRAMEGRABBER_APP_STARTUP
Call frameGrabberT::appStartup with error checking for frameGrabber.
#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_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.
@ 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
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(ts, sec, nsec)
Add the wait time to a timespec for a sem_timedwait call, with -1 returned on error.
Definition semUtils.hpp:38
#define SHMIMMONITORT_APP_STARTUP(SHMIMMONITORT)
Call shmimMonitorT::appStartup with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITORT_UPDATE_INDI(SHMIMMONITORT)
Call shmimMonitorT::updateINDI with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITORT_SETUP_CONFIG(SHMIMMONITORT, cfig)
Call shmimMonitorT::setupConfig with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITORT_APP_LOGIC(SHMIMMONITORT)
Call shmimMonitorT::appLogic with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITORT_APP_SHUTDOWN(SHMIMMONITORT)
Call shmimMonitorT::appShutodwn with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITORT_LOAD_CONFIG(SHMIMMONITORT, cfig)
Call shmimMonitorT::loadConfig with error checking for a typedef-ed shmimMonitor.
static std::string configSection()
static std::string indiPrefix()
static std::string indiPrefix()
static std::string configSection()
A device base class which saves telemetry.
Definition telemeter.hpp:69
int checkRecordTimes(const telT &tel, telTs... tels)
Check the time of the last record for each telemetry type and make an entry if needed.
static std::string 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()
Software CRITICAL log entry.
Software ERR log entry.
Log entry recording framegrabber timings.
#define TELEMETER_APP_LOGIC
Call telemeter::appLogic with error checking.
#define TELEMETER_LOAD_CONFIG(cfig)
Call telemeter::loadConfig with error checking.
#define TELEMETER_APP_STARTUP
Call telemeter::appStartup with error checking.
#define TELEMETER_SETUP_CONFIG(cfig)
Call telemeter::setupConfig with error checking.
#define TELEMETER_APP_SHUTDOWN
Call telemeter::appShutdown with error checking.