API
 
Loading...
Searching...
No Matches
psfFit.hpp
Go to the documentation of this file.
1/** \file psfFit.hpp
2 * \brief The MagAO-X PSF Fitter application header
3 *
4 * \ingroup psfFit_files
5 */
6
7#ifndef psfFit_hpp
8#define psfFit_hpp
9
10#include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
11#include "../../magaox_git_version.h"
12
13/** \defgroup psfFit
14 * \brief The MagAO-X PSF fitter.
15 *
16 * <a href="../handbook/operating/software/apps/psfFit.html">Application Documentation</a>
17 *
18 * \ingroup apps
19 *
20 */
21
22/** \defgroup psfFit_files
23 * \ingroup psfFit
24 */
25
26namespace MagAOX
27{
28namespace app
29{
30
31struct darkShmimT
32{
33 static std::string configSection()
34 {
35 return "darkShmim";
36 };
37
38 static std::string indiPrefix()
39 {
40 return "dark";
41 };
42};
43
45{
46 static std::string configSection()
47 {
48 return "refShmim";
49 };
50
51 static std::string indiPrefix()
52 {
53 return "ref";
54 };
55};
56
57/// The MagAO-X PSF Fitter
58/**
59 * \ingroup psfFit
60 */
61class psfFit : public MagAOXApp<true>,
62 public dev::shmimMonitor<psfFit>,
63 public dev::shmimMonitor<psfFit, darkShmimT>,
64 public dev::shmimMonitor<psfFit, refShmimT>,
65 public dev::frameGrabber<psfFit>,
66 public dev::telemeter<psfFit>
67{
68 // Give the test harness access.
69 friend class psfFit_test;
70
71 friend class dev::shmimMonitor<psfFit>;
72 friend class dev::shmimMonitor<psfFit, darkShmimT>;
73 friend class dev::shmimMonitor<psfFit, refShmimT>;
74 friend class dev::frameGrabber<psfFit>;
75
76 friend class dev::telemeter<psfFit>;
77
78 public:
79 /// The base shmimMonitor type
81
82 /// The dark shmimMonitor type
84
85 /// The reference shmimMonitor type
87
88 // The base frameGrabber type
90
91 // The base telemeter type
93
94 /// Floating point type in which to do all calculations.
95 typedef float realT;
96
97 /** \name app::dev Configurations
98 *@{
99 */
100
101 static constexpr bool c_frameGrabber_flippable =
102 false; ///< app:dev config to tell framegrabber these images can not be flipped
103
104 ///@}
105
106 protected:
107 /** \name Configurable Parameters
108 *@{
109 */
110
111 std::string m_fpsSource; ///< Device name for getting fps if time-based averaging is used. This device should have
112 ///< *.fps.current.
113
114 uint16_t m_fitCircBuffMaxLength{ 5 * 10000 }; ///< Maximum length of the latency measurement circular buffers
115
116 float m_fitCircBuffMaxTime{ 5 }; ///< Maximum time of the latency meaurement circular buffers
117
118 float m_deltaPixThresh{ 2 }; /**< Threshold in pixels for skipping frame due to mismatch between max and c.o.l.
119 Default 2.*/
120
121 float m_sigmaMaxThreshUp{ 5 }; /**< Threshold in rms for skipping frame due to max positive difference from mean
122 max. Default 5.*/
123
124 float m_sigmaMaxThreshDown{ 5 }; /**< Threshold in rms for skipping frame due to max negative difference from mean
125 mas. Default 5.*/
126
127 float m_sigmaPixThresh{ 10 }; /**< Threshold in rms for skipping frame due to max difference from last value.
128 Example: if this is set to 10, then the pixel postion has to change from -5 sigma
129 to + 5 sigma to be rejected. Default 10.*/
130
131 ///@}
132
133 mx::improc::eigenImage<float> m_image; ///< Holds the raw image
134
135 mx::improc::eigenImage<float> m_dark; ///< Holds the dark image
136
137 mx::improc::eigenImage<float> m_ref; ///< Holds the reference image
138
139 bool m_updated{ false }; ///< Indicates that the coordinates were updated was updated
140
141 bool m_skipped{ false }; ///< Indicates that the image failed quality control and this is a skip frame
142
143 float m_x{ 0 }; ///< The current x coordinate
144 float m_last_x{ 0 }; ///< The previous x coordinate
145
146 float m_y{ 0 }; ///< The current y coordinate
147 float m_last_y{ 0 }; ///< The previous y coordinate
148
149 float m_dx{ 0 }; ///< The offset in x to apply to non-skipped measurements
150 float m_dy{ 0 }; ///< The offset in y to apply to non-skipped measurements
151
152 float m_fps{ 0 }; ///< The frame rate from the source camera
153
154 mx::sigproc::circularBufferIndex<float, cbIndexT> m_pcb; ///< Circular buffer for max pixel (p=peak)
155 mx::sigproc::circularBufferIndex<float, cbIndexT> m_xcb; ///< Circular buffer for x COL coords
156 mx::sigproc::circularBufferIndex<float, cbIndexT> m_ycb; ///< Circular buffer for y COL coords
157
158 std::vector<float> m_pcbD; ///< Vector for doing calcs on max pixel
159 std::vector<float> m_xcbD; ///< Vector for doing calcs on x COL coords
160 std::vector<float> m_ycbD; ///< Vector for doing calcs on y COL coords
161
162 float m_mnp{ 0 }; ///< The mean max pixel over the stats time
163 float m_rmsp{ 0 }; ///< The rms max pixel over the stats time
164
165 float m_mnx{ 0 }; ///< The mean x coord over the stats time
166 float m_rmsx{ 0 }; ///< The rms x coord over the stats time
167 float m_mny{ 0 }; ///< The mean y coord over the stats time
168 float m_rmsy{ 0 }; ///< The rms y coord over the stats time
169
170 public:
171 /// Default c'tor.
172 psfFit();
173
174 /// D'tor, declared and defined for noexcept.
176
177 virtual void setupConfig();
178
179 /// Implementation of loadConfig logic, separated for testing.
180 /** This is called by loadConfig().
181 */
182 int loadConfigImpl(
183 mx::app::appConfigurator &_config /**< [in] an application configuration from which to load values*/ );
184
185 virtual void loadConfig();
186
187 /// Startup function
188 /**
189 *
190 */
191 virtual int appStartup();
192
193 /// Implementation of the FSM for psfFit.
194 /**
195 * \returns 0 on no critical error
196 * \returns -1 on an error requiring shutdown
197 */
198 virtual int appLogic();
199
200 /// Shutdown the app.
201 /**
202 *
203 */
204 virtual int appShutdown();
205
206 // shmimMonitor interface:
207 int allocate( const dev::shmimT & );
208
209 int processImage( void *curr_src, const dev::shmimT & );
210
211 // shmimMonitor interface for dark:
212 int allocate( const darkShmimT & );
213
214 int processImage( void *curr_src, const darkShmimT & );
215
216 // shmimMonitor interface for reference:
217 int allocate( const refShmimT & );
218
219 int processImage( void *curr_src, const refShmimT & );
220
221 protected:
222 std::mutex m_imageMutex;
223
224 sem_t m_smSemaphore{ 0 }; ///< Semaphore used to synchronize the fg thread and the sm thread.
225
226 public:
227 /** \name dev::frameGrabber interface
228 *
229 * @{
230 */
231
232 /// Implementation of the framegrabber configureAcquisition interface
233 /**
234 * \returns 0 on success
235 * \returns -1 on error
236 */
238
239 /// Implementation of the framegrabber fps interface
240 /**
241 * \todo this needs to infer the stream fps and return it
242 */
243 float fps()
244 {
245 return m_fps;
246 }
247
248 /// Implementation of the framegrabber startAcquisition interface
249 /**
250 * \returns 0 on success
251 * \returns -1 on error
252 */
253 int startAcquisition();
254
255 /// Implementation of the framegrabber acquireAndCheckValid interface
256 /**
257 * \returns 0 on success
258 * \returns -1 on error
259 */
261
262 /// Implementation of the framegrabber loadImageIntoStream interface
263 /**
264 * \returns 0 on success
265 * \returns -1 on error
266 */
267 int loadImageIntoStream( void *dest /**< [in] */ );
268
269 /// Implementation of the framegrabber reconfig interface
270 /**
271 * \returns 0 on success
272 * \returns -1 on error
273 */
274 int reconfig();
275
276 ///@}
277
278 protected:
279 /** \name INDI
280 * @{
281 */
282
283 pcf::IndiProperty m_indiP_values;
284
285 pcf::IndiProperty m_indiP_reset;
287
288 pcf::IndiProperty m_indiP_statsTime;
290
291 pcf::IndiProperty m_indiP_deltaPixThresh;
293
294 pcf::IndiProperty m_indiP_sigmaMaxThreshUp;
296
297 pcf::IndiProperty m_indiP_sigmaMaxThreshDown;
299
300 pcf::IndiProperty m_indiP_sigmaPixThresh;
302
303 pcf::IndiProperty m_indiP_dx;
305
306 pcf::IndiProperty m_indiP_dy;
308
309 pcf::IndiProperty m_indiP_fpsSource;
311
312 ///@}
313
314 /** \name Telemeter Interface
315 *
316 * @{
317 */
318 int checkRecordTimes();
319
320 int recordTelem( const telem_fgtimings * );
321
322 ///@}
323};
324
325inline psfFit::psfFit() : MagAOXApp( MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED )
326{
329
330 return;
331}
332
333inline psfFit::~psfFit() noexcept
334{
335}
336
338{
343 TELEMETER_SETUP_CONFIG( config );
344
345 config.add(
346 "fitter.fpsSource",
347 "",
348 "fitter.fpsSource",
349 argType::Required,
350 "fitter",
351 "fpsSource",
352 false,
353 "string",
354 "Device name for getting fps if time-based averaging is used. This device should have *.fps.current." );
355
356 config.add( "fitter.deltaPixThresh",
357 "",
358 "fitter.deltaPixThresh",
359 argType::Required,
360 "fitter",
361 "deltaPixThresh",
362 false,
363 "float",
364 "Threshold in pixels for skipping frame due to mismatch between max and c.o.l. Default 2." );
365 config.add( "fitter.sigmaMaxThreshUp",
366 "",
367 "fitter.sigmaMaxThreshUp",
368 argType::Required,
369 "fitter",
370 "sigmaMaxThreshUp",
371 false,
372 "float",
373 "Threshold in rms for skipping frame due to max positive difference from mean max. Default 5." );
374 config.add( "fitter.sigmaMaxThreshDown",
375 "",
376 "fitter.sigmaMaxThreshDown",
377 argType::Required,
378 "fitter",
379 "sigmaMaxThreshDown",
380 false,
381 "float",
382 "Threshold in rms for skipping frame due to max negative difference from mean max. Default 5." );
383
384 config.add( "fitter.sigmaPixThresh",
385 "",
386 "fitter.sigmaPixThresh",
387 argType::Required,
388 "fitter",
389 "sigmaPixThresh",
390 false,
391 "float",
392 "Threshold in rms for skipping frame due to max difference from last value. Example: if this is set "
393 "to 10, then the pixel postion has to change from -5 sigma to + 5 sigma to be rejected. Default 10." );
394}
395
396inline int psfFit::loadConfigImpl( mx::app::appConfigurator &_config )
397{
401
404
405 _config( m_fpsSource, "fitter.fpsSource" );
406 _config( m_deltaPixThresh, "fitter.deltaPixThresh" );
407 _config( m_sigmaMaxThreshUp, "fitter.sigmaMaxThreshUp" );
408 _config( m_sigmaMaxThreshDown, "fitter.sigmaMaxThreshDown" );
409 _config( m_sigmaPixThresh, "fitter.sigmaPixThresh" );
410
411 return 0;
412}
413
415{
416 loadConfigImpl( config );
417}
418
420{
424
425 if( sem_init( &m_smSemaphore, 0, 0 ) < 0 )
426 {
427 log<software_critical>( { __FILE__, __LINE__, errno, 0, "Initializing S.M. semaphore" } );
428 return -1;
429 }
430
433
434 if( m_fpsSource != "" )
435 {
436 REG_INDI_SETPROP( m_indiP_fpsSource, m_fpsSource, std::string( "fps" ) );
437 }
438
439 CREATE_REG_INDI_RO_NUMBER( m_indiP_values, "values", "", "" );
440 m_indiP_values.add( pcf::IndiElement( "max_mean" ) );
441 m_indiP_values.add( pcf::IndiElement( "max_rms" ) );
442 m_indiP_values.add( pcf::IndiElement( "x_mean" ) );
443 m_indiP_values.add( pcf::IndiElement( "x_rms" ) );
444 m_indiP_values.add( pcf::IndiElement( "y_mean" ) );
445 m_indiP_values.add( pcf::IndiElement( "y_rms" ) );
446
448
449 CREATE_REG_INDI_NEW_NUMBERF( m_indiP_statsTime, "statsTime", 0, 5, 1, "%0.1f", "", "" );
450 m_indiP_statsTime["current"].setValue( m_fitCircBuffMaxTime );
451 m_indiP_statsTime["target"].setValue( m_fitCircBuffMaxTime );
452
453 CREATE_REG_INDI_NEW_NUMBERF( m_indiP_deltaPixThresh, "deltaPixThresh", 0, 512, 1, "%0.1f", "", "" );
454 m_indiP_deltaPixThresh["current"].setValue( m_deltaPixThresh );
455 m_indiP_deltaPixThresh["target"].setValue( m_deltaPixThresh );
456
457 CREATE_REG_INDI_NEW_NUMBERF( m_indiP_sigmaMaxThreshUp, "sigmaMaxThreshUp", 0, 512, 1, "%0.1f", "", "" );
458 m_indiP_sigmaMaxThreshUp["current"].setValue( m_sigmaMaxThreshUp );
459 m_indiP_sigmaMaxThreshUp["target"].setValue( m_sigmaMaxThreshUp );
460
461 CREATE_REG_INDI_NEW_NUMBERF( m_indiP_sigmaMaxThreshDown, "sigmaMaxThreshDown", 0, 512, 1, "%0.1f", "", "" );
464
465 CREATE_REG_INDI_NEW_NUMBERF( m_indiP_sigmaPixThresh, "sigmaPixThresh", 0, 512, 1, "%0.1f", "", "" );
466 m_indiP_sigmaPixThresh["current"].setValue( m_sigmaPixThresh );
467 m_indiP_sigmaPixThresh["target"].setValue( m_sigmaPixThresh );
468
469 CREATE_REG_INDI_NEW_NUMBERF( m_indiP_dx, "dx", -100, 100, 1e-2, "%0.02f", "", "" );
470 m_indiP_dx["current"].setValue( m_dx );
471 m_indiP_dx["target"].setValue( m_dx );
472
473 CREATE_REG_INDI_NEW_NUMBERF( m_indiP_dy, "dy", -100, 100, 1e-2, "%0.02f", "", "" );
474 m_indiP_dy["current"].setValue( m_dy );
475 m_indiP_dy["target"].setValue( m_dy );
476
478
479 return 0;
480}
481
483{
489
490 if( state() == stateCodes::OPERATING && m_xcb.size() > 0 )
491 {
492 if( m_xcb.size() >= m_xcb.maxEntries() )
493 {
494 cbIndexT refEntry = m_xcb.earliest();
495
496 m_pcbD.resize( m_pcb.maxEntries() - 1 );
497 m_xcbD.resize( m_xcb.maxEntries() - 1 );
498 m_ycbD.resize( m_xcb.maxEntries() - 1 );
499
500 for( size_t n = 0; n < m_xcb.size(); ++n )
501 {
502 m_pcbD[n] = m_pcb.at( refEntry, n );
503 m_xcbD[n] = m_xcb.at( refEntry, n );
504 m_ycbD[n] = m_ycb.at( refEntry, n );
505 }
506
507 m_mnp = mx::math::vectorMean( m_pcbD );
508 m_rmsp = sqrt( mx::math::vectorVariance( m_pcbD, m_mnp ) );
509
510 m_mnx = mx::math::vectorMean( m_xcbD );
511
512 m_rmsx = sqrt( mx::math::vectorVariance( m_xcbD, m_mnx ) );
513
514 m_mny = mx::math::vectorMean( m_ycbD );
515 m_rmsy = sqrt( mx::math::vectorVariance( m_ycbD, m_mny ) );
516 }
517 else
518 {
519 m_mnp = 0;
520 m_rmsp = 0;
521
522 m_mnx = 0;
523 m_rmsx = 0;
524
525 m_mny = 0;
526 m_rmsy = 0;
527 }
528 }
529 else
530 {
531 m_mnp = 0;
532 m_rmsp = 0;
533
534 m_mnx = 0;
535 m_rmsx = 0;
536
537 m_mny = 0;
538 m_rmsy = 0;
539 }
540
544
546
548
550 std::vector<std::string>( { "max_mean", "max_rms", "x_mean", "x_rms", "y_mean", "y_rms" } ),
551 std::vector<float>( { m_mnp, m_rmsp, m_mnx, m_rmsx, m_mny, m_rmsy } ) );
552
553 updateIfChanged( m_indiP_dx, "current", m_dx );
554 updateIfChanged( m_indiP_dy, "current", m_dy );
555
556 return 0;
557}
558
569
570inline int psfFit::allocate( const dev::shmimT &dummy )
571{
572 static_cast<void>( dummy );
573
574 std::lock_guard<std::mutex> guard( m_imageMutex );
575
577 m_image.setZero();
578
579 if( m_fitCircBuffMaxLength == 0 || m_fitCircBuffMaxTime == 0 || m_fps <= 0 )
580 {
581 m_pcb.maxEntries( 0 );
582 m_xcb.maxEntries( 0 );
583 m_ycb.maxEntries( 0 );
584
585 m_mnp = 0;
586 m_rmsp = 0;
587
588 m_mnx = 0;
589 m_rmsx = 0;
590
591 m_mny = 0;
592 m_rmsy = 0;
593 }
594 else
595 {
596 // Set up the fit circ. buffs
600 if( cbSz < 3 )
601 cbSz = 3; // Make variance meaningful
602
603 m_pcb.maxEntries( cbSz );
604 m_xcb.maxEntries( cbSz );
605 m_ycb.maxEntries( cbSz );
606
607 m_mnp = 0;
608 m_rmsp = 0;
609
610 m_mnx = 0;
611 m_rmsx = 0;
612
613 m_mny = 0;
614 m_rmsy = 0;
615 }
616
617 m_updated = false;
618 return 0;
619}
620
621inline int psfFit::processImage( void *curr_src, const dev::shmimT &dummy )
622{
623 static_cast<void>( dummy );
624
625 // counters for managing printing of delta-pix skips when shutter closed
626 static int skip_interval = 10;
627 static int last_passed = skip_interval + 1;
628
629 std::unique_lock<std::mutex> lock( m_imageMutex );
630
631 if( m_dark.rows() == m_image.rows() && m_dark.cols() == m_image.cols() )
632 {
634 {
635 for( unsigned nn = 0; nn < shmimMonitorT::m_width * shmimMonitorT::m_height; ++nn )
636 {
637 m_image.data()[nn] = ( (uint16_t *)curr_src )[nn] - m_dark.data()[nn];
638 }
639 }
641 {
642 for( unsigned nn = 0; nn < shmimMonitorT::m_width * shmimMonitorT::m_height; ++nn )
643 {
644 m_image.data()[nn] = ( (float *)curr_src )[nn] - m_dark.data()[nn];
645 }
646 }
647 }
648 else
649 {
651 {
652 for( unsigned nn = 0; nn < shmimMonitorT::m_width * shmimMonitorT::m_height; ++nn )
653 {
654 m_image.data()[nn] = ( (uint16_t *)curr_src )[nn];
655 }
656 }
658 {
659 for( unsigned nn = 0; nn < shmimMonitorT::m_width * shmimMonitorT::m_height; ++nn )
660 {
661 m_image.data()[nn] = ( (float *)curr_src )[nn];
662 }
663 }
664 }
665
666 lock.unlock();
667
668 float max;
669 int x = 0;
670 int y = 0;
671
672 max = m_image.maxCoeff( &x, &y );
673
674 mx::improc::imageCenterOfLight( m_x, m_y, m_image );
675
676 m_skipped = false;
677
678 if( fabs( m_x - x ) > m_deltaPixThresh || fabs( m_y - y ) > m_deltaPixThresh )
679 {
680 if( last_passed > skip_interval ) // We only print if it's passed skip_interval times in between without failing
681 {
682 std::cerr << "skip frame (delta from max) " << m_x << " " << x << " " << m_y << " " << y << "("
683 << ( m_x - x ) << " " << ( m_y - y ) << ")\n";
684 }
685 last_passed = 0; // if we fail this threshold, we set last_pass to 0 to start over.
686 m_skipped = true;
687
688 // We do not add these measurements to stats b/c this means bad PSF
689 }
690 else if( last_passed < skip_interval + 1 ) // increment but don't overflow
691 {
692 ++last_passed;
693 }
694
695 // still filling circular buffer
696 if( ( m_rmsx == 0 || m_rmsy == 0 || m_rmsp == 0 ) && !m_skipped )
697 {
698 if( m_xcb.maxEntries() > 0 )
699 {
700 m_pcb.nextEntry( max );
701 m_xcb.nextEntry( m_x );
702 m_ycb.nextEntry( m_y );
703 }
704
705 m_last_x = m_x;
706 m_last_y = m_y;
707
708 m_skipped = true;
709 }
710
711 // The remaining checks are for wild motions but otherwise valid fits (good PSF)
712
713 if( ( ( max - m_mnp ) / m_rmsp > m_sigmaMaxThreshUp ) && !m_skipped )
714 {
715 if( m_pcb.maxEntries() > 0 )
716 {
717 m_pcb.nextEntry( max );
718 m_xcb.nextEntry( m_x );
719 m_ycb.nextEntry( m_y );
720 }
721
722 std::cerr << "skip frame (max-rms up) " << max << " " << m_mnp << " " << m_rmsp << " ("
723 << ( max - m_mnp ) / m_rmsp << ")\n";
724
725 m_last_x = m_x;
726 m_last_y = m_y;
727
728 m_skipped = true;
729 }
730
731 if( ( ( max - m_mnp ) / m_rmsp < -m_sigmaMaxThreshDown ) && !m_skipped )
732 {
733 if( m_pcb.maxEntries() > 0 )
734 {
735 m_pcb.nextEntry( max );
736 m_xcb.nextEntry( m_x );
737 m_ycb.nextEntry( m_y );
738 }
739
740 std::cerr << "skip frame (max-rms down) " << max << " " << m_mnp << " " << m_rmsp << " ("
741 << ( max - m_mnp ) / m_rmsp << ")\n";
742
743 m_last_x = m_x;
744 m_last_y = m_y;
745
746 m_skipped = true;
747 }
748
749 if( ( fabs( m_x - m_last_x ) / m_rmsx > m_sigmaPixThresh ) && !m_skipped )
750 {
751 if( m_xcb.maxEntries() > 0 )
752 {
753 m_pcb.nextEntry( max );
754 m_xcb.nextEntry( m_x );
755 m_ycb.nextEntry( m_y );
756 }
757
758 std::cerr << "skip frame (x-rms) " << m_x << " " << m_last_x << " " << m_rmsx << " ("
759 << ( m_x - m_last_x ) / m_rmsx << ")\n";
760
761 m_last_x = m_x;
762 m_last_y = m_y;
763
764 m_skipped = true;
765 }
766
767 if( ( fabs( m_y - m_last_y ) / m_rmsy > m_sigmaPixThresh ) && !m_skipped )
768 {
769 if( m_ycb.maxEntries() > 0 )
770 {
771 m_pcb.nextEntry( max );
772 m_xcb.nextEntry( m_x );
773 m_ycb.nextEntry( m_y );
774 }
775
776 std::cerr << "skip frame (y-rms) " << m_y << " " << m_last_y << " " << m_rmsy << " ("
777 << ( m_y - m_last_y ) / m_rmsy << ")\n";
778
779 m_last_x = m_x;
780 m_last_y = m_y;
781
782 m_skipped = true;
783 }
784
785 if( m_skipped )
786 {
787 if( m_ref.rows() == 2 && m_ref.cols() == 1 )
788 {
789 m_x = m_ref( 0, 0 );
790 m_y = m_ref( 1, 0 );
791 }
792 else
793 {
794 m_x = 0;
795 m_y = 0;
796 }
797 }
798
799 m_updated = true;
800
801 // signal framegrabber
802 // Now tell the f.g. to get going
803 if( sem_post( &m_smSemaphore ) < 0 )
804 {
805 log<software_critical>( { __FILE__, __LINE__, errno, 0, "Error posting to semaphore" } );
806 return -1;
807 }
808
809 if( !m_skipped )
810 {
811 if( m_xcb.maxEntries() > 0 )
812 {
813 m_pcb.nextEntry( max );
814 m_xcb.nextEntry( m_x );
815 m_ycb.nextEntry( m_y );
816 }
817
818 m_last_x = m_x;
819 m_last_y = m_y;
820 }
821
822 return 0;
823}
824
825int psfFit::allocate( const darkShmimT &dummy )
826{
827 static_cast<void>( dummy );
828
829 std::lock_guard<std::mutex> guard( m_imageMutex );
830
832 {
833 return log<software_error, -1>( { __FILE__, __LINE__, "dark is not float" } );
834 }
835
837 m_dark.setZero();
838
839 return 0;
840}
841
842int psfFit::processImage( void *curr_src, const darkShmimT &dummy )
843{
844 static_cast<void>( dummy );
845
846 std::unique_lock<std::mutex> lock( m_imageMutex );
847
849 {
850 m_dark.data()[nn] = ( (float *)curr_src )[nn];
851 }
852
853 lock.unlock();
854
855 log<text_log>( "dark updated", logPrio::LOG_INFO );
856
857 return 0;
858}
859
860int psfFit::allocate( const refShmimT &dummy )
861{
862 static_cast<void>( dummy );
863
864 std::lock_guard<std::mutex> guard( m_imageMutex );
865
867 {
868 return log<software_error, -1>( { __FILE__, __LINE__, "ref is not float" } );
869 }
870
872 m_ref.setZero();
873
874 return 0;
875}
876
877int psfFit::processImage( void *curr_src, const refShmimT &dummy )
878{
879 static_cast<void>( dummy );
880
881 std::unique_lock<std::mutex> lock( m_imageMutex );
882
884 {
885 m_ref.data()[nn] = ( (float *)curr_src )[nn];
886 }
887
888 lock.unlock();
889
890 log<text_log>( "reference updated", logPrio::LOG_INFO );
891
892 return 0;
893}
894
904
906{
907 return 0;
908}
909
911{
912 timespec ts;
913
914 if( clock_gettime( CLOCK_REALTIME, &ts ) < 0 )
915 {
916 log<software_critical>( { __FILE__, __LINE__, errno, 0, "clock_gettime" } );
917 return -1;
918 }
919
920 ts.tv_sec += 1;
921
922 if( sem_timedwait( &m_smSemaphore, &ts ) == 0 )
923 {
924 if( m_updated )
925 {
927 return 0;
928 }
929 else
930 {
931 return 1;
932 }
933 }
934 else
935 {
936 return 1;
937 }
938}
939
940inline int psfFit::loadImageIntoStream( void *dest )
941{
942 if( !m_skipped )
943 {
944 ( (float *)dest )[0] = m_x - m_dx;
945 ( (float *)dest )[1] = m_y - m_dy;
946 }
947 else
948 {
949 ( (float *)dest )[0] = m_x;
950 ( (float *)dest )[1] = m_y;
951 }
952
953 m_updated = false;
954
955 return 0;
956}
957
959{
960 return 0;
961}
962
963INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_reset )( const pcf::IndiProperty &ipRecv )
964{
965 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_reset, ipRecv );
966
967 if( ipRecv.find( "request" ) != true ) // this isn't valid
968 {
969 return -1;
970 }
971
972 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On )
973 {
974 log<text_log>( "reset requested", logPrio::LOG_NOTICE );
975 shmimMonitorT::m_restart = true;
976 }
977
978 return 0;
979}
980
981INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_statsTime )( const pcf::IndiProperty &ipRecv )
982{
983 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_statsTime, ipRecv );
984
985 float target;
986
987 if( indiTargetUpdate( m_indiP_statsTime, target, ipRecv, true ) < 0 )
988 {
989 log<software_error>( { __FILE__, __LINE__ } );
990 return -1;
991 }
992
993 m_fitCircBuffMaxTime = target;
994
995 shmimMonitorT::m_restart = true;
996
997 log<text_log>( "set statsTime = " + std::to_string( m_fitCircBuffMaxTime ), logPrio::LOG_NOTICE );
998
999 return 0;
1000}
1001
1002INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_deltaPixThresh )( const pcf::IndiProperty &ipRecv )
1003{
1004 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_deltaPixThresh, ipRecv );
1005
1006 float target;
1007
1008 if( indiTargetUpdate( m_indiP_deltaPixThresh, target, ipRecv, true ) < 0 )
1009 {
1010 log<software_error>( { __FILE__, __LINE__ } );
1011 return -1;
1012 }
1013
1014 m_deltaPixThresh = target;
1015
1016 log<text_log>( "set deltaPixThresh = " + std::to_string( m_deltaPixThresh ), logPrio::LOG_NOTICE );
1017 return 0;
1018}
1019
1020INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_sigmaMaxThreshUp )( const pcf::IndiProperty &ipRecv )
1021{
1022 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_sigmaMaxThreshUp, ipRecv );
1023
1024 float target;
1025
1026 if( indiTargetUpdate( m_indiP_sigmaMaxThreshUp, target, ipRecv, true ) < 0 )
1027 {
1028 log<software_error>( { __FILE__, __LINE__ } );
1029 return -1;
1030 }
1031
1032 m_sigmaMaxThreshUp = target;
1033
1034 log<text_log>( "set sigmaMaxThreshUp = " + std::to_string( m_sigmaMaxThreshUp ), logPrio::LOG_NOTICE );
1035 return 0;
1036}
1037
1038INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_sigmaMaxThreshDown )( const pcf::IndiProperty &ipRecv )
1039{
1040 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_sigmaMaxThreshDown, ipRecv );
1041
1042 float target;
1043
1044 if( indiTargetUpdate( m_indiP_sigmaMaxThreshDown, target, ipRecv, true ) < 0 )
1045 {
1046 log<software_error>( { __FILE__, __LINE__ } );
1047 return -1;
1048 }
1049
1050 m_sigmaMaxThreshDown = target;
1051
1052 log<text_log>( "set sigmaMaxThreshDown = " + std::to_string( m_sigmaMaxThreshDown ), logPrio::LOG_NOTICE );
1053 return 0;
1054}
1055
1056INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_sigmaPixThresh )( const pcf::IndiProperty &ipRecv )
1057{
1058 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_sigmaPixThresh, ipRecv );
1059
1060 float target;
1061
1062 if( indiTargetUpdate( m_indiP_sigmaPixThresh, target, ipRecv, true ) < 0 )
1063 {
1064 log<software_error>( { __FILE__, __LINE__ } );
1065 return -1;
1066 }
1067
1068 m_sigmaPixThresh = target;
1069
1070 log<text_log>( "set sigmaMaxThreshDown = " + std::to_string( m_sigmaPixThresh ), logPrio::LOG_NOTICE );
1071 return 0;
1072}
1073
1074INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_dx )( const pcf::IndiProperty &ipRecv )
1075{
1076 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_dx, ipRecv );
1077
1078 float target;
1079
1080 if( indiTargetUpdate( m_indiP_dx, target, ipRecv, true ) < 0 )
1081 {
1082 log<software_error>( { __FILE__, __LINE__ } );
1083 return -1;
1084 }
1085
1086 m_dx = target;
1087
1088 log<text_log>( "set dx = " + std::to_string( m_dx ), logPrio::LOG_NOTICE );
1089 return 0;
1090}
1091
1092INDI_NEWCALLBACK_DEFN( psfFit, m_indiP_dy )( const pcf::IndiProperty &ipRecv )
1093{
1094 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_dy, ipRecv );
1095
1096 float target;
1097
1098 if( indiTargetUpdate( m_indiP_dy, target, ipRecv, true ) < 0 )
1099 {
1100 log<software_error>( { __FILE__, __LINE__ } );
1101 return -1;
1102 }
1103
1104 m_dy = target;
1105
1106 log<text_log>( "set dy = " + std::to_string( m_dy ), logPrio::LOG_NOTICE );
1107 return 0;
1108}
1109
1110INDI_SETCALLBACK_DEFN( psfFit, m_indiP_fpsSource )( const pcf::IndiProperty &ipRecv )
1111{
1112 INDI_VALIDATE_CALLBACK_PROPS( m_indiP_fpsSource, ipRecv );
1113
1114 if( ipRecv.find( "current" ) != true ) // this isn't valid
1115 {
1116 return 0;
1117 }
1118
1119 std::lock_guard<std::mutex> guard( m_indiMutex );
1120
1121 realT fps = ipRecv["current"].get<float>();
1122
1123 if( fps != m_fps )
1124 {
1125
1126 m_fps = fps;
1127
1128 std::cerr << "got fps: " << m_fps << "\n";
1129
1130 shmimMonitorT::m_restart = true;
1131 }
1132
1133 return 0;
1134}
1135
1140
1142{
1143 return recordFGTimings( true );
1144}
1145
1146} // namespace app
1147} // namespace MagAOX
1148
1149#endif // psfFit_hpp
#define IMAGESTRUCT_FLOAT
The base-class for MagAO-X applications.
Definition MagAOXApp.hpp:73
void updateIfChanged(pcf::IndiProperty &p, const std::string &el, const T &newVal, pcf::IndiProperty::PropertyStateType ipState=pcf::IndiProperty::Ok)
Update an INDI property element value if it has changed.
stateCodes::stateCodeT state()
Get the current state code.
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
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.
uint8_t m_dataType
The ImageStreamIO type code.
bool m_getExistingFirst
If set to true by derivedT, any existing image will be grabbed and sent to processImage before waitin...
The MagAO-X PSF Fitter.
Definition psfFit.hpp:67
virtual int appLogic()
Implementation of the FSM for psfFit.
Definition psfFit.hpp:482
pcf::IndiProperty m_indiP_values
Definition psfFit.hpp:283
float m_dx
The offset in x to apply to non-skipped measurements.
Definition psfFit.hpp:149
psfFit()
Default c'tor.
Definition psfFit.hpp:325
int loadImageIntoStream(void *dest)
Implementation of the framegrabber loadImageIntoStream interface.
Definition psfFit.hpp:940
int reconfig()
Implementation of the framegrabber reconfig interface.
Definition psfFit.hpp:958
float m_mnx
The mean x coord over the stats time.
Definition psfFit.hpp:165
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
Definition psfFit.hpp:396
float realT
Floating point type in which to do all calculations.
Definition psfFit.hpp:95
INDI_NEWCALLBACK_DECL(psfFit, m_indiP_sigmaMaxThreshUp)
mx::sigproc::circularBufferIndex< float, cbIndexT > m_pcb
Circular buffer for max pixel (p=peak)
Definition psfFit.hpp:154
bool m_skipped
Indicates that the image failed quality control and this is a skip frame.
Definition psfFit.hpp:141
float m_sigmaMaxThreshDown
Definition psfFit.hpp:124
static constexpr bool c_frameGrabber_flippable
app:dev config to tell framegrabber these images can not be flipped
Definition psfFit.hpp:101
INDI_NEWCALLBACK_DECL(psfFit, m_indiP_dy)
uint16_t m_fitCircBuffMaxLength
Maximum length of the latency measurement circular buffers.
Definition psfFit.hpp:114
INDI_NEWCALLBACK_DECL(psfFit, m_indiP_dx)
float fps()
Implementation of the framegrabber fps interface.
Definition psfFit.hpp:243
pcf::IndiProperty m_indiP_dx
Definition psfFit.hpp:303
float m_mny
The mean y coord over the stats time.
Definition psfFit.hpp:167
float m_x
The current x coordinate.
Definition psfFit.hpp:143
float m_rmsp
The rms max pixel over the stats time.
Definition psfFit.hpp:163
std::vector< float > m_ycbD
Vector for doing calcs on y COL coords.
Definition psfFit.hpp:160
float m_rmsy
The rms y coord over the stats time.
Definition psfFit.hpp:168
INDI_NEWCALLBACK_DECL(psfFit, m_indiP_sigmaMaxThreshDown)
sem_t m_smSemaphore
Semaphore used to synchronize the fg thread and the sm thread.
Definition psfFit.hpp:224
dev::telemeter< psfFit > telemeterT
Definition psfFit.hpp:92
mx::sigproc::circularBufferIndex< float, cbIndexT > m_xcb
Circular buffer for x COL coords.
Definition psfFit.hpp:155
pcf::IndiProperty m_indiP_reset
Definition psfFit.hpp:285
dev::shmimMonitor< psfFit, darkShmimT > darkShmimMonitorT
The dark shmimMonitor type.
Definition psfFit.hpp:83
virtual void loadConfig()
Definition psfFit.hpp:414
pcf::IndiProperty m_indiP_dy
Definition psfFit.hpp:306
~psfFit() noexcept
D'tor, declared and defined for noexcept.
Definition psfFit.hpp:333
int acquireAndCheckValid()
Implementation of the framegrabber acquireAndCheckValid interface.
Definition psfFit.hpp:910
std::vector< float > m_pcbD
Vector for doing calcs on max pixel.
Definition psfFit.hpp:158
dev::frameGrabber< psfFit > frameGrabberT
Definition psfFit.hpp:89
int recordTelem(const telem_fgtimings *)
Definition psfFit.hpp:1141
pcf::IndiProperty m_indiP_sigmaPixThresh
Definition psfFit.hpp:300
std::mutex m_imageMutex
Definition psfFit.hpp:222
float m_fps
The frame rate from the source camera.
Definition psfFit.hpp:152
INDI_NEWCALLBACK_DECL(psfFit, m_indiP_deltaPixThresh)
float m_last_y
The previous y coordinate.
Definition psfFit.hpp:147
int allocate(const dev::shmimT &)
Definition psfFit.hpp:570
INDI_NEWCALLBACK_DECL(psfFit, m_indiP_statsTime)
float m_fitCircBuffMaxTime
Maximum time of the latency meaurement circular buffers.
Definition psfFit.hpp:116
pcf::IndiProperty m_indiP_deltaPixThresh
Definition psfFit.hpp:291
mx::improc::eigenImage< float > m_dark
Holds the dark image.
Definition psfFit.hpp:135
float m_rmsx
The rms x coord over the stats time.
Definition psfFit.hpp:166
pcf::IndiProperty m_indiP_fpsSource
Definition psfFit.hpp:309
INDI_NEWCALLBACK_DECL(psfFit, m_indiP_reset)
virtual void setupConfig()
Definition psfFit.hpp:337
virtual int appShutdown()
Shutdown the app.
Definition psfFit.hpp:559
dev::shmimMonitor< psfFit, refShmimT > refShmimMonitorT
The reference shmimMonitor type.
Definition psfFit.hpp:86
mx::improc::eigenImage< float > m_ref
Holds the reference image.
Definition psfFit.hpp:137
std::vector< float > m_xcbD
Vector for doing calcs on x COL coords.
Definition psfFit.hpp:159
pcf::IndiProperty m_indiP_statsTime
Definition psfFit.hpp:288
mx::sigproc::circularBufferIndex< float, cbIndexT > m_ycb
Circular buffer for y COL coords.
Definition psfFit.hpp:156
float m_last_x
The previous x coordinate.
Definition psfFit.hpp:144
float m_y
The current y coordinate.
Definition psfFit.hpp:146
float m_mnp
The mean max pixel over the stats time.
Definition psfFit.hpp:162
INDI_SETCALLBACK_DECL(psfFit, m_indiP_fpsSource)
virtual int appStartup()
Startup function.
Definition psfFit.hpp:419
bool m_updated
Indicates that the coordinates were updated was updated.
Definition psfFit.hpp:139
int configureAcquisition()
Implementation of the framegrabber configureAcquisition interface.
Definition psfFit.hpp:895
pcf::IndiProperty m_indiP_sigmaMaxThreshUp
Definition psfFit.hpp:294
float m_dy
The offset in y to apply to non-skipped measurements.
Definition psfFit.hpp:150
std::string m_fpsSource
Definition psfFit.hpp:111
int processImage(void *curr_src, const dev::shmimT &)
Definition psfFit.hpp:621
pcf::IndiProperty m_indiP_sigmaMaxThreshDown
Definition psfFit.hpp:297
mx::improc::eigenImage< float > m_image
Holds the raw image.
Definition psfFit.hpp:133
INDI_NEWCALLBACK_DECL(psfFit, m_indiP_sigmaPixThresh)
dev::shmimMonitor< psfFit > shmimMonitorT
The base shmimMonitor type.
Definition psfFit.hpp:80
friend class psfFit_test
Definition psfFit.hpp:69
int startAcquisition()
Implementation of the framegrabber startAcquisition interface.
Definition psfFit.hpp:905
#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_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.
const pcf::IndiProperty & ipRecv
std::unique_lock< std::mutex > lock(m_indiMutex)
Definition dm.hpp:24
static constexpr logPrioT LOG_NOTICE
A normal but significant condition.
static constexpr logPrioT LOG_INFO
Informational. The info log level is the lowest level recorded during normal operations.
#define SHMIMMONITORT_APP_STARTUP(SHMIMMONITORT)
Call shmimMonitorT::appStartup with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITOR_APP_SHUTDOWN
Call shmimMonitorT::appShutdown with error checking for shmimMonitor.
#define SHMIMMONITOR_APP_LOGIC
Call shmimMonitorT::appLogic with error checking for shmimMonitor.
#define SHMIMMONITORT_UPDATE_INDI(SHMIMMONITORT)
Call shmimMonitorT::updateINDI with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITOR_APP_STARTUP
Call shmimMonitorT::appStartup with error checking for shmimMonitor.
#define SHMIMMONITOR_LOAD_CONFIG(cfig)
Call shmimMonitorT::loadConfig with error checking for 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 SHMIMMONITOR_UPDATE_INDI
Call shmimMonitorT::updateINDI with error checking for shmimMonitor.
#define SHMIMMONITORT_LOAD_CONFIG(SHMIMMONITORT, cfig)
Call shmimMonitorT::loadConfig with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITOR_SETUP_CONFIG(cfig)
Call shmimMonitorT::setupConfig with error checking for shmimMonitor.
static std::string configSection()
Definition psfFit.hpp:33
static std::string indiPrefix()
Definition psfFit.hpp:38
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 indiPrefix()
Definition psfFit.hpp:51
static std::string configSection()
Definition psfFit.hpp:46
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.