API
 
Loading...
Searching...
No Matches
hoPredCtrl.hpp
Go to the documentation of this file.
1/** \file hoPredCtrl.hpp
2 * \brief The MagAO-X tweeter to woofer offloading manager
3 *
4 * \ingroup app_files
5 */
6
7#ifndef hoPredCtrl_hpp
8#define hoPredCtrl_hpp
9
10#include <iostream>
11#include <limits>
12#include <chrono>
13#include <thread>
14
15
16#include <mx/improc/eigenCube.hpp>
17#include <mx/improc/eigenImage.hpp>
18using namespace mx::improc;
19
20#include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
21#include "../../magaox_git_version.h"
22
23#include "predictive_controller.cuh"
24
25using namespace DDSPC;
26
27namespace MagAOX
28{
29namespace app
30{
31
33{
34 static std::string configSection()
35 {
36 return "darkShmim";
37 };
38
39 static std::string indiPrefix()
40 {
41 return "dark";
42 };
43};
44
45/** \defgroup hoPredCtrl Tweeter to Woofer Offloading
46 * \brief Monitors the averaged tweeter shape, and sends it to the woofer.
47 *
48 * <a href="../handbook/operating/software/apps/hoPredCtrl.html">Application Documentation</a>
49 *
50 * \ingroup apps
51 *
52 */
53
54/** \defgroup hoPredCtrl_files Tweeter to Woofer Offloading
55 * \ingroup hoPredCtrl
56 */
57
58/** MagAO-X application to control offloading the tweeter to the woofer.
59 *
60 * \ingroup hoPredCtrl
61 *
62 */
63class hoPredCtrl : public MagAOXApp<true>, public dev::shmimMonitor<hoPredCtrl>, public dev::shmimMonitor<hoPredCtrl,darkShmimT>
64{
65
66 //Give the test harness access.
67 friend class hoPredCtrl_test;
68
69 friend class dev::shmimMonitor<hoPredCtrl>;
71
72 //The base shmimMonitor type
74
75 //The dark shmimMonitor type
77
78 ///Floating point type in which to do all calculations.
79 typedef float realT;
80
81protected:
82
83 /** \name Configurable Parameters
84 *@{
85 */
86
87 // std::string m_twRespMPath;
88 // std::string m_dmChannel;
89 // float m_gain {0.1};
90 // float m_leak {0.0};
91 // float m_actLim {7.0}; ///< the upper limit on woofer actuator commands. default is 7.0.
92
93 ///@}
94
95 std::string m_pupilMaskFilename; // aol1_wfsmask.fits
96 std::string m_interaction_matrix_filename; // aol1_modesWFS.fits in cacao
97 std::string m_mapping_matrix_filename; // aol1_DMmodes.fits
98 std::string m_refWavefront_filename; // aol1_wfsref.fits
100
101 // std::string m_actuator_mask_filename; //
102
103 // IMAGE m_dmStream;
104 size_t m_pwfsWidth {0}; ///< The width of the image
105 size_t m_pwfsHeight {0}; ///< The height of the image.
106
107 size_t m_quadWidth {0}; ///< The width of the image
108 size_t m_quadHeight {0}; ///< The height of the image.
109
110 uint8_t m_pwfsDataType{0}; ///< The ImageStreamIO type code.
111 size_t m_pwfsTypeSize {0}; ///< The size of the type, in bytes.
112
113 unsigned long long duration;
114 unsigned long long iterations;
115
116 // The wavefront sensor variables
119
122
126
128
130
131 realT (*pwfs_pixget)(void *, size_t) {nullptr}; ///< Pointer to a function to extract the image data as our desired type realT.
132
133 // The dark image parameters
135 realT (*dark_pixget)(void *, size_t) {nullptr}; ///< Pointer to a function to extract the image data as our desired type realT.
136 bool m_darkSet {false};
137
138 // Predictive control parameters
142 int m_numHist; ///< The number of past states to use for the prediction
143 int m_numFut; ///< The number of future states to predict
144 realT m_gamma; ///< The forgetting factore (0, 1)
145
146 realT m_inv_covariance; ///< The starting point of the inverse covariance matrix
147 realT m_lambda; ///< The regularization parameter
148
149 // Integrator commands
153
154 DDSPC::PredictiveController* controller;
155
156 // Learning time
162
164
165 // Interaction for the DM
166 float* m_command;
168
169 // If true we can just use a mask to map the controlled subset of actuators to the 50x50 shmim.
170 // Otherwise we should use another matrix that maps mode coefficients to DM actuator patterns.
174
175 std::string m_dmChannel;
177 uint32_t m_dmWidth {0}; ///< The width of the image
178 uint32_t m_dmHeight {0}; ///< The height of the image.
179
180 uint8_t m_dmDataType{0}; ///< The ImageStreamIO type code.
181 size_t m_dmTypeSize {0}; ///< The size of the type, in bytes.
182
183 bool m_dmOpened {false};
184 bool m_dmRestart {false};
185
186 std::string savepath;
187
188 pcf::IndiProperty m_indiP_controlToggle;
189 pcf::IndiProperty m_indiP_predictorToggle;
191 pcf::IndiProperty m_indiP_reset_modelRequest;
192 pcf::IndiProperty m_indiP_reset_cleanRequest;
193
195
196 pcf::IndiProperty m_indiP_learningSteps;
197 pcf::IndiProperty m_indiP_learningIterations;
198 pcf::IndiProperty m_indiP_explorationRms;
199 pcf::IndiProperty m_indiP_explorationSteps;
201 pcf::IndiProperty m_indiP_zeroRequest;
202
203 pcf::IndiProperty m_indiP_saveRequest;
204 pcf::IndiProperty m_indiP_loadRequest;
205 pcf::IndiProperty m_indiP_timestamp;
206
207 // The control parameters
208 pcf::IndiProperty m_indiP_lambda;
209 pcf::IndiProperty m_indiP_clipval;
210 pcf::IndiProperty m_indiP_gamma;
211
212 // Integrator parameters
213 pcf::IndiProperty m_indiP_intgain;
214 pcf::IndiProperty m_indiP_intleak;
215
216 // pcf::IndiProperty m_indiP_inv_cov;
217
218 /*
219 TODO:
220 5) Create a Double variant? Use a typedef for the variables.
221 6) Create a GUI.
222 7) Update reconstruction matrix.
223 8) Update pupil mask.
224 9) Add a toggle to create an empty loop?
225 10) Save and load model.
226 11) Reset to loaded model.
227 */
228
229 // Control states
240
241
242 // Control parameters
250
254
255public:
256 /// Default c'tor.
257 hoPredCtrl();
258
259 /// D'tor, declared and defined for noexcept.
262
263 virtual void setupConfig();
264
265 /// Implementation of loadConfig logic, separated for testing.
266 /** This is called by loadConfig().
267 */
268 int loadConfigImpl( mx::app::appConfigurator & _config /**< [in] an application configuration from which to load values*/);
269
270 virtual void loadConfig();
271
272 /// Startup function
273 /**
274 *
275 */
276 virtual int appStartup();
277
278 /// Implementation of the FSM for hoPredCtrl.
279 /**
280 * \returns 0 on no critical error
281 * \returns -1 on an error requiring shutdown
282 */
283 virtual int appLogic();
284
285 /// Shutdown the app.
286 /**
287 *
288 */
289 virtual int appShutdown();
290
291 int allocate( const dev::shmimT & dummy /**< [in] tag to differentiate shmimMonitor parents.*/);
292 int processImage( void * curr_src, ///< [in] pointer to start of current frame.
293 const dev::shmimT & dummy ///< [in] tag to differentiate shmimMonitor parents.
294 );
295
296 int allocate( const darkShmimT & dummy /**< [in] tag to differentiate shmimMonitor parents.*/);
297
298 int processImage( void * curr_src, ///< [in] pointer to start of current frame.
299 const darkShmimT & dummy ///< [in] tag to differentiate shmimMonitor parents.
300 );
301
302 int zero();
303 int send_dm_command();
305 int set_pupil_mask(std::string pupil_mask_filename);
306
307 void save_state(){};
308
309protected:
310
311
312};
313
314inline
315hoPredCtrl::hoPredCtrl() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
316{
318 return;
319}
320
321inline
323{
326
327 config.add("parameters.calib_directory", "", "parameters.calib_directory", argType::Required, "parameters", "calib_directory", false, "string", "The path to the PyWFS pupil mask.");
328 config.add("parameters.pupil_mask", "", "parameters.pupil_mask", argType::Required, "parameters", "pupil_mask", false, "string", "The path to the PyWFS pupil mask.");
329 config.add("parameters.interaction_matrix", "", "parameters.interaction_matrix", argType::Required, "parameters", "interaction_matrix", false, "string", "The path to the PyWFS interaction matrix.");
330 config.add("parameters.mapping_matrix", "", "parameters.mapping_matrix", argType::Required, "parameters", "mapping_matrix", false, "string", "The path to the DM mapping matrix.");
331 config.add("parameters.act_mask", "", "parameters.act_mask", argType::Required, "parameters", "act_mask", false, "string", "The path to the PyWFS interaction matrix.");
332 config.add("parameters.reference_image", "", "parameters.reference_image", argType::Required, "parameters", "reference_image", false, "string", "The path to the PyWFS interaction matrix.");
333
334
335 config.add("parameters.Nhist", "", "parameters.Nhist", argType::Required, "parameters", "Nhist", false, "int", "The history length.");
336 config.add("parameters.Nfut", "", "parameters.Nfut", argType::Required, "parameters", "Nfut", false, "int", "The prediction horizon.");
337 config.add("parameters.gamma", "", "parameters.gamma", argType::Required, "parameters", "gamma", false, "float", "The prediction horizon.");
338 config.add("parameters.inv_covariance", "", "parameters.inv_covariance", argType::Required, "parameters", "inv_covariance", false, "float", "The prediction horizon.");
339 config.add("parameters.lambda", "", "parameters.lambda", argType::Required, "parameters", "lambda", false, "float", "The prediction horizon.");
340 config.add("parameters.clip_val", "", "parameters.clip_val", argType::Required, "parameters", "clip_val", false, "float", "The update clip value.");
341
342 //
343 config.add("parameters.learning_steps", "", "parameters.learning_steps", argType::Required, "parameters", "learning_steps", false, "int", "The update clip value.");
344 config.add("parameters.learning_iterations", "", "parameters.learning_iterations", argType::Required, "parameters", "learning_iterations", false, "int", "The amount of learning cycles.");
345 config.add("parameters.exploration_steps", "", "parameters.exploration_steps", argType::Required, "parameters", "exploration_steps", false, "int", "The update clip value.");
346 config.add("parameters.exploration_rms", "", "parameters.exploration_rms", argType::Required, "parameters", "exploration_rms", false, "float", "The update clip value.");
347
348 // Read in the learning parameters as a vector.
349 // config.add("parameters.exploration_steps", "", "parameters.exploration_steps", argType::Required, "parameters", "exploration_steps", false, "vector<int>", "The number of steps for each training iteration.");
350 // config.add("parameters.exploration_rms", "", "parameters.exploration_rms", argType::Required, "parameters", "exploration_rms", false, "vector<double>", "The rms for each training iteration.");
351 // config.add("parameters.exploration_lambda", "", "parameters.exploration_lambda", argType::Required, "parameters", "exploration_lambda", false, "vector<double>", "The regularization for each training iteration.");
352
353 //
354 config.add("parameters.channel", "", "parameters.channel", argType::Required, "parameters", "channel", false, "string", "The DM channel to control.");
355
356 // The integrator parameters
357 config.add("integrator.gain", "", "integrator.gain", argType::Required, "integrator", "gain", false, "float", "The integrator gain value.");
358 config.add("integrator.leakage", "", "integrator.leakage", argType::Required, "integrator", "leakage", false, "float", "The integrator leakage.");
359}
360
361inline
362int hoPredCtrl::loadConfigImpl( mx::app::appConfigurator & _config )
363{
364
367
368 // The integrator control parameters
369 _config(m_intgain, "integrator.gain");
370 _config(m_intleak, "integrator.leakage");
371
372 // Calibration files
373 std::string calibration_directory;
374 _config(calibration_directory, "parameters.calib_directory");
375
376 _config(m_pupilMaskFilename, "parameters.pupil_mask");
378 std::cout << m_pupilMaskFilename << std::endl;
379
380 _config(m_interaction_matrix_filename, "parameters.interaction_matrix");
382 std::cout << m_interaction_matrix_filename << std::endl;
383
384 _config(m_mapping_matrix_filename, "parameters.mapping_matrix");
386 std::cout << m_mapping_matrix_filename << std::endl;
387
388 _config(m_refWavefront_filename, "parameters.reference_image");
390 std::cout << m_refWavefront_filename << std::endl;
391
392 // Controller parameters
393 _config(m_numHist, "parameters.Nhist");
394 std::cout << "Nhist="<< m_numHist << std::endl;
395 _config(m_numFut, "parameters.Nfut");
396 std::cout << "Nfut="<< m_numFut << std::endl;
397
398 _config(m_gamma, "parameters.gamma");
399 std::cout << "gamma="<< m_gamma << std::endl;
400 _config(m_inv_covariance, "parameters.inv_covariance");
401 std::cout << "inv_covariance="<< m_inv_covariance << std::endl;
402 _config(m_lambda, "parameters.lambda");
403 std::cout << "lambda="<< m_lambda << std::endl;
404 _config(m_clip_val, "parameters.clip_val");
405 std::cout << "clip_val="<< m_clip_val << std::endl;
406
407 // The learning parameters
408 _config(m_exploration_steps, "parameters.exploration_steps");
409 _config(m_learning_steps, "parameters.learning_steps");
411 _config(m_learning_iterations, "parameters.learning_iterations");
412
413 _config(m_exploration_rms, "parameters.exploration_rms");
414 std::cout << "Nexplore:: "<< m_exploration_steps << " with " << m_exploration_rms << " rms." << std::endl;
415
416 _config(m_dmChannel, "parameters.channel");
417 std::cout << "Open DM tweeter channel at " << m_dmChannel << std::endl;
418 std::cout << "Done reading config Impl." << std::endl;
419
420 return 0;
421}
422
423inline
425{
426 loadConfigImpl(config);
427}
428
429inline
431{
432
434 {
435 return log<software_error,-1>({__FILE__, __LINE__});
436 }
437
439 {
440 return log<software_error,-1>({__FILE__, __LINE__});
441 }
442
443 createStandardIndiToggleSw( m_indiP_controlToggle, "control", "Control State", "Loop Controls");
445
446 createStandardIndiRequestSw( m_indiP_reset_bufferRequest, "reset_buffer", "Reset the data buffers", "Loop Controls");
448
449 createStandardIndiRequestSw( m_indiP_reset_modelRequest, "reset_model", "Reset the RLS model", "Loop Controls");
451
452 createStandardIndiRequestSw( m_indiP_reset_cleanRequest, "clean", "Clean the complete model.", "Loop Controls");
454
455 createStandardIndiRequestSw( m_indiP_updateControllerRequest, "calc_controller", "Update the controller.", "Loop Controls");
457
458 createStandardIndiRequestSw( m_indiP_reset_exploreRequest, "reset_exploration", "Reset the exploration model", "Loop Controls");
460
461 createStandardIndiRequestSw( m_indiP_zeroRequest, "zero", "Zero the dm", "Loop Controls");
463
464 createStandardIndiRequestSw( m_indiP_saveRequest, "save", "Save the controller", "Loop Controls");
466
467 createStandardIndiRequestSw( m_indiP_loadRequest, "load", "Load the controller", "Loop Controls");
469
470 createStandardIndiNumber<uint64_t>( m_indiP_timestamp, "timestamp", -1, 20000000000000000, 1, "%d", "Timestamp", "Loading the controller");
472
473 createStandardIndiNumber<int>( m_indiP_learningSteps, "learning_steps", -1, 200000, 1, "%d", "Learning Steps", "Learning control");
475
476 createStandardIndiNumber<int>( m_indiP_learningSteps, "learning_steps", -1, 200000, 1, "%d", "Learning Steps", "Learning control");
478
479 createStandardIndiNumber<int>( m_indiP_learningIterations, "learning_iterations", -1, 200000, 1, "%d", "Learning iterations", "Learning control");
481
482 createStandardIndiNumber<float>( m_indiP_explorationRms, "exploration_rms", 0.0, 1.0, 0.00001, "%0.4f", "Learning Steps", "Learning control");
484
485 createStandardIndiNumber<float>( m_indiP_explorationSteps, "exploration_steps", 0, 200000, 1, "%d", "Exploration Steps", "Learning control");
487
488 createStandardIndiNumber<float>( m_indiP_gamma, "gamma", 0, 1.0, 0.0001, "%0.3f", "Forgetting parameter", "Learning control");
490
491 createStandardIndiNumber<float>( m_indiP_lambda, "lambda", 0, 1000.0, 0.0001, "%0.3f", "Regularization", "Learning control");
493
494 createStandardIndiNumber<float>( m_indiP_clipval, "clipval", 0, 1000.0, 0.0001, "%0.3f", "Regularization", "Learning control");
496
497 // createStandardIndiNumber<int>( m_indiP_inv_cov, "lambda", 0, 1e8, 0.1, "%0.3f", "Inverse Covariance", "Learning control");
498 // registerIndiPropertyNew( m_indiP_inv_cov, INDI_NEWCALLBACK(m_indiP_inv_cov) );
499
500 createStandardIndiToggleSw( m_indiP_predictorToggle, "use_predictor", "Choose controller", "Loop Controls");
502
503 createStandardIndiNumber<float>( m_indiP_intgain, "intgain", 0, 1.0, 0.0001, "%0.3f", "Integrator gain", "Learning control");
505
506 createStandardIndiNumber<float>( m_indiP_intleak, "intleak", 0, 1.0, 0.0001, "%0.3f", "Integrator gain", "Learning control");
508
510
511 return 0;
512}
513
514inline
516{
517 if( shmimMonitorT::appLogic() < 0)
518 {
519 return log<software_error,-1>({__FILE__,__LINE__});
520 }
521
522
523 if( darkMonitorT::appLogic() < 0)
524 {
525 return log<software_error,-1>({__FILE__,__LINE__});
526 }
527
528 std::unique_lock<std::mutex> lock(m_indiMutex);
529
531 {
533 }
534
536 {
538 }
539
540 // Send updates to indi if the values changed due to changes caused by software
541
549
552 // updateIfChanged(m_indiP_inv_cov, "current", m_inv_covariance);
553
555 updateSwitchIfChanged(m_indiP_controlToggle, "toggle", pcf::IndiElement::On, INDI_OK);
556 }else{
557 updateSwitchIfChanged(m_indiP_controlToggle, "toggle", pcf::IndiElement::Off, INDI_IDLE);
558 }
559
561 updateSwitchIfChanged(m_indiP_predictorToggle, "toggle", pcf::IndiElement::On, INDI_OK);
562 }else{
563 updateSwitchIfChanged(m_indiP_predictorToggle, "toggle", pcf::IndiElement::Off, INDI_IDLE);
564 }
565
566
567 return 0;
568}
569
570inline
572{
574
576
577 m_shaped_command.setZero();
579 delete controller;
580
581 if(m_temp_command){
582 delete m_temp_command;
583 }
584
585 return 0;
586}
587
588inline
590{
591 static_cast<void>(dummy); //be unused
592
593 // Or get from config
595
596 // Wavefront sensor setup
599 std::cout << "Width " << m_pwfsWidth << std::endl;
600
603 std::cout << "Height " << m_pwfsHeight << std::endl;
604
606 std::cout << "Start reading in calibration files\n";
607
608 // Read in the pupil mask
609 mx::fits::fitsFile<realT> ff;
611
612 //
614 // std::cout << temp_matrix.shape() << "\n";
615 std::cerr << "Read a " << temp_matrix.rows() << " x " << temp_matrix.cols() << " x " << temp_matrix.planes() << " interaction matrix.\n";
616 m_interaction_matrix = temp_matrix.asVectors().matrix().transpose().array();
617
618 //
619 std::cerr << "Read a " << m_interaction_matrix.rows() << " x " << m_interaction_matrix.cols() << " interaction matrix.\n";
621
622 bool use_cacao_calib = true;
623 if(use_cacao_calib){
624
625 for(int row_i = 0; row_i < m_interaction_matrix.rows(); row_i++ ){
626
627 realT norm = 0;
628 for(int col_i = 0; col_i < m_interaction_matrix.cols(); col_i++ ){
629 if(col_i==(25*30))
630 std::cout << m_interaction_matrix(row_i, col_i) << std::endl;
631
633 }
634
635 std::cout << "Norm for mode " << row_i << " " << norm << std::endl;
636
637
638 for(int col_i = 0; col_i < m_interaction_matrix.cols(); col_i++ ){
640
641 if(col_i==(25*30))
642 std::cout << m_interaction_matrix(row_i, col_i) << std::endl;
643
644 //
645 }
646
647 realT test_norm = 0.0;
648 for(int col_i = 0; col_i < m_interaction_matrix.cols(); col_i++ ){
650 }
651 std::cout << "Test Norm for mode " << row_i << " " << test_norm << std::endl;
652 }
653
654 }
655
656 // Read in the reference image
658 std::cerr << "Read a " << m_refWavefront.rows() << " x " << m_refWavefront.cols() << " reference image.\n";
659
660 // Read in the pupil mask
662 m_mapping_matrix = temp_matrix.asVectors();
663
664 std::cerr << "Read a " << m_mapping_matrix.rows() << " x " << m_mapping_matrix.cols() << " mapping matrix.\n";
666
667 m_temp_command = new float[m_numVoltages];
668 for(int i = 0; i < m_numVoltages; ++i)
669 m_temp_command[i] = 0.001;
671 std::cerr << "Initialized temp command.\n";
672
673 // Allocate the DM
674 if(m_dmOpened){
676 }
677
678 m_dmOpened = false;
679 m_dmRestart = false; //Set this up front, since we're about to restart.
680 use_actuators = true;
681
682 if( ImageStreamIO_openIm(&m_dmStream, m_dmChannel.c_str()) == 0){
683 if(m_dmStream.md[0].sem < 10){
685 }else{
686 m_dmOpened = true;
687 }
688 }
689
690 if(!m_dmOpened){
691 // log<software_error>({__FILE__, __LINE__, m_dmChannel + " not opened."});
692
693 log<text_log>( m_dmChannel + " not opened.", logPrio::LOG_NOTICE);
694 return -1;
695 }else{
696 m_dmWidth = m_dmStream.md->size[0];
697 m_dmHeight = m_dmStream.md->size[1];
698
699 m_dmDataType = m_dmStream.md->datatype;
700 m_dmTypeSize = sizeof(float);
701
702 log<text_log>( "Opened " + m_dmChannel + " " + std::to_string(m_dmWidth) + " x " + std::to_string(m_dmHeight) + " with data type: " + std::to_string(m_dmDataType), logPrio::LOG_NOTICE);
704 std::cout << m_shaped_command.rows() << " x " << m_shaped_command.cols() << '\n';
705 m_shaped_command.setZero();
707 }
708
709 // Controller setup
711 controller->set_interaction_matrix(m_interaction_matrix.data());
712 controller->set_mapping_matrix(m_mapping_matrix.data());
713 std::cerr << "Finished intializing the controller.\n";
714
715 // mx::fits::fitsFile<realT> ff2;
716 // ff2.read(m_illuminated_actuators_mask, m_actuator_mask_filename);
717 // std::cerr << "Read a " << m_illuminated_actuators_mask.rows() << " x " << m_illuminated_actuators_mask.cols() << " actuator mask.\n";
718
719 controller->create_exploration_buffer(m_exploration_rms, m_exploration_steps);
720 std::cerr << "Initialized exploration buffer.\n";
721
722 //Initialize dark image if not correct size.
725 m_darkImage.setZero();
726 m_darkSet = false;
727 }
728
729 duration = 0;
730 iterations = 0;
731 m_is_closed_loop = false;
732
734 controller->controller->set_integrator(m_use_predictive_control, m_intgain, m_intleak);
735 std::cerr << "Finished setup.\n";
736
737 average_pupil_intensity = -100000.0;
738
739 savepath = "/data/users/xsup/PredCtrlData/";
740 return 0;
741}
742
743inline
744int hoPredCtrl::processImage( void * curr_src, const dev::shmimT & dummy )
745{
746
747 static_cast<void>(dummy); //be unused
748 auto start = std::chrono::steady_clock::now();
749
750 Eigen::Map<eigenImage<unsigned short>> pwfsIm( static_cast<unsigned short *>(curr_src), m_pwfsHeight, m_pwfsWidth);
751 // Calculate the norm
752 realT pwfs_norm = 0;
753
755 // realT mean_value = 0;
756 realT Ia = 0, Ib = 0, Ic = 0, Id = 0;
757 realT total_norm = 0;
758 size_t number_of_pixels = 0;
759
760 size_t ki = 0;
761 for(uint32_t col_i=0; col_i < m_quadWidth; ++col_i){
763 // Select the pixel from the correct quadrant and subtract dark
768
769 // Calculate the norm
770 // TODO: Add an exponential learning to the PWFS norm?
771 pwfs_norm = Ia + Ib + Ic + Id;
772
773 // Take all linear combinations of the measurements and concatenate in vector
774 if(m_pupilMask(row_i, col_i) > 0.5){
775 m_measurementVector(ki, 0) = (Ia - Ib + Ic - Id) / pwfs_norm;
778 ++ki;
780 }
781 }
782 }
783
784 total_norm /= ki;
785
786 }else{
787
788 for(uint32_t col_i=0; col_i < m_pwfsWidth; ++col_i){
791 }
792 }
793
794 // Extract the illuminated pixels.
795 size_t ki = 0;
796 for(uint32_t col_i=0; col_i < m_pwfsWidth; ++col_i){
798 // Subtract a dark and the reference.
800 ++ki;
801 }
802 }
803
804 }
805
806 controller->add_measurement(m_measurementVector.data());
807
808 // Okay reconstruction matrix is used correctly!
809 // The error is now in the slope measurement.
810 if( m_is_closed_loop ){
811 m_command = controller->get_command(m_clip_val);
812
813 // This works!
814 if(use_actuators){
816 }
818
819 // Only learn if we have a predictor
821
822 // If -1 always learn, otherwise learn for N steps
823 if(m_learning_counter == -1){
824
825 controller->update_predictor();
826 controller->update_controller();
827
828 }else if(m_learning_counter > 0){
829
830 controller->update_predictor();
831 controller->update_controller();
833
834 }
835
839
840 m_lambda /= 10.0;
841
842 controller->set_zero(); // set current control to zero
843 zero(); // set the DM shape to zero
844 controller->create_exploration_buffer(m_exploration_rms, m_exploration_steps); // Make a new buffer
845 controller->set_new_regularization(m_lambda); // set a new regularization
846 controller->reset_data_buffer(); // remove the history
847 }
848
849
850 }
851
852 }
853
854 auto end = std::chrono::steady_clock::now();
855
856
857 if(iterations == 0){
858 duration = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
859 }else{
860 duration = 0.95 * duration + 0.05 * std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
861 }
862 iterations += 1;
863
864 if(iterations % 10000 == 0){
865 // std::cout << "PWFS NORM: " << pwfs_norm << std::endl;
866 // std::cout << m_measurementVector(25*30,0)/1e-5 << " " << m_measurementVector(25*30+1,0)/1e-5 << " " << m_measurementVector(25*30+2,0)/1e-5 << std::endl;
867 // controller->m_measurement->print(true);
868 std::cout << "elapsed " << (double)duration << " us." << std::endl;
869 std::cout << '\n';
870 }
871
872 return 0;
873}
874
875inline
876int hoPredCtrl::set_pupil_mask(std::string pupil_mask_filename){
877/*
878 This function reads in the filename to create a pupil mask and to initialize the measurement vector.
879*/
880
881 // Read in the pupil mask
882 mx::fits::fitsFile<realT> ff;
884 std::cerr << "Read a " << m_pupilMask.rows() << " x " << m_pupilMask.cols() << " matrix.\n";
885
886 // Count the number of pixels that are used for the wavefront sensing
887 realT * data = m_pupilMask.data();
889
892 }else{
893 for(size_t nn=0; nn < m_pupilMask.rows() * m_pupilMask.cols(); ++nn){
894 if(data[nn] > 0.5)
896 }
898 }
899
900 std::cout << "Number of illuminated pixels :: " << m_illuminatedPixels << std::endl;
901 std::cout << "Measurement vector size :: " << m_measurement_size << std::endl;
902
903 // Create the measurement vector
905 m_measurementVector.setZero();
906
907 return 0;
908}
909
910
911inline
913{
914
915 static_cast<void>(dummy); //be unused
916
917 m_darkSet = false;
918
920
922
923 if(dark_pixget == nullptr)
924 {
925 log<software_error>({__FILE__, __LINE__, "bad data type"});
926 return -1;
927 }
928 std::cout << "Allocated dark frames stuff. \n";
929
930
931 return 0;
932}
933
934inline
935int hoPredCtrl::processImage( void * curr_src,
936 const darkShmimT & dummy
937 )
938{
939
940 static_cast<void>(dummy); //be unused
941
942 realT * data = m_darkImage.data();
943
945 {
946 //data[nn] = *( (int16_t * ) (curr_src + nn*shmimMonitorT::m_dmDataType));
947 data[nn] = dark_pixget(curr_src, nn);
948 }
949
950 m_darkSet = true;
951
952
953 return 0;
954}
955
956
957inline
959{
960
961 m_shaped_command.setZero();
963 return 0;
964
965}
966
967inline
969
970 // Convert the actuators modes into a 50x50 image.
971 /*
972 This function maps the command vector to a masked 2D image. A mapping is implicitely assumed due to the way the array is accessed.
973 */
974
975
976 // The new output of the controller is a nact length vector. So this can be replaced by a single copy statement.
977 // For now let's keep the dumb copy.
978 int ki = 0;
979 for(uint32_t col_i=0; col_i < m_dmHeight; ++col_i){
980 for(uint32_t row_i=0; row_i < m_dmHeight; ++row_i){
982 ki += 1;
983 }
984 }
985
986
987 return 0;
988}
989
990inline
992 // Check if processImage is running
993 // while(m_dmStream.md[0].write == 1);
994
995 m_dmStream.md[0].write = 1;
996 memcpy(m_dmStream.array.raw, m_shaped_command.data(), 2500 * sizeof(float));
997 m_dmStream.md[0].cnt0++;
998 m_dmStream.md[0].write = 0;
999
1001
1002 // log<text_log>("zeroed", logPrio::LOG_NOTICE);W
1003 return 0;
1004}
1005
1006INDI_NEWCALLBACK_DEFN(hoPredCtrl, m_indiP_learningSteps )(const pcf::IndiProperty &ipRecv)
1007{
1008 if(ipRecv.getName() != m_indiP_learningSteps.getName())
1009 {
1010 log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1011 return -1;
1012 }
1013
1014 int current = -1;
1015 int target = -1;
1016
1017 if(ipRecv.find("current"))
1018 {
1019 current = ipRecv["current"].get<int>();
1020 }
1021
1022 if(ipRecv.find("target"))
1023 {
1024 target = ipRecv["target"].get<int>();
1025 }
1026
1027 if(target == -1) target = current;
1028
1029 if(target == -1)
1030 {
1031 return 0;
1032 }
1033
1034 std::lock_guard<std::mutex> guard(m_indiMutex);
1035
1036 m_learning_counter = target;
1037 m_learning_steps = target;
1038
1039 updateIfChanged(m_indiP_learningSteps, "target", m_learning_counter);
1040
1041 return 0;
1042}
1043
1044INDI_NEWCALLBACK_DEFN(hoPredCtrl, m_indiP_learningIterations )(const pcf::IndiProperty &ipRecv)
1045{
1046 if(ipRecv.getName() != m_indiP_learningIterations.getName())
1047 {
1048 log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1049 return -1;
1050 }
1051
1052 int current = -1;
1053 int target = -1;
1054
1055 if(ipRecv.find("current"))
1056 {
1057 current = ipRecv["current"].get<int>();
1058 }
1059
1060 if(ipRecv.find("target"))
1061 {
1062 target = ipRecv["target"].get<int>();
1063 }
1064
1065 if(target == -1) target = current;
1066
1067 if(target == -1)
1068 {
1069 return 0;
1070 }
1071
1072 std::lock_guard<std::mutex> guard(m_indiMutex);
1073
1074 m_learning_iterations = target;
1075
1076 updateIfChanged(m_indiP_learningIterations, "target", m_learning_iterations);
1077
1078 return 0;
1079}
1080
1081INDI_NEWCALLBACK_DEFN(hoPredCtrl, m_indiP_explorationRms )(const pcf::IndiProperty &ipRecv)
1082{
1083 if(ipRecv.getName() != m_indiP_explorationRms.getName())
1084 {
1085 log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1086 return -1;
1087 }
1088
1089 float current = -1;
1090 float target = -1;
1091
1092 if(ipRecv.find("current"))
1093 {
1094 current = ipRecv["current"].get<float>();
1095 }
1096
1097 if(ipRecv.find("target"))
1098 {
1099 target = ipRecv["target"].get<float>();
1100 }
1101
1102 if(target == -1) target = current;
1103
1104 if(target == -1)
1105 {
1106 return 0;
1107 }
1108
1109 std::lock_guard<std::mutex> guard(m_indiMutex);
1110
1111 m_exploration_rms = target;
1112 std::cout << "New expl. rms: " << m_exploration_rms << "\n";
1113
1114 updateIfChanged(m_indiP_explorationRms, "target", m_exploration_rms);
1115
1116 return 0;
1117}
1118
1119INDI_NEWCALLBACK_DEFN(hoPredCtrl, m_indiP_explorationSteps )(const pcf::IndiProperty &ipRecv)
1120{
1121 if(ipRecv.getName() != m_indiP_explorationSteps.getName())
1122 {
1123 log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1124 return -1;
1125 }
1126
1127 float current = -1;
1128 float target = -1;
1129
1130 if(ipRecv.find("current"))
1131 {
1132 current = ipRecv["current"].get<float>();
1133 }
1134
1135 if(ipRecv.find("target"))
1136 {
1137 target = ipRecv["target"].get<float>();
1138 }
1139
1140 if(target == -1) target = current;
1141
1142 if(target == -1)
1143 {
1144 return 0;
1145 }
1146
1147 std::lock_guard<std::mutex> guard(m_indiMutex);
1148
1149 m_exploration_steps = target;
1150
1151 updateIfChanged(m_indiP_explorationSteps, "target", m_exploration_steps);
1152
1153 return 0;
1154}
1155
1156INDI_NEWCALLBACK_DEFN(hoPredCtrl, m_indiP_lambda )(const pcf::IndiProperty &ipRecv)
1157{
1158 if(ipRecv.getName() != m_indiP_lambda.getName()){
1159 log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1160 return -1;
1161 }
1162
1163 float current = -1;
1164 float target = -1;
1165
1166 if(ipRecv.find("current"))
1167 current = ipRecv["current"].get<float>();
1168
1169 if(ipRecv.find("target"))
1170 target = ipRecv["target"].get<float>();
1171
1172 if(target == -1) target = current;
1173
1174 if(target == -1)
1175 return 0;
1176
1177 std::lock_guard<std::mutex> guard(m_indiMutex);
1178 if(!m_is_closed_loop){
1179 m_lambda = target;
1180 controller->set_new_regularization(m_lambda);
1181 updateIfChanged(m_indiP_lambda, "target", m_lambda);
1182 }else{
1183 log<text_log>("Lambda not changed. Loop is still running.", logPrio::LOG_NOTICE);
1184 }
1185
1186 return 0;
1187}
1188
1189INDI_NEWCALLBACK_DEFN(hoPredCtrl, m_indiP_clipval )(const pcf::IndiProperty &ipRecv)
1190{
1191 if(ipRecv.getName() != m_indiP_clipval.getName()){
1192 log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1193 return -1;
1194 }
1195
1196 float current = -1;
1197 float target = -1;
1198
1199 if(ipRecv.find("current"))
1200 current = ipRecv["current"].get<float>();
1201
1202 if(ipRecv.find("target"))
1203 target = ipRecv["target"].get<float>();
1204
1205 if(target == -1) target = current;
1206
1207 if(target == -1)
1208 return 0;
1209
1210 std::lock_guard<std::mutex> guard(m_indiMutex);
1211 if(!m_is_closed_loop){
1212 m_clip_val = target;
1213 updateIfChanged(m_indiP_clipval, "target", m_clip_val);
1214 }else{
1215 log<text_log>("Clip value not changed. Loop is still running.", logPrio::LOG_NOTICE);
1216 }
1217
1218 return 0;
1219}
1220
1221INDI_NEWCALLBACK_DEFN(hoPredCtrl, m_indiP_gamma )(const pcf::IndiProperty &ipRecv)
1222{
1223 if(ipRecv.getName() != m_indiP_gamma.getName()){
1224 log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1225 return -1;
1226 }
1227
1228 float current = -1;
1229 float target = -1;
1230
1231 if(ipRecv.find("current"))
1232 current = ipRecv["current"].get<float>();
1233
1234 if(ipRecv.find("target"))
1235 target = ipRecv["target"].get<float>();
1236
1237 if(target == -1) target = current;
1238
1239 if(target == -1)
1240 return 0;
1241
1242 std::lock_guard<std::mutex> guard(m_indiMutex);
1243
1244 if(!m_is_closed_loop){
1245 m_gamma = target;
1246
1247 controller->set_new_gamma(m_gamma);
1248 updateIfChanged(m_indiP_gamma, "target", m_gamma);
1249 }else{
1250 log<text_log>("Gamma value not changed. Loop is still running.", logPrio::LOG_NOTICE);
1251 }
1252
1253 return 0;
1254}
1255
1256INDI_NEWCALLBACK_DEFN(hoPredCtrl, m_indiP_intgain )(const pcf::IndiProperty &ipRecv)
1257{
1258 if(ipRecv.getName() != m_indiP_intgain.getName()){
1259 log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1260 return -1;
1261 }
1262
1263 float current = -1;
1264 float target = -1;
1265
1266 if(ipRecv.find("current"))
1267 current = ipRecv["current"].get<float>();
1268
1269 if(ipRecv.find("target"))
1270 target = ipRecv["target"].get<float>();
1271
1272 if(target == -1) target = current;
1273
1274 if(target == -1)
1275 return 0;
1276
1277 std::lock_guard<std::mutex> guard(m_indiMutex);
1278
1279
1280 m_intgain = target;
1281 controller->controller->set_integrator(m_use_predictive_control, m_intgain, m_intleak);
1282 updateIfChanged(m_indiP_intgain, "target", m_intgain);
1283
1284 // if(!m_is_closed_loop){
1285 // }else{
1286 // log<text_log>("Integrator gain value not changed. Loop is still running.", logPrio::LOG_NOTICE);
1287 // }
1288
1289 return 0;
1290}
1291
1292INDI_NEWCALLBACK_DEFN(hoPredCtrl, m_indiP_intleak )(const pcf::IndiProperty &ipRecv)
1293{
1294 if(ipRecv.getName() != m_indiP_intleak.getName()){
1295 log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1296 return -1;
1297 }
1298
1299 float current = -1;
1300 float target = -1;
1301
1302 if(ipRecv.find("current"))
1303 current = ipRecv["current"].get<float>();
1304
1305 if(ipRecv.find("target"))
1306 target = ipRecv["target"].get<float>();
1307
1308 if(target == -1) target = current;
1309
1310 if(target == -1)
1311 return 0;
1312
1313 std::lock_guard<std::mutex> guard(m_indiMutex);
1314
1315
1316 m_intleak = target;
1317 controller->controller->set_integrator(m_use_predictive_control, m_intgain, m_intleak);
1318 updateIfChanged(m_indiP_intleak, "target", m_intleak);
1319
1320 // if(!m_is_closed_loop){
1321 // }else{
1322 // log<text_log>("Integrator leakage value not changed. Loop is still running.", logPrio::LOG_NOTICE);
1323 // }
1324
1325 return 0;
1326}
1327
1328
1329INDI_NEWCALLBACK_DEFN(hoPredCtrl, m_indiP_timestamp )(const pcf::IndiProperty &ipRecv)
1330{
1331 if(ipRecv.getName() != m_indiP_timestamp.getName()){
1332 log<software_error>({__FILE__,__LINE__, "wrong INDI property received."});
1333 return -1;
1334 }
1335
1336 uint64_t current = -1;
1337 uint64_t target = -1;
1338
1339 if(ipRecv.find("current"))
1340 current = ipRecv["current"].get<uint64_t>();
1341
1342 if(ipRecv.find("target"))
1343 target = ipRecv["target"].get<uint64_t>();
1344
1345 if(target == -1) target = current;
1346
1347 if(target == -1)
1348 return 0;
1349
1350 std::lock_guard<std::mutex> guard(m_indiMutex);
1351
1352 loading_timestamp = target;
1353 updateIfChanged(m_indiP_timestamp, "target", loading_timestamp);
1354
1355 return 0;
1356}
1357
1358
1359INDI_NEWCALLBACK_DEFN(hoPredCtrl, m_indiP_controlToggle )(const pcf::IndiProperty &ipRecv)
1360{
1361 if(ipRecv.getName() != m_indiP_controlToggle.getName())
1362 {
1363 log<software_error>({__FILE__, __LINE__, "invalid indi property received"});
1364 return -1;
1365 }
1366
1367 //switch is toggled to on
1368 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On)
1369 {
1370 if(!m_is_closed_loop) //not offloading so change
1371 {
1372 // m_woofer.setZero(); //always zero when offloading starts
1373 // log<text_log>("zeroed", logPrio::LOG_NOTICE);
1374 // m_offloading = true;
1375 m_is_closed_loop = true;
1376 log<text_log>("started closed-loop operation", logPrio::LOG_NOTICE);
1377 updateSwitchIfChanged(m_indiP_controlToggle, "toggle", pcf::IndiElement::On, INDI_BUSY);
1378
1379 }
1380 return 0;
1381 }
1382
1383 //switch is toggle to off
1384 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::Off)
1385 {
1386 if(m_is_closed_loop) //offloading so change it
1387 {
1388 m_is_closed_loop = false;
1389 log<text_log>("stopped closed-loop operation", logPrio::LOG_NOTICE);
1390 updateSwitchIfChanged(m_indiP_controlToggle, "toggle", pcf::IndiElement::Off, INDI_IDLE);
1391 }
1392 return 0;
1393 }
1394
1395 return 0;
1396}
1397
1398INDI_NEWCALLBACK_DEFN(hoPredCtrl, m_indiP_predictorToggle )(const pcf::IndiProperty &ipRecv)
1399{
1400 if(ipRecv.getName() != m_indiP_predictorToggle.getName())
1401 {
1402 log<software_error>({__FILE__, __LINE__, "invalid indi property received"});
1403 return -1;
1404 }
1405
1406 //switch is toggled to on
1407 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::On)
1408 {
1409 m_use_predictive_control = true;
1410 controller->controller->set_integrator(m_use_predictive_control, m_intgain, m_intleak);
1411 log<text_log>("Switched to predictive control.", logPrio::LOG_NOTICE);
1412 updateSwitchIfChanged(m_indiP_predictorToggle, "toggle", pcf::IndiElement::On, INDI_BUSY);
1413 return 0;
1414 }
1415
1416 //switch is toggled to off
1417 if( ipRecv["toggle"].getSwitchState() == pcf::IndiElement::Off)
1418 {
1419 if(!m_is_closed_loop)
1420 {
1421 m_use_predictive_control = false;
1422 controller->controller->set_integrator(m_use_predictive_control, m_intgain, m_intleak);
1423 log<text_log>("Switched to integrator.", logPrio::LOG_NOTICE);
1424 updateSwitchIfChanged(m_indiP_predictorToggle, "toggle", pcf::IndiElement::Off, INDI_IDLE);
1425 }
1426 return 0;
1427 }
1428
1429 return 0;
1430}
1431
1432INDI_NEWCALLBACK_DEFN(hoPredCtrl, m_indiP_reset_bufferRequest )(const pcf::IndiProperty &ipRecv)
1433{
1434 if(ipRecv.getName() != m_indiP_reset_bufferRequest.getName())
1435 {
1436 log<software_error>({__FILE__, __LINE__, "invalid indi property received"});
1437 return -1;
1438 }
1439
1440 if(!ipRecv.find("request")) return 0;
1441
1442 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
1443 {
1444 std::lock_guard<std::mutex> guard(m_indiMutex);
1445 controller->reset_data_buffer();
1446 updateSwitchIfChanged(m_indiP_reset_bufferRequest, "request", pcf::IndiElement::Off, INDI_IDLE);
1447 }
1448
1449 return 0;
1450}
1451
1452
1453INDI_NEWCALLBACK_DEFN(hoPredCtrl, m_indiP_reset_exploreRequest )(const pcf::IndiProperty &ipRecv)
1454{
1455 if(ipRecv.getName() != m_indiP_reset_exploreRequest.getName())
1456 {
1457 log<software_error>({__FILE__, __LINE__, "invalid indi property received"});
1458 return -1;
1459 }
1460
1461 if(!ipRecv.find("request")) return 0;
1462
1463 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
1464 {
1465 std::lock_guard<std::mutex> guard(m_indiMutex);
1466 controller->create_exploration_buffer(m_exploration_rms, m_exploration_steps);
1467 updateSwitchIfChanged(m_indiP_reset_exploreRequest, "request", pcf::IndiElement::Off, INDI_IDLE);
1468 }
1469
1470 return 0;
1471}
1472
1473
1474INDI_NEWCALLBACK_DEFN(hoPredCtrl, m_indiP_reset_modelRequest )(const pcf::IndiProperty &ipRecv)
1475{
1476 if(ipRecv.getName() != m_indiP_reset_modelRequest.getName())
1477 {
1478 log<software_error>({__FILE__, __LINE__, "invalid indi property received"});
1479 return -1;
1480 }
1481
1482 if(!ipRecv.find("request")) return 0;
1483
1484 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
1485 {
1486 std::lock_guard<std::mutex> guard(m_indiMutex);
1487 controller->reset_controller();
1488 updateSwitchIfChanged(m_indiP_reset_modelRequest, "request", pcf::IndiElement::Off, INDI_IDLE);
1489 }
1490
1491 return 0;
1492}
1493
1494
1495
1496INDI_NEWCALLBACK_DEFN(hoPredCtrl, m_indiP_reset_cleanRequest )(const pcf::IndiProperty &ipRecv)
1497{
1498 if(ipRecv.getName() != m_indiP_reset_cleanRequest.getName())
1499 {
1500 log<software_error>({__FILE__, __LINE__, "invalid indi property received"});
1501 return -1;
1502 }
1503
1504 if(!ipRecv.find("request")) return 0;
1505
1506 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
1507 {
1508 std::lock_guard<std::mutex> guard(m_indiMutex);
1509
1510 // Regenerate the exploration buffer
1511 controller->create_exploration_buffer(m_exploration_rms, m_exploration_steps);
1512
1513 // Reset the controller
1514 controller->reset_controller();
1515 controller->reset_data_buffer(); // Clear the data buffer
1516
1517 // Set the current DM shape and command to zero
1518 zero();
1519 controller->set_zero();
1520
1521 updateSwitchIfChanged(m_indiP_reset_cleanRequest, "request", pcf::IndiElement::Off, INDI_IDLE);
1522 }
1523
1524 return 0;
1525}
1526
1527
1528INDI_NEWCALLBACK_DEFN(hoPredCtrl, m_indiP_updateControllerRequest )(const pcf::IndiProperty &ipRecv)
1529{
1530 if(ipRecv.getName() != m_indiP_updateControllerRequest.getName())
1531 {
1532 log<software_error>({__FILE__, __LINE__, "invalid indi property received"});
1533 return -1;
1534 }
1535
1536 if(!ipRecv.find("request")) return 0;
1537
1538 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
1539 {
1540 std::lock_guard<std::mutex> guard(m_indiMutex);
1541
1542 // Regenerate the exploration buffer
1543 controller->update_controller();
1544 updateSwitchIfChanged(m_indiP_updateControllerRequest, "request", pcf::IndiElement::Off, INDI_IDLE);
1545 }
1546
1547 return 0;
1548}
1549
1550
1551INDI_NEWCALLBACK_DEFN(hoPredCtrl, m_indiP_zeroRequest )(const pcf::IndiProperty &ipRecv)
1552{
1553 if(ipRecv.getName() != m_indiP_zeroRequest.getName())
1554 {
1555 log<software_error>({__FILE__, __LINE__, "invalid indi property received"});
1556 return -1;
1557 }
1558
1559 if(!ipRecv.find("request")) return 0;
1560
1561 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
1562 {
1563
1564 if(!m_is_closed_loop){
1565 zero();
1566 controller->set_zero();
1567 }else{
1568 m_shaped_command.setZero();
1569 }
1570
1571 updateSwitchIfChanged(m_indiP_zeroRequest, "request", pcf::IndiElement::Off, INDI_IDLE);
1572 }
1573
1574 return 0;
1575}
1576
1577INDI_NEWCALLBACK_DEFN(hoPredCtrl, m_indiP_saveRequest )(const pcf::IndiProperty &ipRecv)
1578{
1579 if(ipRecv.getName() != m_indiP_saveRequest.getName())
1580 {
1581 log<software_error>({__FILE__, __LINE__, "invalid indi property received"});
1582 return -1;
1583 }
1584
1585 if(!ipRecv.find("request")) return 0;
1586
1587 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
1588 {
1589 controller->save_state(savepath);
1590 updateSwitchIfChanged(m_indiP_saveRequest, "request", pcf::IndiElement::Off, INDI_IDLE);
1591 }
1592
1593 return 0;
1594}
1595
1596
1597INDI_NEWCALLBACK_DEFN(hoPredCtrl, m_indiP_loadRequest )(const pcf::IndiProperty &ipRecv)
1598{
1599 if(ipRecv.getName() != m_indiP_loadRequest.getName())
1600 {
1601 log<software_error>({__FILE__, __LINE__, "invalid indi property received"});
1602 return -1;
1603 }
1604
1605 if(!ipRecv.find("request")) return 0;
1606
1607 if( ipRecv["request"].getSwitchState() == pcf::IndiElement::On)
1608 {
1609 controller->load_state(savepath, std::to_string(loading_timestamp));
1610 updateSwitchIfChanged(m_indiP_loadRequest, "request", pcf::IndiElement::Off, INDI_IDLE);
1611 }
1612
1613 return 0;
1614}
1615
1616} //namespace app
1617} //namespace MagAOX
1618
1619#endif //hoPredCtrl_hpp
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.
int createStandardIndiRequestSw(pcf::IndiProperty &prop, const std::string &name, const std::string &label="", const std::string &group="")
Create a standard R/W INDI switch with a single request element.
stateCodes::stateCodeT state()
Get the current state code.
int registerIndiPropertyNew(pcf::IndiProperty &prop, int(*)(void *, const pcf::IndiProperty &))
Register an INDI property which is exposed for others to request a New Property for.
int createStandardIndiToggleSw(pcf::IndiProperty &prop, const std::string &name, const std::string &label="", const std::string &group="")
Create a standard R/W INDI switch with a single toggle element.
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.
std::mutex m_indiMutex
Mutex for locking INDI communications.
uint32_t m_width
The width of the images in the stream.
int setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
int updateINDI()
Update the INDI properties for this device controller.
int appLogic()
Checks the shmimMonitor thread.
uint32_t m_height
The height of the images in the stream.
int appShutdown()
Shuts down the shmimMonitor thread.
int loadConfig(mx::app::appConfigurator &config)
load the configuration system results
bool m_getExistingFirst
If set to true by derivedT, any existing image will be grabbed and sent to processImage before waitin...
pcf::IndiProperty m_indiP_explorationSteps
INDI_NEWCALLBACK_DECL(hoPredCtrl, m_indiP_reset_exploreRequest)
pcf::IndiProperty m_indiP_zeroRequest
INDI_NEWCALLBACK_DECL(hoPredCtrl, m_indiP_timestamp)
pcf::IndiProperty m_indiP_reset_exploreRequest
hoPredCtrl()
Default c'tor.
pcf::IndiProperty m_indiP_explorationRms
DDSPC::PredictiveController * controller
pcf::IndiProperty m_indiP_intgain
eigenImage< realT > m_mapping_matrix
int processImage(void *curr_src, const dev::shmimT &dummy)
INDI_NEWCALLBACK_DECL(hoPredCtrl, m_indiP_loadRequest)
realT(* dark_pixget)(void *, size_t)
pcf::IndiProperty m_indiP_learningSteps
INDI_NEWCALLBACK_DECL(hoPredCtrl, m_indiP_zeroRequest)
int m_numFut
The number of future states to predict.
INDI_NEWCALLBACK_DECL(hoPredCtrl, m_indiP_clipval)
unsigned long long iterations
INDI_NEWCALLBACK_DECL(hoPredCtrl, m_indiP_controlToggle)
pcf::IndiProperty m_indiP_lambda
INDI_NEWCALLBACK_DECL(hoPredCtrl, m_indiP_intgain)
INDI_NEWCALLBACK_DECL(hoPredCtrl, m_indiP_updateControllerRequest)
realT m_inv_covariance
The starting point of the inverse covariance matrix.
int m_numHist
The number of past states to use for the prediction.
virtual int appLogic()
Implementation of the FSM for hoPredCtrl.
size_t m_pwfsHeight
The height of the image.
uint32_t m_dmWidth
The width of the image.
friend class hoPredCtrl_test
virtual int appStartup()
Startup function.
std::string m_pupilMaskFilename
pcf::IndiProperty m_indiP_reset_cleanRequest
size_t m_pwfsTypeSize
The size of the type, in bytes.
pcf::IndiProperty m_indiP_clipval
uint32_t m_dmHeight
The height of the image.
INDI_NEWCALLBACK_DECL(hoPredCtrl, m_indiP_explorationSteps)
pcf::IndiProperty m_indiP_saveRequest
INDI_NEWCALLBACK_DECL(hoPredCtrl, m_indiP_gamma)
realT m_gamma
The forgetting factore (0, 1)
dev::shmimMonitor< hoPredCtrl > shmimMonitorT
dev::shmimMonitor< hoPredCtrl, darkShmimT > darkMonitorT
eigenImage< realT > m_measurementVector
eigenImage< realT > m_shaped_command
INDI_NEWCALLBACK_DECL(hoPredCtrl, m_indiP_lambda)
std::string m_mapping_matrix_filename
INDI_NEWCALLBACK_DECL(hoPredCtrl, m_indiP_reset_bufferRequest)
eigenImage< realT > m_darkImage
Pointer to a function to extract the image data as our desired type realT.
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
realT m_lambda
The regularization parameter.
unsigned long long duration
virtual int appShutdown()
Shutdown the app.
eigenImage< realT > m_illuminated_actuators_mask
pcf::IndiProperty m_indiP_reset_modelRequest
bool m_darkSet
Pointer to a function to extract the image data as our desired type realT.
virtual void setupConfig()
INDI_NEWCALLBACK_DECL(hoPredCtrl, m_indiP_explorationRms)
pcf::IndiProperty m_indiP_learningIterations
uint8_t m_dmDataType
The ImageStreamIO type code.
INDI_NEWCALLBACK_DECL(hoPredCtrl, m_indiP_learningSteps)
pcf::IndiProperty m_indiP_controlToggle
size_t m_pwfsWidth
The width of the image.
int allocate(const dev::shmimT &dummy)
pcf::IndiProperty m_indiP_predictorToggle
pcf::IndiProperty m_indiP_timestamp
INDI_NEWCALLBACK_DECL(hoPredCtrl, m_indiP_reset_modelRequest)
pcf::IndiProperty m_indiP_loadRequest
float realT
Floating point type in which to do all calculations.
virtual void loadConfig()
INDI_NEWCALLBACK_DECL(hoPredCtrl, m_indiP_reset_cleanRequest)
eigenImage< realT > m_pupilMask
std::string m_refWavefront_filename
size_t m_quadWidth
The width of the image.
INDI_NEWCALLBACK_DECL(hoPredCtrl, m_indiP_learningIterations)
pcf::IndiProperty m_indiP_reset_bufferRequest
pcf::IndiProperty m_indiP_intleak
std::string m_interaction_matrix_filename
realT(* pwfs_pixget)(void *, size_t)
size_t m_quadHeight
The height of the image.
pcf::IndiProperty m_indiP_gamma
INDI_NEWCALLBACK_DECL(hoPredCtrl, m_indiP_intleak)
eigenImage< realT > m_refWavefront
size_t m_dmTypeSize
The size of the type, in bytes.
eigenImage< realT > m_interaction_matrix
uint8_t m_pwfsDataType
The ImageStreamIO type code.
~hoPredCtrl() noexcept
D'tor, declared and defined for noexcept.
pcf::IndiProperty m_indiP_updateControllerRequest
INDI_NEWCALLBACK_DECL(hoPredCtrl, m_indiP_saveRequest)
int set_pupil_mask(std::string pupil_mask_filename)
INDI_NEWCALLBACK_DECL(hoPredCtrl, m_indiP_predictorToggle)
#define INDI_NEWCALLBACK_DEFN(class, prop)
Define the callback for a new property request.
#define INDI_NEWCALLBACK(prop)
Get the name of the static callback wrapper for a new property.
@ OPERATING
The device is operating, other than homing.
#define INDI_IDLE
Definition indiUtils.hpp:28
#define INDI_BUSY
Definition indiUtils.hpp:30
#define INDI_OK
Definition indiUtils.hpp:29
const pcf::IndiProperty & ipRecv
updateIfChanged(m_indiP_angle, "target", m_angle)
std::unique_lock< std::mutex > lock(m_indiMutex)
Definition dm.hpp:24
static constexpr logPrioT LOG_NOTICE
A normal but significant condition.
static std::string configSection()
static std::string indiPrefix()
Software ERR log entry.