7#ifndef strehlEstimator_hpp
8#define strehlEstimator_hpp
15#include <mx/ao/analysis/aoSystem.hpp>
16using namespace mx::math;
18#include "../../libMagAOX/libMagAOX.hpp"
19#include "../../magaox_git_version.h"
61 return "wfsmaskShmim";
89 typedef mx::AO::analysis::aoSystem<float, mx::AO::analysis::vonKarmanSpectrum<float>>
aoSystemT;
151 float m_r0{ 0.2063f * 0.5f / 0.64f };
374 const std::string &name,
375 const std::string &
label,
376 const std::string &
group
384 const predictionInputs &
inputs,
480 config.add(
"loop.number",
488 "The number of the loop. Used to set shmim names, as in aolN_mgainfact." );
490 config.add(
"phot.qe_6535",
498 "The WFS QE in the 65-35 B/S." );
500 config.add(
"phot.qe_HaIR",
508 "The WFS QE in the Ha-IR B/S." );
539 const std::string &name,
540 const std::string &label,
541 const std::string &group )
543 prop = pcf::IndiProperty( pcf::IndiProperty::Number );
545 prop.setName( name );
546 prop.setPerm( pcf::IndiProperty::ReadWrite );
547 prop.setState( pcf::IndiProperty::Idle );
551 prop.setLabel(
label );
556 prop.setGroup(
group );
559 prop.add( pcf::IndiElement(
"current", 0.0f ) );
560 prop.add( pcf::IndiElement(
"estimated", 0.0f ) );
597 static const std::vector<std::string>
names{
"slow",
"normal",
"fast",
"very-fast" };
603 static const std::vector<std::string>
labels{
604 "Slow (9.4 m/s)",
"Normal (18.7 m/s)",
"Fast (23.4 m/s)",
"Very Fast (30.0 m/s)" };
630 float nearestDiff = std::numeric_limits<float>::max();
668 if(
inputs.m_useEstimates )
686 return 0.2063f * 0.5f / seeing;
691 return std::isfinite( value );
701 float diff = std::fabs(
a -
b );
707 float scale = std::fabs(
a );
708 if( std::fabs(
b ) >
scale )
744 : pcf::IndiElement::Off );
749 : pcf::IndiElement::Off );
761 inputs.m_useEstimates ? pcf::IndiElement::On : pcf::IndiElement::Off,
772 aosys.ron_wfs( std::vector<float>( { 245.0f /
inputs.m_emg } ) );
773 aosys.npix_wfs( std::vector<float>( {
static_cast<float>(
inputs.m_npix ) } ) );
774 aosys.minTauWFS( std::vector<float>( { 1.0f / fps } ) );
775 aosys.tauWFS( 1.0f / fps );
806 for(
int fps = 100; fps <= 3000; fps += 100 )
829 bestFPS =
static_cast<float>( fps );
843 std::ostringstream
oss;
844 oss <<
"strehlEstimator suspicious optimum scan" <<
" use_estimates=" << std::boolalpha <<
inputs.m_useEstimates
845 <<
" selected_mag=" <<
inputs.m_selectedMag <<
" selected_seeing=" <<
inputs.m_selectedSeeing
846 <<
" selected_wind=" <<
inputs.m_selectedWindSpeed <<
" fps_live=" <<
inputs.m_fps
847 <<
" emg=" <<
inputs.m_emg <<
" elevation=" <<
inputs.m_elevation <<
" npix=" <<
inputs.m_npix
854 oss <<
" fps=" <<
point.fps <<
" strehl=" <<
point.strehl <<
" wfe_total=" <<
point.wfeTotal
855 <<
" wfe_meas=" <<
point.wfeMeasurement <<
" wfe_delay=" <<
point.wfeTimeDelay
856 <<
" wfe_fit=" <<
point.wfeFitting <<
" d_opt=" <<
point.dOpt <<
" bin_opt=" <<
point.binOpt <<
'\n';
859 std::cerr <<
oss.str();
881 {
"fps",
"strehl",
"wfe_total",
"wfe_measurement",
"wfe_time_delay",
"wfe_fitting" },
910 m_aosys.minTauWFS().size() > 0 &&
944 {
"total",
"measurement",
"time_delay",
"fitting" },
988 "Error Budget" ) < 0 )
1010 m_indiP_wfe.add( pcf::IndiElement(
"total", 0.0f ) );
1011 m_indiP_wfe.add( pcf::IndiElement(
"measurement", 0.0f ) );
1012 m_indiP_wfe.add( pcf::IndiElement(
"time_delay", 0.0f ) );
1013 m_indiP_wfe.add( pcf::IndiElement(
"fitting", 0.0f ) );
1055 static_cast<void>(
dummy );
1063 static_cast<void>(
dummy );
1065 auto wfsavg = mx::improc::eigenMap<float>(
1068 float counts = 0.0f;
1086 std::cerr <<
"counts: " << counts <<
'\n';
1096 static_cast<void>(
dummy );
1104 static_cast<void>(
dummy );
1106 auto wfsmask = mx::improc::eigenMap<float>(
1135 float counts = 0.0f;
1165 std::cerr <<
"calcMag: " << counts <<
' ' <<
m_again <<
' ' <<
' ' <<
emg <<
' ' << fps <<
' ' <<
qe <<
' ' <<
F0
1181 if(
ipRecv.find(
"current" ) )
1183 float fps =
ipRecv[
"current"].get<
float>();
1185 bool changed =
false;
1188 std::lock_guard<std::mutex>
lock( m_stateMutex );
1189 if( finitePositiveValue( fps ) && fps != m_fps )
1198 std::cerr <<
"Got FPS: " << fps <<
'\n';
1210 if(
ipRecv.find(
"current" ) )
1212 float emg =
ipRecv[
"current"].get<
float>();
1214 bool changed =
false;
1217 std::lock_guard<std::mutex>
lock( m_stateMutex );
1218 if( finitePositiveValue( emg ) && emg != m_emg )
1227 std::cerr <<
"Got EMG: " << emg <<
'\n';
1239 std::string preset =
"none";
1241 for(
auto &&el :
ipRecv.getElements() )
1243 if( el.second.getSwitchState() == pcf::IndiElement::On )
1250 std::cerr <<
"Got stage bs: " << preset <<
'\n';
1253 std::lock_guard<std::mutex>
lock( m_stateMutex );
1255 if( preset ==
"ha-ir" )
1258 m_lam0 = m_lam0_HaIR;
1264 m_lam0 = m_lam0_6535;
1278 if(
ipRecv.find(
"dimm_fwhm_corr" ) )
1280 float seeing =
ipRecv[
"dimm_fwhm_corr"].get<
float>();
1282 bool changed =
false;
1285 std::lock_guard<std::mutex>
lock( m_stateMutex );
1287 if( finitePositiveValue( seeing ) && seeing != m_seeing )
1290 m_r0 = seeingToR0( m_seeing );
1291 m_dimm_fwhm_corr = seeing;
1293 if( !m_useEstimates && !m_seeingEstimatedManual )
1295 m_seeingEstimated = m_seeing;
1304 std::cerr <<
"Got seeing: " << seeing <<
'\n';
1306 updatePlanningProperties();
1307 updatePredictionOutputs();
1318 if(
ipRecv.find(
"el" ) )
1320 float elevation =
ipRecv[
"el"].get<
float>();
1322 bool changed =
false;
1325 std::lock_guard<std::mutex>
lock( m_stateMutex );
1326 if( finiteValue( elevation ) && elevation != m_elevation )
1328 m_elevation = elevation;
1335 std::cerr <<
"Got elevation: " << elevation <<
'\n';
1337 updatePredictionOutputs();
1347 if(
ipRecv.find(
"estimated" ) )
1349 float mag =
ipRecv[
"estimated"].get<
float>();
1351 bool changed =
false;
1354 std::lock_guard<std::mutex>
lock( m_stateMutex );
1355 if( finiteValue( mag ) && mag != m_magEstimated )
1357 m_magEstimated = mag;
1358 m_magEstimatedManual =
true;
1365 updatePlanningProperties();
1366 updatePredictionOutputs();
1377 if(
ipRecv.find(
"estimated" ) )
1379 float seeing =
ipRecv[
"estimated"].get<
float>();
1381 bool changed =
false;
1384 std::lock_guard<std::mutex>
lock( m_stateMutex );
1385 if( finitePositiveValue( seeing ) && seeing != m_seeingEstimated )
1387 m_seeingEstimated = seeing;
1388 m_seeingEstimatedManual =
true;
1395 updatePlanningProperties();
1396 updatePredictionOutputs();
1407 std::string selection;
1408 for(
auto &&el :
ipRecv.getElements() )
1410 if( el.second.getSwitchState() == pcf::IndiElement::On )
1412 selection = el.first;
1417 if( selection ==
"" )
1422 float windSpeed = windSpeedSelectionValue( selection );
1423 bool changed =
false;
1426 std::lock_guard<std::mutex>
lock( m_stateMutex );
1427 if( finitePositiveValue( windSpeed ) && windSpeed != m_windSpeed )
1429 m_windSpeed = windSpeed;
1434 updatePlanningProperties();
1438 updatePredictionOutputs();
1448 if( !
ipRecv.find(
"toggle" ) )
1453 bool useEstimates =
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::On;
1454 bool changed =
false;
1457 std::lock_guard<std::mutex>
lock( m_stateMutex );
1458 if( useEstimates != m_useEstimates )
1460 m_useEstimates = useEstimates;
1465 updatePlanningProperties();
1469 updatePredictionOutputs();
The base-class for XWCTk applications.
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.
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.
indiDriver< MagAOXApp > * m_indiDriver
The INDI driver wrapper. Constructed and initialized by execute, which starts and stops communication...
void updateSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, const pcf::IndiElement::SwitchStateType &newVal, pcf::IndiProperty::PropertyStateType ipState=pcf::IndiProperty::Ok)
Update an INDI switch element value if it has changed.
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
std::string configName()
Get the config name.
int createStandardIndiSelectionSw(pcf::IndiProperty &prop, const std::string &name, const std::vector< std::string > &elements, const std::vector< std::string > &elementLabels, const std::string &label="", const std::string &group="")
Create a standard R/W INDI selection (one of many) switch with vector of elements and element labels.
uint32_t m_width
The width of the images in the stream.
uint32_t m_height
The height of the images in the stream.
Predicts Strehl and WFE from live WFS telemetry and optional planning overrides.
virtual int appShutdown()
Shut down the shmim monitors.
float m_magEstimated
Operator-entered guide-star magnitude estimate.
float m_selectedSeeing
Selected seeing used for prediction.
INDI_SETCALLBACK_DECL(strehlEstimator, m_indiP_tcsi_telpos)
Callback for live TCS elevation updates.
float m_mag
Live guide-star magnitude derived from m_counts.
INDI_SETCALLBACK_DECL(strehlEstimator, m_indiP_tcsi_seeing)
Callback for live TCS seeing updates.
mx::AO::analysis::aoSystem< float, mx::AO::analysis::vonKarmanSpectrum< float > > aoSystemT
float m_fps
Live loop speed in Hz.
float selectedStarMag() const
Return the selected star magnitude for prediction calculations.
float m_windSpeed
Operator-selected wind speed in m/s used for planning calculations.
INDI_NEWCALLBACK_DECL(strehlEstimator, m_indiP_seeing_magaox)
Callback for local seeing estimate writes.
double m_dimm_fwhm_corr
Latest DIMM elevation-corrected FWHM.
float m_again
Analog gain factor converting WFS counts into photo-electrons.
friend class strehlEstimator_test
bool m_seeingEstimatedManual
Tracks whether the estimated seeing has been explicitly set by an operator.
pcf::IndiProperty m_indiP_useEstimates
Local toggle selecting whether predicted outputs use estimated inputs.
float selectedSeeing() const
Return the selected seeing for prediction calculations.
static const std::vector< std::string > & windSpeedSelectionElements()
Return the supported wind-speed selection element names.
float m_selectedWindSpeed
Selected wind speed used for prediction.
float m_elevation
Telescope elevation in degrees.
virtual int appStartup()
Register INDI properties and transition the app into the operating state.
bool m_useEstimates
Whether estimated planning inputs are currently selected.
int allocate(const wfsavgShmimT &dummy)
React to allocation of the WFS average shmim stream.
void updateOptimumLoopSpeed(const predictionInputs &inputs)
Refresh the fixed-grid optimum-loop-speed summary property.
int loadConfigImpl(mx::app::appConfigurator &_config)
Load configuration values after setupConfig() has registered them.
INDI_NEWCALLBACK_DECL(strehlEstimator, m_indiP_windSpeed)
Callback for local wind-speed selection writes.
float m_windSpeed
Operator-selected wind speed in m/s.
pcf::IndiProperty m_indiP_loopSpeedOptimum
Summary property for the best fixed-grid loop speed.
std::string m_wfsDevice
WFS device providing the live FPS property.
~strehlEstimator() noexcept
Destroy the application.
float m_qe_HaIR
WFS QE for the Ha/IR beamsplitter branch.
pcf::IndiProperty m_indiP_fps
Subscription to the live WFS FPS property.
float m_seeing
Live seeing in arcseconds.
static float wfeNm(float variance, float lam0)
Convert AO model phase variance into WFE in nm RMS at the specified wavelength.
std::mutex m_predictionMutex
Serializes access to the shared AO-model instances and prediction-property updates.
virtual void setupConfig()
Declare configuration keys and initialize the AO models.
float m_lam0
Active wavelength in microns.
aoSystemT m_aosys
AO model used for the current predicted Strehl and WFE outputs.
INDI_SETCALLBACK_DECL(strehlEstimator, m_indiP_stage)
Callback for beamsplitter preset updates.
float m_qe
Active WFS quantum efficiency for the currently selected beamsplitter branch.
std::mutex m_stateMutex
Protects the live telemetry and planning-input state while prediction snapshots are assembled.
float m_lam0_HaIR
Effective WFS wavelength in microns for the Ha/IR beamsplitter branch.
void updatePredictionOutputs()
Refresh the predicted Strehl, WFE, and optimum-loop-speed properties.
void updatePlanningProperties()
Update the published planning-input properties from the current runtime state.
int processImage(void *curr_src, const wfsavgShmimT &dummy)
Process one WFS average frame.
bool m_useEstimates
Selects whether predicted outputs use the live or estimated planning inputs.
virtual int appLogic()
Refresh the AO predictions and service the shmim-monitor state machine.
bool m_magEstimatedManual
Tracks whether the estimated star magnitude has been explicitly set by an operator.
float m_F0
Active zero-magnitude photon flux for the selected beamsplitter branch.
float m_seeingEstimated
Operator-entered seeing in arcseconds used when planning overrides are enabled.
double m_mag1_fwhm_corr
Latest MAG1 elevation-corrected FWHM.
float m_fps
Live WFS frame rate in Hz.
float m_lam0_6535
Effective WFS wavelength in microns for the 65/35 beamsplitter branch.
float selectedWindSpeed() const
Return the selected wind speed for prediction calculations.
float m_selectedMag
Selected guide-star magnitude used for prediction.
static bool finiteValue(float value)
Return whether a value is finite.
pcf::IndiProperty m_indiP_stage
Subscription to the beamsplitter preset state.
static bool finitePositiveValue(float value)
Return whether a value is finite and strictly positive.
static std::string windSpeedSelectionName(float windSpeed)
Return the nearest supported wind-speed selection element name for a speed in m/s.
float m_lastLoggedSuspiciousOptimumFps
Tracks the last suspicious optimum FPS reported in debug logging.
float m_F0
Active zero-magnitude photon flux.
pcf::IndiProperty m_indiP_windSpeed
Local writable wind-speed selection property exposing slow, normal, and fast.
pcf::IndiProperty m_indiP_tcsi_seeing
Subscription to the TCS seeing property.
void configureAoSystem(aoSystemT &aosys, const predictionInputs &inputs, float fps, bool optimizeTau)
Configure an AO model for the selected inputs and requested loop speed.
float m_qe_6535
WFS QE for the 65/35 beamsplitter branch.
int m_npix
Number of illuminated WFS pixels in the current mask.
int m_mag1_time
Seconds since midnight of the latest MAG1 measurement.
float m_emg
Live EM gain reported by the WFS camera.
void calcMag()
Recalculate the live guide-star magnitude from the current WFS counts.
std::string m_stagebsDevice
Beamsplitter stage device used to choose the active photometric calibration.
pcf::IndiProperty m_indiP_wfe
Predicted WFE breakdown for the currently selected conditions.
dev::shmimMonitor< strehlEstimator, wfsmaskShmimT > wfsmaskShmimMonitorT
int m_loopNum
Loop number used to resolve the WFS shmim names.
int m_dimm_time
Seconds since midnight of the latest DIMM measurement.
static float windSpeedSelectionValue(const std::string &selection)
Convert a wind-speed selection element name into its configured speed in m/s.
strehlEstimator()
Construct the application with the compiled git-version metadata.
float m_counts
Total masked WFS counts used to derive the live guide-star magnitude.
INDI_SETCALLBACK_DECL(strehlEstimator, m_indiP_emg)
Callback for live EM-gain updates.
dev::shmimMonitor< strehlEstimator, wfsavgShmimT > wfsavgShmimMonitorT
static bool nearlyEqual(float a, float b, float relTol, float absTol)
Return whether two scalar AO-model inputs are effectively equal.
mx::improc::eigenImage< float > m_wfsavg
Latest WFS average image.
int createCurrentEstimatedProperty(pcf::IndiProperty &prop, const std::string &name, const std::string &label, const std::string &group)
Create a writable number property with current and estimated elements.
pcf::IndiProperty m_indiP_strehl
Predicted Strehl property for the currently selected conditions.
float m_r0
Live Fried parameter corresponding to m_seeing.
INDI_NEWCALLBACK_DECL(strehlEstimator, m_indiP_useEstimates)
Callback for the use_estimates toggle.
float m_magEstimated
Operator-entered star magnitude used when planning overrides are enabled.
mx::improc::eigenImage< float > m_wfsmask
Latest WFS mask image.
pcf::IndiProperty m_indiP_mag
Local writable star-magnitude property exposing current and estimated.
static float seeingToR0(float seeing)
Convert seeing in arcseconds to Fried parameter r0 in meters.
float m_lam0
Active WFS/science wavelength in microns for the selected beamsplitter branch.
static const std::vector< std::string > & windSpeedSelectionLabels()
Return the supported wind-speed selection labels.
double m_mag2_fwhm_corr
Latest MAG2 elevation-corrected FWHM.
INDI_NEWCALLBACK_DECL(strehlEstimator, m_indiP_mag)
Callback for local star-magnitude estimate writes.
INDI_SETCALLBACK_DECL(strehlEstimator, m_indiP_fps)
Callback for live FPS updates.
float m_F0_6535
Zero-magnitude photon flux for the 65/35 beamsplitter branch.
int m_mag2_time
Seconds since midnight of the latest MAG2 measurement.
pcf::IndiProperty m_indiP_seeing_magaox
Local writable seeing property exposing current and estimated.
virtual void loadConfig()
Load the configured runtime values.
pcf::IndiProperty m_indiP_emg
Subscription to the live WFS EM-gain property.
pcf::IndiProperty m_indiP_tcsi_telpos
Subscription to the TCS telescope position property.
float m_F0_HaIR
Zero-magnitude photon flux for the Ha/IR beamsplitter branch.
float m_seeingEstimated
Operator-entered seeing estimate in arcseconds.
float m_mag
Live guide-star magnitude.
float m_qe
Active quantum efficiency.
float m_seeing
Live seeing estimate in arcseconds from tcsi.seeing.dimm_fwhm_corr.
predictionInputs snapshotPredictionInputs() const
Snapshot the scalar state used by the planning properties and AO-model calculations.
int m_npix
Current illuminated WFS-pixel count.
aoSystemT m_aosysScan
AO model dedicated to the fixed-FPS optimum-loop-speed scan.
float m_elevation
Telescope elevation in degrees.
#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.
#define INDI_SETCALLBACK_DEFN(class, prop)
Define the callback for a set property request.
#define REG_INDI_SETPROP(prop, devName, propName)
Register a SET INDI property with the class, using the standard callback name.
#define CREATE_REG_INDI_RO_NUMBER(prop, name, label, group)
Create and register a RO INDI property as a number, using the standard callback name.
#define INDI_VALIDATE_CALLBACK_PROPS(prop1, prop2)
Standard check for matching INDI properties in a callback.
void updateSelectionSwitchIfChanged(pcf::IndiProperty &p, const std::string &el, indiDriverT *indiDriver, pcf::IndiProperty::PropertyStateType newState=pcf::IndiProperty::Ok)
Update the values of a one-of-many INDI switch vector, but only if it has changed.
const pcf::IndiProperty & ipRecv
std::unique_lock< std::mutex > lock(m_indiMutex)
#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.
@ OPERATING
The device is operating, other than homing.
Tag type for the live WFS average shmim monitor.
static std::string configSection()
Return the configuration section name for this shmim monitor.
static std::string indiPrefix()
Return the INDI prefix for this shmim monitor.
Tag type for the WFS mask shmim monitor.
static std::string indiPrefix()
Return the INDI prefix for this shmim monitor.
static std::string configSection()
Return the configuration section name for this shmim monitor.
double variance(double data[], int size, int num_skip=0)