7#ifndef modalGainOpt_hpp
8#define modalGainOpt_hpp
14#include <mx/ao/analysis/clAOLinearPredictor.hpp>
15#include <mx/ao/analysis/clGainOpt.hpp>
16#include <mx/mxException.hpp>
20#include "../../libMagAOX/libMagAOX.hpp"
21#include "../../magaox_git_version.h"
71 return "power_law_only";
73 return "moffat_peaks";
87 return "Power Law Only";
89 return "Moffat Peaks";
103 return "power-law-only";
105 return "moffat-peaks";
114 if( element ==
"legacy" )
119 if( element ==
"power_law_only" )
124 if( element ==
"moffat_peaks" )
134 std::transform( method.begin(),
137 [](
unsigned char c )
141 return static_cast<char>(
'-' );
144 return static_cast<char>( std::tolower( c ) );
147 if( method ==
"legacy" )
152 if( method ==
"power-law-only" )
157 if( method ==
"moffat-peaks" )
167 return value ?
"true" :
"false";
175 return "closed_loop_pre_xfer";
187 return "Closed Loop Pre-Xfer";
199 return "closed-loop-pre-xfer";
208 if( element ==
"closed_loop_pre_xfer" )
218 std::transform( domain.begin(),
221 [](
unsigned char c )
225 return static_cast<char>(
'-' );
228 return static_cast<char>( std::tolower( c ) );
231 if( domain ==
"closed-loop-pre-xfer" )
233 return c_extrapNoiseEstimateClosedLoopPreXfer;
236 return c_extrapNoiseEstimateOpenLoop;
256 return "Low Frequency";
259 return "High Frequency";
277 if( element ==
"low_freq" )
287 std::transform( range.begin(),
290 [](
unsigned char c )
294 return static_cast<char>(
'-' );
297 return static_cast<char>( std::tolower( c ) );
300 if( range ==
"low-freq" )
302 return c_extrapNoiseEstimateLowFreq;
305 return c_extrapNoiseEstimateHighFreq;
346 if( element ==
"minimum" )
356 std::transform( statistic.begin(),
359 [](
unsigned char c )
363 return static_cast<char>(
'-' );
366 return static_cast<char>( std::tolower( c ) );
369 if( statistic ==
"minimum" )
371 return c_extrapNoiseEstimateMinimum;
374 return c_extrapNoiseEstimatePercentile;
415 if( element ==
"ntf_aware" )
425 std::transform( method.begin(),
428 [](
unsigned char c )
432 return static_cast<char>(
'-' );
435 return static_cast<char>( std::tolower( c ) );
438 if( method ==
"ntf-aware" )
440 return c_extrapClosedLoopOlEstimateNtfAware;
443 return c_extrapClosedLoopOlEstimateEtfOnly;
451 return "auto_smoothed_crossing";
463 return "Auto Smoothed Crossing";
475 return "auto-smoothed-crossing";
484 if( element ==
"auto_smoothed_crossing" )
494 std::transform( mode.begin(),
497 [](
unsigned char c )
501 return static_cast<char>(
'-' );
504 return static_cast<char>( std::tolower( c ) );
507 if( mode ==
"auto" || mode ==
"automatic" || mode ==
"auto-crossing" || mode ==
"auto-smoothed-crossing" )
509 return c_extrapPowerLawCrossoverAutoSmoothedCrossing;
512 return c_extrapPowerLawCrossoverManual;
545 return "gainFactShmim";
558 return "multFactShmim";
567struct pcGainFactShmimT
571 return "pcGainFactShmim";
580struct pcMultFactShmimT
584 return "pcMultFactShmim";
597 return "numpccoeffShmim";
610 return "acoeffShmim";
623 return "bcoeffShmim";
636 return "gainCalShmim";
649 return "gainCalFactShmim";
654 return "gainCalFact";
688 return "wfsavgShmim";
701 return "wfsmaskShmim";
735 friend class modalGainOpt_test;
773 typedef std::chrono::time_point<std::chrono::steady_clock>
timePointT;
786 std::string m_wfsDevice{
"camwfs" };
788 std::string m_psdDevice{
"hopsds" };
791 std::string m_opticalGainDevice{
"strehl" };
792 std::string m_opticalGainProperty{
"strehl_optimal" };
793 std::string m_opticalGainElement{
"pyramid" };
795 bool m_autoUpdate{
false };
796 bool m_opticalGainUpdate{
false };
803 uint32_t m_maxNCoeff{ 1000 };
805 uint32_t m_defaultNCoeff{ 25 };
821 uint32_t m_nFreq{ 0 };
822 uint32_t m_nModes{ 0 };
824 bool m_updateOnce{
false };
826 bool m_dump{
false };
827 bool m_zeroGains{
false };
833 std::vector<mx::AO::analysis::clGainOpt<float>>
m_goptSI;
834 std::vector<mx::AO::analysis::clGainOpt<float>>
m_goptLP;
835 std::vector<mx::AO::analysis::clAOLinearPredictor<float>>
m_linPred;
837 bool m_goptUpdated{
true };
839 bool m_pcgoptUpdated{
true };
842 bool m_freqUpdated{
true };
844 float m_psdTime{ 1 };
845 float m_psdAvgTime{ 10 };
846 float m_psdOverlapFraction{ 0.5 };
877 bool m_siGainStateNeedsSync{
true };
886 bool m_loop{
false };
890 float m_opticalGainSource{ 1 };
900 bool m_doPCCalcs{
true };
906 bool m_pcOn{
false };
948 int m_sinceChange{ -1 };
971 IMAGE *m_olPSDStream{
nullptr };
973 IMAGE *m_rawOlPSDStream{
nullptr };
975 IMAGE *m_smoothOlPSDStream{
nullptr };
977 IMAGE *m_noisePSDStream{
nullptr };
979 IMAGE *m_clXferCurrentStream{
nullptr };
981 IMAGE *m_clNtfCurrentStream{
nullptr };
983 IMAGE *m_clXferSIStream{
nullptr };
985 IMAGE *m_clNtfSIStream{
nullptr };
987 IMAGE *m_clXferLPStream{
nullptr };
989 IMAGE *m_clNtfLPStream{
nullptr };
992 IMAGE *m_optGainStream{
nullptr };
995 IMAGE *m_optGainSIRawStream{
nullptr };
997 IMAGE *m_optGainSIStream{
nullptr };
999 IMAGE *m_maxGainSIStream{
nullptr };
1002 IMAGE *m_optGainLPStream{
nullptr };
1004 IMAGE *m_maxGainLPStream{
nullptr };
1007 IMAGE *m_modevarStream{
nullptr };
1011 void destroyImageStream( IMAGE *&stream );
1014 int createImageStream( IMAGE *&stream,
1015 const std::string &name,
1024 void writePublishedGainArrays(
float *currentData,
1034 void writePublishedPredictorArrays(
float *pcGainData,
1043 int countEnabledGainFactors(
const std::vector<float> &gainFacts )
const;
1047 void updateAppliedModeCount(
const std::vector<float> &gainFacts,
1053 bool applyGainFactorUpdate( std::vector<float> &gainFacts,
1054 const float *incoming,
1062 bool applyMultiplierUpdate( std::vector<float> &multFacts,
1064 const float *incoming,
1071 bool applyFrequencyUpdate(
const float *incoming,
1082 bool refreshGoptStructures();
1085 void syncSiGainStateFromAppliedGains();
1088 void updateIntegratedSiGain(
size_t modeIndex );
1091 template <
typename valueT>
1093 valueT &localTarget,
1094 const pcf::IndiProperty &ipRecv,
1095 const std::string &label );
1100 const pcf::IndiProperty &ipRecv,
1101 const std::string &label );
1130 virtual void setupConfig();
1135 int loadConfigImpl( mx::app::appConfigurator &_config
1138 virtual void loadConfig();
1144 virtual int appStartup();
1151 virtual int appLogic();
1157 virtual int appShutdown();
1159 int allocatePCShmims();
1164 int processImage(
void *curr_src,
1171 int processImage(
void *curr_src,
1178 int processImage(
void *curr_src,
1185 int processImage(
void *curr_src,
1192 int processImage(
void *curr_src,
1199 int processImage(
void *curr_src,
1206 int processImage(
void *curr_src,
1213 int processImage(
void *curr_src,
1220 int processImage(
void *curr_src,
1227 int processImage(
void *curr_src,
1234 int processImage(
void *curr_src,
1241 int processImage(
void *curr_src,
1248 int processImage(
void *curr_src,
1255 int processImage(
void *curr_src,
1262 int processImage(
void *curr_src,
1275 std::atomic<bool> m_updating{
false };
1281 int m_goptThreadPrio{ 0 };
1288 bool m_goptThreadInit{
true };
1290 pid_t m_goptThreadID{ 0 };
1297 bool m_goptSemaphoreInit{
false };
1299 float noisePSD(
int n );
1307 void goptThreadExec();
1415 int checkRecordTimes();
1426modalGainOpt::modalGainOpt() :
MagAOXApp( MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED )
1449 config.add(
"loop.number",
1457 "The number of the loop. Used to set shmim names, as in aolN_mgainfact." );
1459 config.add(
"loop.name",
1467 "The name of the loop control INDI device name." );
1469 config.add(
"loop.psdDev",
1477 "The INDI device name of the PSD calculator. Defaults to "
1478 "aolN_modevalPSDs where N is loop.number." );
1480 config.add(
"loop.autoUpdate",
1488 "Flag controlling whether the gains are auto updated. Also "
1489 "settable via INDI." );
1491 config.add(
"loop.gainGain",
1499 "The gain to use for closed-loop gain updates. Default is 0.1" );
1501 config.add(
"loop.gainLeak",
1509 "The leak factor to use for SI optimal-gain integration. Default is 0.9" );
1511 config.add(
"extrapolation.method",
1513 "extrapolation.method",
1519 "The OL PSD extrapolation method: none, legacy, power_law_only, "
1520 "or moffat_peaks." );
1522 config.add(
"extrapolation.noiseEstimateDomain",
1524 "extrapolation.noiseEstimateDomain",
1527 "noiseEstimateDomain",
1530 "Where to estimate the flat noise floor: open_loop or "
1531 "closed_loop_pre_xfer." );
1533 config.add(
"extrapolation.noiseEstimateRange",
1535 "extrapolation.noiseEstimateRange",
1538 "noiseEstimateRange",
1541 "Which end of the PSD is used for noise estimation: high_freq or "
1544 config.add(
"extrapolation.noiseEstimateStatistic",
1546 "extrapolation.noiseEstimateStatistic",
1549 "noiseEstimateStatistic",
1552 "How to summarize the selected noise-estimation bins: percentile "
1555 config.add(
"extrapolation.noiseEstimateLowFreqMaxHz",
1557 "extrapolation.noiseEstimateLowFreqMaxHz",
1560 "noiseEstimateLowFreqMaxHz",
1563 "For low_freq noise estimation, the maximum frequency in Hz to "
1564 "include. Set to 0 to disable." );
1566 config.add(
"extrapolation.closedLoopOlEstimateMethod",
1568 "extrapolation.closedLoopOlEstimateMethod",
1571 "closedLoopOlEstimateMethod",
1574 "How to reconstruct OL PSD from CL PSD: etf_only or ntf_aware." );
1576 config.add(
"extrapolation.powerLawIndex",
1578 "extrapolation.powerLawIndex",
1584 "The power-law exponent a in the 1/f^a continuum model." );
1586 config.add(
"extrapolation.powerLawNormFreq",
1588 "extrapolation.powerLawNormFreq",
1594 "The power-law normalization frequency in Hz. Set to 0 to use the "
1595 "first positive bin." );
1597 config.add(
"extrapolation.powerLawMatchFreq",
1599 "extrapolation.powerLawMatchFreq",
1602 "powerLawMatchFreq",
1605 "The frequency in Hz where the extrapolated power law is forced "
1606 "to match the measured PSD." );
1608 config.add(
"extrapolation.powerLawMatchFallbackWindowHz",
1610 "extrapolation.powerLawMatchFallbackWindowHz",
1613 "powerLawMatchFallbackWindowHz",
1616 "Half-width in Hz of the local fallback window used when the "
1617 "match bin falls in a trough." );
1619 config.add(
"extrapolation.powerLawCrossoverMode",
1621 "extrapolation.powerLawCrossoverMode",
1624 "powerLawCrossoverMode",
1627 "How the power-law match/cutoff frequencies are chosen: manual or "
1628 "auto_smoothed_crossing." );
1630 config.add(
"extrapolation.powerLawAutoSmoothWidthHz",
1632 "extrapolation.powerLawAutoSmoothWidthHz",
1635 "powerLawAutoSmoothWidthHz",
1638 "Median-smoothing width in Hz used when auto power-law crossover "
1639 "selection is enabled." );
1641 config.add(
"extrapolation.powerLawAutoMaxFreqFraction",
1643 "extrapolation.powerLawAutoMaxFreqFraction",
1646 "powerLawAutoMaxFreqFraction",
1649 "Maximum searched frequency for auto power-law crossover as a "
1650 "fraction of the sampled maximum frequency. Set to 0 to disable "
1653 config.add(
"extrapolation.fitPowerLawIndex",
1655 "extrapolation.fitPowerLawIndex",
1661 "Whether to fit the power-law index from the high-frequency "
1662 "disturbance PSD bins." );
1664 config.add(
"extrapolation.powerLawOnlyAboveFreq",
1666 "extrapolation.powerLawOnlyAboveFreq",
1669 "powerLawOnlyAboveFreq",
1672 "Above this frequency in Hz, force the extrapolation to be "
1673 "power-law only." );
1675 config.add(
"extrapolation.powerLawFitIncludesMatchPoint",
1677 "extrapolation.powerLawFitIncludesMatchPoint",
1680 "powerLawFitIncludesMatchPoint",
1683 "Whether to include the explicit match point directly in the "
1684 "power-law exponent fit." );
1686 config.add(
"extrapolation.powerLawFitMinFreqHz",
1688 "extrapolation.powerLawFitMinFreqHz",
1691 "powerLawFitMinFreqHz",
1694 "The low edge in Hz of the power-law exponent fit range." );
1696 config.add(
"extrapolation.powerLawFitMaxFreqHz",
1698 "extrapolation.powerLawFitMaxFreqHz",
1701 "powerLawFitMaxFreqHz",
1704 "The high edge in Hz of the power-law exponent fit range." );
1706 config.add(
"extrapolation.powerLawFitBinWidthHz",
1708 "extrapolation.powerLawFitBinWidthHz",
1711 "powerLawFitBinWidthHz",
1714 "The width in Hz of the median bins used in the power-law exponent fit." );
1716 config.add(
"extrapolation.powerLawBlendBins",
1718 "extrapolation.powerLawBlendBins",
1721 "powerLawBlendBins",
1724 "The number of bins used to blend between the measured PSD and "
1725 "the extrapolated continuum." );
1727 config.add(
"extrapolation.peakDetectWidthHz",
1729 "extrapolation.peakDetectWidthHz",
1732 "peakDetectWidthHz",
1735 "The wide smoothing width in Hz used for peak detection." );
1737 config.add(
"extrapolation.peakDetectFactor",
1739 "extrapolation.peakDetectFactor",
1745 "The factor above the smoothed PSD required for a strong peak "
1748 config.add(
"extrapolation.peakDetectBroadFactor",
1750 "extrapolation.peakDetectBroadFactor",
1753 "peakDetectBroadFactor",
1756 "The lower factor above the smoothed PSD used for broad-peak "
1759 config.add(
"extrapolation.peakDetectMinWidthLog",
1761 "extrapolation.peakDetectMinWidthLog",
1764 "peakDetectMinWidthLog",
1767 "The minimum accepted broad-peak width in log-frequency." );
1769 config.add(
"extrapolation.peakDetectPasses",
1771 "extrapolation.peakDetectPasses",
1777 "The number of iterative subtract-and-redetect peak-detection passes." );
1779 config.add(
"extrapolation.peakMoffatBeta",
1781 "extrapolation.peakMoffatBeta",
1787 "The minimum Moffat beta used when synthesizing extrapolated peaks." );
1789 config.add(
"extrapolation.dropoutGapFactor",
1791 "extrapolation.dropoutGapFactor",
1797 "The relative depth threshold used to identify PSD dropouts for repair." );
1799 config.add(
"extrapolation.dropoutTinyFactor",
1801 "extrapolation.dropoutTinyFactor",
1804 "dropoutTinyFactor",
1807 "The maximum fraction of the local good-bin scale allowed for a "
1808 "candidate dropout run to be considered truly tiny." );
1810 config.add(
"extrapolation.dropoutMaxBins",
1812 "extrapolation.dropoutMaxBins",
1818 "The maximum consecutive dropout-run length that will be repaired." );
1820 config.add(
"extrapolation.clSignificanceThreshold",
1822 "extrapolation.clSignificanceThreshold",
1825 "clSignificanceThreshold",
1828 "The multiplier above the fitted raw CL noise floor required "
1829 "for a PSD bin to be considered significant." );
1831 config.add(
"extrapolation.clMinSignificantFraction",
1833 "extrapolation.clMinSignificantFraction",
1836 "clMinSignificantFraction",
1839 "The minimum fraction of raw CL PSD bins that must exceed the "
1840 "significance threshold for a mode to remain active." );
2097 "Extrapolation Method",
2098 "Extrapolation" ) < 0 )
2109 "extrap_noiseEstimateDomain",
2114 "Noise Estimate Domain",
2115 "Extrapolation" ) < 0 )
2127 "extrap_noiseEstimateRange",
2132 "Noise Estimate Range",
2133 "Extrapolation" ) < 0 )
2145 "extrap_noiseEstimateStatistic",
2150 "Noise Estimate Statistic",
2151 "Extrapolation" ) < 0 )
2163 "extrap_noiseEstimateLowFreqMaxHz",
2168 "Noise Estimate Low-Freq Max",
2172 "extrap_closedLoopOlEstimateMethod",
2177 "Closed Loop OL Estimate Method",
2178 "Extrapolation" ) < 0 )
2190 "extrap_powerLawIndex",
2198 "extrap_powerLawNormFreq",
2203 "Power-Law Norm Freq",
2206 "extrap_powerLawMatchFreq",
2211 "Power-Law Match Freq",
2214 "extrap_powerLawMatchFallbackWindowHz",
2219 "Power-Law Match Window",
2223 "extrap_powerLawCrossoverMode",
2228 "Power-Law Crossover Mode",
2229 "Extrapolation" ) < 0 )
2241 "extrap_powerLawAutoSmoothWidthHz",
2246 "Power-Law Auto Smooth Width",
2249 "extrap_powerLawAutoMaxFreqFraction",
2254 "Power-Law Auto Max Freq Fraction",
2257 "extrap_fitPowerLawIndex",
2258 "Fit Power-Law Index",
2259 "Extrapolation" ) < 0 )
2271 "extrap_powerLawOnlyAboveFreq",
2276 "Power-Law Only Above",
2279 "extrap_powerLawFitIncludesMatchPoint",
2280 "Fit Includes Match Point",
2281 "Extrapolation" ) < 0 )
2293 "extrap_powerLawFitMinFreqHz",
2301 "extrap_powerLawFitMaxFreqHz",
2309 "extrap_powerLawFitBinWidthHz",
2317 "extrap_powerLawBlendBins",
2325 "extrap_dropoutGapFactor",
2330 "Dropout Gap Factor",
2333 "extrap_dropoutTinyFactor",
2338 "Dropout Tiny Factor",
2341 "extrap_dropoutMaxBins",
2349 "extrap_clSignificanceThreshold",
2354 "CL Significance Threshold",
2357 "extrap_clMinSignificantFraction",
2362 "CL Min Significant Fraction",
2449 float opticalGain = 0;
2550 {
"current",
"target" },
2557 {
"current",
"target" },
2560 {
"current",
"target" },
2563 {
"current",
"target" },
2567 {
"current",
"target" },
2574 {
"current",
"target" },
2578 {
"current",
"target" },
2582 extrapConfig.m_fitPowerLawIndex ? pcf::IndiElement::On : pcf::IndiElement::Off,
2585 {
"current",
"target" },
2589 extrapConfig.m_powerLawFitIncludesMatchPoint ? pcf::IndiElement::On : pcf::IndiElement::Off,
2592 {
"current",
"target" },
2595 {
"current",
"target" },
2598 {
"current",
"target" },
2601 {
"current",
"target" },
2604 {
"current",
"target" },
2607 {
"current",
"target" },
2611 {
"current",
"target" },
2614 {
"current",
"target" },
2617 {
"current",
"target" },
2621 {
"current",
"integrator",
"predictor" },
2697 float opticalGain = 0;
2738 IMAGE *&stream,
const std::string &name, uint32_t size0, uint32_t size1, uint32_t size2, uint8_t dataType )
2770 if(
stream->md ==
nullptr )
2773 return log<
software_error, -1>( {
"stream metadata not initialized for " + name } );
2788 float *modeVarData )
2809 float *pcGainData,
float *aCoeffData, uint32_t aWidth,
float *bCoeffData, uint32_t bWidth,
bool blend )
2892 const float *incoming,
2894 bool predictorPath )
2934 const float *incoming,
2936 bool predictorPath )
2981 if( size !=
m_freq.size() )
2987 for(
size_t n = 0;
n < size; ++
n )
3022 std::cerr <<
"updating gopt structures\n";
3047 for(
size_t m = 0;
m <
ta.size(); ++
m )
3054 for(
size_t m = 0;
m <
tb.size(); ++
m )
3079 std::cerr <<
"done.\n";
3085 const float tiny = std::numeric_limits<float>::min();
3132 mx::improc::eigenImage<uint32_t>
Npc(
m_nModes, 2 );
3142 std::cerr <<
"created numppccoeff shmim\n";
3153 std::cerr <<
"created acoeff shmim\n";
3164 std::cerr <<
"created bcoeff shmim\n";
3175 std::cerr <<
"created pcGainFact shmim\n";
3186 std::cerr <<
"created pcMultFact shmim\n";
3194 static_cast<void>(
dummy );
3419 static_cast<void>(
dummy );
3438 if( !
lock.owns_lock() )
3464 static_cast<void>(
dummy );
3471 static_cast<void>(
dummy );
3478 float *
f =
static_cast<float *
>(
curr_src );
3486 for(
size_t n = 0;
n <
sz; ++
n )
3506 std::cerr <<
"got freq: " <<
sz <<
'\n';
3507 std::cerr <<
" fps: " <<
m_fps <<
'\n';
3518 static_cast<void>(
dummy );
3530 static_cast<void>(
dummy );
3533 float *
g =
static_cast<float *
>(
curr_src );
3562 std::cerr <<
"got gains: " <<
m_gainFacts.size() <<
"\n";
3577 static_cast<void>(
dummy );
3589 static_cast<void>(
dummy );
3592 float *
m =
static_cast<float *
>(
curr_src );
3621 std::cerr <<
"got mcs: " <<
m_multFacts.size() <<
" " << w <<
"\n";
3636 static_cast<void>(
dummy );
3648 static_cast<void>(
dummy );
3651 float *
g =
static_cast<float *
>(
curr_src );
3680 std::cerr <<
"got pc gains: " <<
m_pcGainFacts.size() <<
"\n";
3695 static_cast<void>(
dummy );
3707 static_cast<void>(
dummy );
3710 float *
m =
static_cast<float *
>(
curr_src );
3754 static_cast<void>(
dummy );
3761 std::cerr <<
"numpccoeffShmimMonitorT::allocate\n";
3767 static_cast<void>(
dummy );
3838 std::cerr <<
"got num pc coeffs: " <<
m_Na.size() <<
"\n";
3846 static_cast<void>(
dummy );
3853 static_cast<void>(
dummy );
3872 m_as.resize( w - 1, h );
3924 std::cerr <<
"got a coeffs: " << w <<
' ' << h <<
' ' <<
m_NaCurrent.size() <<
"\n";
3932 static_cast<void>(
dummy );
3939 static_cast<void>(
dummy );
3959 m_bs.resize( w - 1, h );
4010 std::cerr <<
"got b coeffs: " << w <<
' ' << h <<
' ' <<
m_NbCurrent.size() <<
"\n";
4020 static_cast<void>(
dummy );
4027 static_cast<void>(
dummy );
4052 float *
g =
static_cast<float *
>(
curr_src );
4076 std::cerr <<
"got gainCals: " <<
m_gainCals.size() <<
"\n";
4085 static_cast<void>(
dummy );
4092 static_cast<void>(
dummy );
4116 float *
g =
static_cast<float *
>(
curr_src );
4140 std::cerr <<
"got gainCalsFacts: " <<
m_gainCalFacts.size() <<
"\n";
4149 static_cast<void>(
dummy );
4156 static_cast<void>(
dummy );
4180 float *t =
static_cast<float *
>(
curr_src );
4205 std::cerr <<
"got taus: " <<
m_taus.size() <<
"\n";
4213 static_cast<void>(
dummy );
4220 static_cast<void>(
dummy );
4244 mx::improc::eigenMap<float>
np(
static_cast<float *
>(
curr_src ), 3, h );
4278 static_cast<void>(
dummy );
4286 static_cast<void>(
dummy );
4291 m_wfsavg = mx::improc::eigenMap<float>(
reinterpret_cast<float *
>(
curr_src ),
4306 static_cast<void>(
dummy );
4314 static_cast<void>(
dummy );
4336 static std::vector<bool>
logged( 50,
false );
4674 std::cerr <<
"check sizes failed\n";
4704#pragma omp parallel for num_threads( 15 )
4781 const float tiny = std::numeric_limits<float>::min();
4837 const float tiny = std::numeric_limits<float>::min();
4891 "error processing modal PSD with method " +
4893 std::string( mx::errorName(
errc ) ) +
"] " +
4894 mx::errorMessage(
errc ) } );
4896 "extrapolation settings: noiseDomain=" +
processConfig.m_noiseEstimateDomain +
4898 " noiseStatistic=" +
processConfig.m_noiseEstimateStatistic +
4899 " noiseLowMax=" + std::to_string(
processConfig.m_noiseEstimateLowFreqMaxHz ) +
4900 " olEstimateMethod=" +
processConfig.m_closedLoopOlEstimateMethod +
4901 " match=" + std::to_string(
processConfig.m_powerLawMatchFreq ) +
4902 " matchWindow=" + std::to_string(
processConfig.m_powerLawMatchFallbackWindowHz ) +
4904 " autoSmooth=" + std::to_string(
processConfig.m_powerLawAutoSmoothWidthHz ) +
4905 " autoMaxFrac=" + std::to_string(
processConfig.m_powerLawAutoMaxFreqFraction ) +
4906 " fitIndex=" + std::string(
processConfig.m_fitPowerLawIndex ?
"true" :
"false" ) +
4907 " fitMin=" + std::to_string(
processConfig.m_powerLawFitMinFreqHz ) +
4908 " fitMax=" + std::to_string(
processConfig.m_powerLawFitMaxFreqHz ) +
4909 " fitBin=" + std::to_string(
processConfig.m_powerLawFitBinWidthHz ) +
4910 " blendBins=" + std::to_string(
processConfig.m_powerLawBlendBins ) +
4911 " peakWidth=" + std::to_string(
processConfig.m_peakDetectWidthHz ) +
4912 " peakFactor=" + std::to_string(
processConfig.m_peakDetectFactor ) +
4913 " peakBroadFactor=" + std::to_string(
processConfig.m_peakDetectBroadFactor ) +
4914 " peakMinWidthLog=" + std::to_string(
processConfig.m_peakDetectMinWidthLog ) +
4915 " peakPasses=" + std::to_string(
processConfig.m_peakDetectPasses ) +
4916 " peakBeta=" + std::to_string(
processConfig.m_peakMoffatBeta ) +
4917 " dropoutGap=" + std::to_string(
processConfig.m_dropoutGapFactor ) +
4918 " dropoutTiny=" + std::to_string(
processConfig.m_dropoutTinyFactor ) +
4919 " dropoutMaxBins=" + std::to_string(
processConfig.m_dropoutMaxBins ) +
4920 " powerLawOnlyAbove=" + std::to_string(
processConfig.m_powerLawOnlyAboveFreq ),
4946 const float tiny = std::numeric_limits<float>::min();
5258 std::cerr <<
"Optimization took " <<
dt.count() <<
" seconds\n";
5363 m_olPSDs[0].size() *
sizeof(
float ) );
5374 m_nPSDs[0].size() *
sizeof(
float ) );
5433(
const pcf::IndiProperty &
ipRecv )
5441 std::lock_guard<std::mutex>
lock( m_goptMutex );
5443 if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::On )
5449 m_autoUpdate =
true;
5457 m_autoUpdate =
false;
5468(
const pcf::IndiProperty &
ipRecv )
5474 std::lock_guard<std::mutex>
lock( m_goptMutex );
5476 if(
ipRecv[
"request"].getSwitchState() == pcf::IndiElement::On )
5478 m_updateOnce =
true;
5482 m_updateOnce =
false;
5490(
const pcf::IndiProperty &
ipRecv )
5494 if(
ipRecv.find(
"request" ) )
5496 std::lock_guard<std::mutex>
lock( m_goptMutex );
5498 if(
ipRecv[
"request"].getSwitchState() == pcf::IndiElement::On )
5512(
const pcf::IndiProperty &
ipRecv )
5517 if( indiTargetUpdate( m_indiP_opticalGain,
target,
ipRecv,
true ) < 0 )
5519 log<software_error>( { __FILE__, __LINE__ } );
5526 std::lock_guard<std::mutex>
lock( m_goptMutex );
5536(
const pcf::IndiProperty &
ipRecv )
5540 if(
ipRecv.find(
"toggle" ) )
5544 std::lock_guard<std::mutex>
lock( m_goptMutex );
5546 if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::Off )
5548 m_opticalGainUpdate =
false;
5552 m_opticalGainUpdate =
true;
5554 if( m_opticalGainSource > 0 && m_opticalGainSource < 1 )
5568(
const pcf::IndiProperty &
ipRecv )
5576 std::lock_guard<std::mutex>
lock( m_goptMutex );
5578 float opticalg =
ipRecv[m_opticalGainElement].get<
float>();
5580 opticalg = ( floor( opticalg * 100 + 0.5 ) ) / 100.;
5582 if( opticalg > 0 && opticalg < 1 )
5584 m_opticalGainSource = opticalg;
5587 if( m_opticalGainUpdate )
5599(
const pcf::IndiProperty &
ipRecv )
5604 if( indiTargetUpdate( m_indiP_gainGain,
target,
ipRecv,
true ) < 0 )
5606 log<software_error>( { __FILE__, __LINE__ } );
5613 std::lock_guard<std::mutex>
lock( m_goptMutex );
5623(
const pcf::IndiProperty &
ipRecv )
5628 if( indiTargetUpdate( m_indiP_gainLeak,
target,
ipRecv,
true ) < 0 )
5630 log<software_error>( { __FILE__, __LINE__ } );
5637 std::lock_guard<std::mutex>
lock( m_goptMutex );
5647(
const pcf::IndiProperty &
ipRecv )
5651 if(
ipRecv.find(
"request" ) )
5653 std::lock_guard<std::mutex>
lock( m_goptMutex );
5655 if(
ipRecv[
"request"].getSwitchState() == pcf::IndiElement::On )
5657 std::fill( m_optGainSI.begin(), m_optGainSI.end(), 0.0F );
5658 m_siGainStateNeedsSync =
false;
5663 m_zeroGains =
false;
5670template <
typename valueT>
5672 valueT &localTarget,
5673 const pcf::IndiProperty &
ipRecv,
5674 const std::string &label )
5701 const pcf::IndiProperty &
ipRecv,
5702 const std::string &label )
5706 if( !
ipRecv.find(
"toggle" ) )
5711 bool target =
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::On;
5735 if(
elit->second.getSwitchState() != pcf::IndiElement::On )
5742 return log<
software_error, -1>( {
"Multiple extrapolation methods selected in one update" } );
5801 if(
elit->second.getSwitchState() != pcf::IndiElement::On )
5808 return log<
software_error, -1>( {
"Multiple noise-estimate domains selected in one update" } );
5872 if(
elit->second.getSwitchState() != pcf::IndiElement::On )
5879 return log<
software_error, -1>( {
"Multiple noise-estimate ranges selected in one update" } );
5940 if(
elit->second.getSwitchState() != pcf::IndiElement::On )
5947 return log<
software_error, -1>( {
"Multiple noise-estimate statistics selected in one update" } );
6011 if(
elit->second.getSwitchState() != pcf::IndiElement::On )
6018 return log<
software_error, -1>( {
"Multiple closed-loop OL estimate methods selected in one update" } );
6025 return log<
software_error, -1>( {
"Invalid closed-loop-OL-estimate-method element: " +
elit->first } );
6082 if(
elit->second.getSwitchState() != pcf::IndiElement::On )
6089 return log<
software_error, -1>( {
"Multiple power-law crossover modes selected in one update" } );
6148(
const pcf::IndiProperty &
ipRecv )
6155(
const pcf::IndiProperty &
ipRecv )
6162(
const pcf::IndiProperty &
ipRecv )
6169(
const pcf::IndiProperty &
ipRecv )
6176(
const pcf::IndiProperty &
ipRecv )
6180 m_extrapConfig.m_noiseEstimateLowFreqMaxHz,
6182 "extrap noise-estimate low-freq max hz" );
6186(
const pcf::IndiProperty &
ipRecv )
6193(
const pcf::IndiProperty &
ipRecv )
6197 m_extrapConfig.m_powerLawIndex,
6199 "extrap power-law index" );
6203(
const pcf::IndiProperty &
ipRecv )
6207 m_extrapConfig.m_powerLawNormFreq,
6209 "extrap power-law norm freq" );
6213(
const pcf::IndiProperty &
ipRecv )
6217 m_extrapConfig.m_powerLawMatchFreq,
6219 "extrap power-law match freq" );
6223(
const pcf::IndiProperty &
ipRecv )
6227 m_extrapConfig.m_powerLawMatchFallbackWindowHz,
6229 "extrap power-law match fallback window" );
6233(
const pcf::IndiProperty &
ipRecv )
6240(
const pcf::IndiProperty &
ipRecv )
6244 m_extrapConfig.m_powerLawAutoSmoothWidthHz,
6246 "extrap power-law auto smooth width" );
6250(
const pcf::IndiProperty &
ipRecv )
6254 m_extrapConfig.m_powerLawAutoMaxFreqFraction,
6256 "extrap power-law auto max freq fraction" );
6260(
const pcf::IndiProperty &
ipRecv )
6264 m_extrapConfig.m_fitPowerLawIndex,
6266 "extrap fit power-law index" );
6270(
const pcf::IndiProperty &
ipRecv )
6274 m_extrapConfig.m_powerLawOnlyAboveFreq,
6276 "extrap power-law only above freq" );
6280(
const pcf::IndiProperty &
ipRecv )
6284 m_extrapConfig.m_powerLawFitIncludesMatchPoint,
6286 "extrap fit includes match point" );
6290(
const pcf::IndiProperty &
ipRecv )
6294 m_extrapConfig.m_powerLawFitMinFreqHz,
6296 "extrap fit min freq" );
6300(
const pcf::IndiProperty &
ipRecv )
6304 m_extrapConfig.m_powerLawFitMaxFreqHz,
6306 "extrap fit max freq" );
6310(
const pcf::IndiProperty &
ipRecv )
6314 m_extrapConfig.m_powerLawFitBinWidthHz,
6316 "extrap fit bin width" );
6320(
const pcf::IndiProperty &
ipRecv )
6324 m_extrapConfig.m_powerLawBlendBins,
6326 "extrap power-law blend bins" );
6330(
const pcf::IndiProperty &
ipRecv )
6334 m_extrapConfig.m_dropoutGapFactor,
6336 "extrap dropout gap factor" );
6340(
const pcf::IndiProperty &
ipRecv )
6344 m_extrapConfig.m_dropoutTinyFactor,
6346 "extrap dropout tiny factor" );
6350(
const pcf::IndiProperty &
ipRecv )
6354 m_extrapConfig.m_dropoutMaxBins,
6356 "extrap dropout max bins" );
6360(
const pcf::IndiProperty &
ipRecv )
6364 m_extrapConfig.m_clSignificanceThreshold,
6366 "extrap CL significance threshold" );
6370(
const pcf::IndiProperty &
ipRecv )
6374 m_extrapConfig.m_clMinSignificantFraction,
6376 "extrap CL minimum significant fraction" );
6380(
const pcf::IndiProperty &
ipRecv )
6384 if(
ipRecv.find(
"current" ) )
6386 std::lock_guard<std::mutex>
lock( m_goptMutex );
6388 float emg =
ipRecv[
"current"].get<
float>();
6393 std::cerr <<
"Got EMG: " << m_emg <<
'\n';
6400(
const pcf::IndiProperty &
ipRecv )
6404 if(
ipRecv.find(
"current" ) )
6406 float psdTime =
ipRecv[
"current"].get<
float>();
6408 if( psdTime != m_psdTime )
6411 std::lock_guard<std::mutex>
lock( m_goptMutex );
6414 m_psdTime = psdTime;
6419 std::cerr <<
"Got psdTime: " << m_psdTime <<
'\n';
6426(
const pcf::IndiProperty &
ipRecv )
6430 if(
ipRecv.find(
"current" ) )
6432 float psdAvgTime =
ipRecv[
"current"].get<
float>();
6434 if( psdAvgTime != m_psdAvgTime )
6437 std::lock_guard<std::mutex>
lock( m_goptMutex );
6440 m_psdAvgTime = psdAvgTime;
6445 std::cerr <<
"Got psdAvgTime: " << m_psdAvgTime <<
'\n';
6453(
const pcf::IndiProperty &
ipRecv )
6457 if(
ipRecv.find(
"toggle" ) )
6460 bool changed{
false };
6462 if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::On )
6471 if( state != m_loop )
6476 std::lock_guard<std::mutex>
lock( m_goptMutex );
6483 m_autoUpdate =
false;
6489 std::cerr <<
"Got loop: " << m_loop <<
'\n';
6502(
const pcf::IndiProperty &
ipRecv )
6506 if(
ipRecv.find(
"current" ) )
6508 float gain =
ipRecv[
"current"].get<
float>();
6510 if( gain != m_gain && !m_pcOn )
6513 std::lock_guard<std::mutex>
lock( m_goptMutex );
6525 std::cerr <<
"Got gain: " << m_gain <<
'\n';
6537(
const pcf::IndiProperty &
ipRecv )
6541 if(
ipRecv.find(
"current" ) )
6543 float mc =
ipRecv[
"current"].get<
float>();
6545 if( mc != m_mult && !m_pcOn )
6548 std::lock_guard<std::mutex>
lock( m_goptMutex );
6558 m_goptUpdated =
true;
6560 std::cerr <<
"Got mc: " << m_mult <<
'\n';
6572(
const pcf::IndiProperty &
ipRecv )
6576 if(
ipRecv.find(
"current" ) )
6578 float gain =
ipRecv[
"current"].get<
float>();
6580 if( gain != m_pcGain && m_pcOn )
6583 std::lock_guard<std::mutex>
lock( m_goptMutex );
6595 std::cerr <<
"Got pc gain: " << m_pcGain <<
'\n';
6607(
const pcf::IndiProperty &
ipRecv )
6611 if(
ipRecv.find(
"current" ) )
6613 float mc =
ipRecv[
"current"].get<
float>();
6615 if( mc != m_pcMult && m_pcOn )
6618 std::lock_guard<std::mutex>
lock( m_goptMutex );
6628 m_pcgoptUpdated =
true;
6630 std::cerr <<
"Got pc mc: " << m_pcMult <<
'\n';
6642(
const pcf::IndiProperty &
ipRecv )
6646 if(
ipRecv.find(
"toggle" ) )
6650 if(
ipRecv[
"toggle"].getSwitchState() == pcf::IndiElement::On )
6659 if( state != m_pcOn )
6662 std::lock_guard<std::mutex>
lock( m_goptMutex );
6669 std::cerr <<
"Got pcOn: " << std::boolalpha << m_pcOn <<
'\n';
#define XWCAPP_THREAD_CHECK(thrdSt, thrdName)
Error handling wrapper for checking on thread status with tryjoin.
#define XWCAPP_THREAD_START(thrdSt, thrdInit, thrdId, thrdProp, thrdPrio, thrdCpuset, thrdName, thrdStart)
Error handling wrapper for the threadStart function of the XWCApp.
#define XWCAPP_THREAD_STOP(thrdSt)
Error handlng wrapper for stopping a thread.
The base-class for XWCTk applications.
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.
int m_shutdown
Flag to signal it's time to shutdown. When not 0, the main loop exits.
int shutdown()
Get the value of the shutdown flag.
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.
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.
int indiTargetUpdate(pcf::IndiProperty &localProperty, T &localTarget, const pcf::IndiProperty &remoteProperty, bool setBusy=true)
Get the target element value from an new property.
uint32_t m_width
The width of the images in the stream.
const uint8_t & dataType() const
uint32_t m_height
The height of the images in the stream.
IMAGE m_imageStream
The ImageStreamIO shared memory buffer.
int create(uint32_t width, uint32_t height, uint32_t depth, uint8_t datatype, void *initData=nullptr)
Create the image.
const uint32_t & width() const
uint8_t m_dataType
The ImageStreamIO type code.
shmimMonitorState m_smState
The MagAO-X PSD-based gain optimizer.
int countEnabledGainFactors(const std::vector< float > &gainFacts) const
Count how many modes are enabled by a gain-factor vector.
void destroyImageStream(IMAGE *&stream)
Destroy an owned ImageStreamIO output stream and clear its pointer.
pcf::IndiProperty m_indiP_emg
std::vector< mx::AO::analysis::clGainOpt< float > > m_goptCurrent
Each mode gets its own gain optimizer.
pcf::IndiProperty m_indiP_extrapPowerLawNormFreq
pcf::IndiProperty m_indiP_extrapClMinSignificantFraction
int recordTelem(const telem_modalgainopt *)
void updateAppliedModeCount(const std::vector< float > &gainFacts, bool predictorPath)
eigenImage< float > m_wfsavg
IMAGE * m_optGainSIRawStream
pcf::IndiProperty m_indiP_gainGain
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawIndex)
pcf::IndiProperty m_indiP_extrapNoiseEstimateLowFreqMaxHz
void syncSiGainStateFromAppliedGains()
Synchronize the integrated SI gain state from the applied gain-factor stream.
int m_extrapPowerLawCrossoverMode
std::string m_clXferSIShmimName
std::vector< uint32_t > m_NbCurrent
std::string m_clNtfLPShmimName
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_updateOnce)
std::string m_clXferCurrentShmimName
pcf::IndiProperty m_indiP_extrapDropoutTinyFactor
dev::shmimMonitor< modalGainOpt, numpccoeffShmimT > numpccoeffShmimMonitorT
pcf::IndiProperty m_indiP_extrapNoiseEstimateRange
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapClSignificanceThreshold)
mx::improc::eigenImage< float > m_clNtfLP
Published predictive closed-loop noise transfer function.
mx::improc::eigenImage< float > m_clXferCurrent
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawFitBinWidthHz)
~modalGainOpt() noexcept
D'tor, declared and defined for noexcept.
std::vector< float > m_modeVarCL
int handleExtrapPowerLawCrossoverModeProperty(const pcf::IndiProperty &ipRecv)
Handle the power-law crossover-mode selection switch property.
dev::shmimMonitor< modalGainOpt, wfsmaskShmimT > wfsmaskShmimMonitorT
std::vector< int > m_regCounter
Counters to track when this mode was last regularized.
pcf::IndiProperty m_indiP_extrapClSignificanceThreshold
int handleExtrapNoiseEstimateDomainProperty(const pcf::IndiProperty &ipRecv)
Handle the noise-estimation-domain selection switch property.
std::vector< float > m_gmaxLP
The previously calculated maximum gains for LP.
std::vector< float > m_pcGainFacts
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapClMinSignificantFraction)
std::vector< mx::AO::analysis::clGainOpt< float > > m_goptLP
std::string m_optGainSIShmimName
pcf::IndiProperty m_indiP_extrapPowerLawFitMaxFreqHz
std::chrono::time_point< std::chrono::steady_clock > timePointT
dev::shmimMonitor< modalGainOpt, pcGainFactShmimT > pcGainFactShmimMonitorT
pid_t m_goptThreadID
gain optimization thread PID.
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_autoUpdate)
pcf::IndiProperty m_indiP_extrapDropoutMaxBins
bool applyMultiplierUpdate(std::vector< float > &multFacts, const float *incoming, uint32_t width, bool predictorPath)
dev::shmimMonitor< modalGainOpt, pcMultFactShmimT > pcMultFactShmimMonitorT
std::vector< float > m_taus
dev::shmimMonitor< modalGainOpt, gainCalShmimT > gainCalShmimMonitorT
pcf::IndiProperty m_indiP_extrapPowerLawMatchFallbackWindowHz
float m_psdOverlapFraction
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapMethod)
int allocate(const psdShmimT &)
std::vector< int > m_timesOnLP
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_dump)
int handleExtrapMethodProperty(const pcf::IndiProperty &ipRecv)
Handle the extrapolation-method selection switch property.
std::vector< std::vector< float > > m_rawOlPSDs
std::string m_modevarShmimName
std::vector< float > m_freq
pcf::IndiProperty m_indiP_siGain
virtual int appLogic()
Implementation of the FSM for modalGainOpt.
std::vector< float > m_modeVarSI
pcf::IndiProperty m_indiP_extrapFitPowerLawIndex
pcf::IndiProperty m_indiP_autoUpdate
std::vector< float > m_gainCalFacts
pcf::IndiProperty m_indiP_dump
mx::improc::eigenImage< float > m_clNtfSI
std::vector< float > m_gainFacts
std::string m_optGainSIRawShmimName
dev::shmimMonitor< modalGainOpt, bcoeffShmimT > bcoeffShmimMonitorT
int checkSizes()
Check that all sizes and allocations have occurred.
pcf::IndiProperty m_indiP_extrapPowerLawOnlyAboveFreq
int m_goptThreadPrio
Priority of the gain optimization thread.
pcf::IndiProperty m_indiP_opticalGainUpdate
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_pcOn)
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawMatchFallbackWindowHz)
std::vector< float > m_optGainLP
int createImageStream(IMAGE *&stream, const std::string &name, uint32_t size0, uint32_t size1, uint32_t size2, uint8_t dataType)
Allocate and create an owned ImageStreamIO output stream.
std::string m_maxGainSIShmimName
bool refreshGoptStructures()
IMAGE * m_optGainLPStream
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapDropoutTinyFactor)
pcf::IndiProperty m_indiP_extrapNoiseEstimateDomain
std::string m_goptThreadCpuset
pcf::IndiProperty m_indiP_loop
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_siGain)
int handleExtrapClosedLoopOlEstimateMethodProperty(const pcf::IndiProperty &ipRecv)
Handle the closed-loop OL-estimation-method selection switch property.
mx::improc::eigenImage< float > m_clPSDs
dev::shmimMonitor< modalGainOpt, wfsavgShmimT > wfsavgShmimMonitorT
std::vector< float > m_gmaxSI
The previously calculated maximum gains for SI.
std::vector< std::vector< float > > m_smoothOlPSDs
pcf::IndiProperty m_indiP_siMult
pcf::IndiProperty m_indiP_pcOn
processPsdProcessorT::processModelConfig m_extrapConfig
Configuration of the OL PSD extrapolation model.
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapFitPowerLawIndex)
std::vector< std::vector< float > > m_olPSDs
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_loop)
eigenImage< float > m_wfsmask
std::string m_clXferLPShmimName
pcf::IndiProperty m_indiP_modesOn
std::string m_olPSDShmimName
bool applyFrequencyUpdate(const float *incoming, size_t size)
Apply an incoming frequency frame to the stored frequency scale.
int handleExtrapNumberProperty(pcf::IndiProperty &localProperty, valueT &localTarget, const pcf::IndiProperty &ipRecv, const std::string &label)
Handle a standard target/current numeric extrapolation property update.
mx::improc::eigenImage< float > m_clXferLP
Published predictive closed-loop error transfer function.
dev::shmimMonitor< modalGainOpt, freqShmimT > freqShmimMonitorT
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawBlendBins)
virtual void loadConfig()
std::string m_loopName
The name of the loop control INDI device name.
std::chrono::duration< double > durationT
int handleExtrapToggleProperty(pcf::IndiProperty &localProperty, bool &localTarget, const pcf::IndiProperty &ipRecv, const std::string &label)
Handle a boolean extrapolation toggle property update.
std::string m_opticalGainDevice
dev::shmimMonitor< modalGainOpt, gainFactShmimT > gainFactShmimMonitorT
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawMatchFreq)
IMAGE * m_maxGainLPStream
pcf::IndiProperty m_indiP_extrapPowerLawFitIncludesMatchPoint
bool m_updateOnce
Flag to trigger a single update with gain.
pcf::IndiProperty m_indiP_extrapPowerLawAutoSmoothWidthHz
pcf::IndiProperty m_indiP_updateOnce
int recordModalGainOpt(bool force=false)
dev::shmimMonitor< modalGainOpt, tauShmimT > tauShmimMonitorT
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_zeroGains)
eigenImage< float > m_noiseParams
std::string m_clNtfCurrentShmimName
std::vector< mx::AO::analysis::clAOLinearPredictor< float > > m_linPred
pcf::IndiProperty m_goptThreadProp
std::string m_smoothOlPSDShmimName
static void goptThreadStart(modalGainOpt *p)
Gain Optimization thread starter function.
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_psdAvgTime)
IMAGE * m_clNtfCurrentStream
mx::improc::eigenImage< float > m_clNtfCurrent
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapNoiseEstimateDomain)
void updateIntegratedSiGain(size_t modeIndex)
Apply one SI leaky-integrator update from the raw optimal gain.
bool m_dump
Flag to trigger a single update with no gain.
void writePublishedPredictorArrays(float *pcGainData, float *aCoeffData, uint32_t aWidth, float *bCoeffData, uint32_t bWidth, bool blend)
Populate the published predictive-control gain and coefficient arrays.
mx::improc::eigenImage< float > m_clXferSI
std::string m_opticalGainProperty
pcf::IndiProperty m_indiP_extrapPowerLawCrossoverMode
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapNoiseEstimateRange)
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawAutoMaxFreqFraction)
bool m_goptSemaphoreInit
Tracks whether the gain optimization semaphore needs cleanup.
pcf::IndiProperty m_indiP_psdAvgTime
std::vector< float > m_modeVarLP
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_opticalGainSource)
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawFitMaxFreqHz)
pcf::IndiProperty m_indiP_extrapDropoutGapFactor
std::vector< float > m_optGainSI
The leaky-integrated SI optimal gains.
IMAGE * m_optGainSIStream
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_gainLeak)
IMAGE * m_clXferCurrentStream
std::atomic< bool > m_updating
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_psdTime)
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
bool m_zeroGains
Flag requesting the SI gain integrator state be zeroed.
int handleExtrapNoiseEstimateStatisticProperty(const pcf::IndiProperty &ipRecv)
Handle the noise-estimation-statistic selection switch property.
std::vector< float > m_gainCals
virtual int appStartup()
Startup function.
void writePublishedGainArrays(float *currentData, float *siRawData, float *siData, float *maxSiData, float *lpData, float *maxLpData, float *modeVarData)
std::thread m_goptThread
The gain optimization thread.
void goptThreadExec()
Gain optimization thread function.
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawAutoSmoothWidthHz)
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_opticalGain)
pcf::IndiProperty m_indiP_opticalGain
dev::shmimMonitor< modalGainOpt, psdShmimT > psdShmimMonitorT
std::string m_noisePSDShmimName
IMAGE * m_smoothOlPSDStream
virtual void setupConfig()
pcf::IndiProperty m_indiP_gainLeak
pcf::IndiProperty m_indiP_extrapPowerLawIndex
virtual int appShutdown()
Shutdown the app.
bool m_goptThreadInit
Initialization flag for the gain optimization thread.
int processImage(void *curr_src, const psdShmimT &)
std::vector< float > m_modeVarOL
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawFitMinFreqHz)
std::string m_optGainShmimName
std::vector< float > m_pcMultFacts
std::string m_clNtfSIShmimName
pcf::IndiProperty m_indiP_extrapMethod
std::mutex m_goptMutex
Mutex for synchronizing updates.
dev::shmimMonitor< modalGainOpt, multFactShmimT > multFactShmimMonitorT
pcf::IndiProperty m_indiP_extrapPowerLawFitBinWidthHz
bool m_siGainStateNeedsSync
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_siMult)
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_emg)
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapNoiseEstimateStatistic)
int handleExtrapNoiseEstimateRangeProperty(const pcf::IndiProperty &ipRecv)
Handle the noise-estimation-range selection switch property.
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawNormFreq)
bool m_autoUpdate
Flag controlling whether gains are automatically updated.
dev::shmimMonitor< modalGainOpt, gainCalFactShmimT > gainCalFactShmimMonitorT
pcf::IndiProperty m_indiP_zeroGains
std::vector< uint32_t > m_NaCurrent
std::vector< int > m_timesOnSI
int m_extrapNoiseEstimateRange
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapClosedLoopOlEstimateMethod)
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_pcMult)
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapNoiseEstimateLowFreqMaxHz)
std::string m_rawOlPSDShmimName
std::string m_optGainLPShmimName
int m_extrapOL
Which extrapolation method to use for the OL PSD.
std::string m_maxGainLPShmimName
std::vector< float > m_multFacts
dev::shmimMonitor< modalGainOpt, acoeffShmimT > acoeffShmimMonitorT
std::vector< float > m_regScale
The regularization scale factors for each mode.
pcf::IndiProperty m_indiP_opticalGainSource
pcf::IndiProperty m_indiP_extrapNoiseEstimateStatistic
int m_extrapNoiseEstimateStatistic
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawCrossoverMode)
pcf::IndiProperty m_indiP_extrapPowerLawBlendBins
pcf::IndiProperty m_indiP_extrapPowerLawAutoMaxFreqFraction
std::vector< uint32_t > m_Nb
int m_extrapNoiseEstimateDomain
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_opticalGainUpdate)
std::vector< std::vector< float > > m_nPSDs
int m_extrapClosedLoopOlEstimateMethod
IMAGE * m_maxGainSIStream
float m_gainGain
The gain to use for SI gain correction updates. Default is 0.1.
pcf::IndiProperty m_indiP_pcGain
std::vector< mx::AO::analysis::clGainOpt< float > > m_goptSI
dev::shmimMonitor< modalGainOpt, noiseShmimT > noiseShmimMonitorT
pcf::IndiProperty m_indiP_extrapClosedLoopOlEstimateMethod
INDI_SETCALLBACK_DECL(modalGainOpt, m_indiP_pcGain)
bool applyGainFactorUpdate(std::vector< float > &gainFacts, const float *incoming, uint32_t width, bool predictorPath)
Apply an incoming gain-factor frame to one of the stored gain vectors.
pcf::IndiProperty m_indiP_extrapPowerLawMatchFreq
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_gainGain)
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapDropoutMaxBins)
std::vector< uint32_t > m_Na
pcf::IndiProperty m_indiP_psdTime
int m_nRegCycles
How often to regularize each mode.
pcf::IndiProperty m_indiP_pcMult
float m_gainLeak
The leak factor used for SI gain integration. Default is 0.9.
pcf::IndiProperty m_indiP_extrapPowerLawFitMinFreqHz
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapDropoutGapFactor)
std::vector< float > m_optGainSIRaw
The raw SI optimal gains before leaky integration.
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawOnlyAboveFreq)
INDI_NEWCALLBACK_DECL(modalGainOpt, m_indiP_extrapPowerLawFitIncludesMatchPoint)
realT m_dropoutGapFactor
The threshold used to identify dropout bins.
std::string m_noiseEstimateStatistic
realT m_noiseEstimateLowFreqMaxHz
realT m_powerLawMatchFallbackWindowHz
realT m_peakDetectWidthHz
The wide smoothing width used for peak detection.
realT m_peakDetectMinWidthLog
The minimum accepted broad-peak width in log-frequency.
realT m_peakMoffatBeta
The minimum Moffat beta used for synthesized peaks.
bool m_fitPowerLawIndex
Whether to fit the power-law exponent from high-frequency bins.
realT m_dropoutTinyFactor
realT m_powerLawOnlyAboveFreq
Above this frequency, force the extrapolation to be power-law only.
static constexpr realT c_defaultLpContinuumWidthHz
The default LP-continuum smoothing width.
realT m_powerLawNormFreq
The normalization frequency for the power-law continuum.
std::string m_noiseEstimateRange
Which end of the PSD is used to estimate the flat noise floor.
realT m_peakDetectBroadFactor
The lower factor used for broad-peak candidates.
realT m_powerLawAutoSmoothWidthHz
realT m_clSignificanceThreshold
size_t m_dropoutMaxBins
The maximum dropout-run length repaired by the gap-filling logic.
realT m_powerLawFitMaxFreqHz
The high edge of the exponent-fit range.
static mx::error_t estimateNoisePsd(std::vector< realT > &noisePsd, realT &noiseFloor, const std::vector< realT > &measuredPsd, const std::vector< realT > &freq, size_t modeIndex, std::string noiseEstimateRange=c_defaultNoiseEstimateRange, std::string noiseEstimateStatistic=c_defaultNoiseEstimateStatistic, realT noiseEstimateLowFreqMaxHz=c_defaultNoiseEstimateLowFreqMaxHz)
Estimate the flat noise PSD using the configured modalGainOpt statistic.
realT m_peakDetectFactor
The minimum factor above the smoothed PSD for a strong peak.
int m_peakDetectPasses
The number of iterative peak-detection passes.
static mx::error_t analyzePsd(processResults &result, const std::vector< realT > &measuredPsd, const std::vector< realT > &freq, size_t modeIndex, const processModelConfig &config, realT lpContinuumFreq=static_cast< realT >(0), realT lpContinuumWidthHz=c_defaultLpContinuumWidthHz, const std::vector< realT > *etfPsd=nullptr, const std::vector< realT > *ntfPsd=nullptr)
Build the noise PSD, disturbance PSD, and LP continuum PSD for one mode.
realT m_powerLawIndex
The power-law exponent in .
std::string m_powerLawCrossoverMode
How the power-law match/cutoff frequencies are chosen.
std::string m_noiseEstimateDomain
The domain used to estimate the flat noise floor.
realT m_powerLawAutoMaxFreqFraction
std::string m_closedLoopOlEstimateMethod
bool m_powerLawFitIncludesMatchPoint
Whether the match point is included directly in the exponent fit.
realT m_powerLawFitMinFreqHz
The low edge of the exponent-fit range.
realT m_powerLawMatchFreq
realT m_clMinSignificantFraction
std::string m_method
The extrapolation method name.
realT m_powerLawFitBinWidthHz
The width of the exponent-fit median bins.
Configuration of the disturbance-PSD extrapolation model.
Results of modal PSD noise estimation and disturbance extrapolation.
#define INDI_NEWCALLBACK_DEFN(class, prop)
Define the callback for a new property request.
#define CREATE_REG_INDI_NEW_TOGGLESWITCH(prop, name)
Create and register a NEW INDI property as a standard toggle switch, using the standard callback name...
#define CREATE_REG_INDI_NEW_REQUESTSWITCH(prop, name)
Create and register a NEW INDI property as a standard request switch, using the standard callback nam...
#define INDI_NEWCALLBACK(prop)
Get the name of the static callback wrapper for a new property.
#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.
#define CREATE_REG_INDI_NEW_NUMBERI(prop, name, min, max, step, format, label, group)
Create and register a NEW INDI property as a standard number as int, using the standard callback name...
#define INDI_VALIDATE_CALLBACK_PROPS(prop1, prop2)
Standard check for matching INDI properties in a callback.
Header-only template class for modal PSD noise estimation and disturbance extrapolation.
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.
int addNumberElement(pcf::IndiProperty &prop, const std::string &name, const T &min, const T &max, const T &step, const std::string &format, const std::string &label="")
Add a standard INDI Number element.
std::string extrapBoolString(bool value)
recordModalGainOpt(false)
int extrapClosedLoopOlEstimateMethodFromElement(const std::string &element)
modalPsdProcessor< float > processPsdProcessorT
std::string extrapClosedLoopOlEstimateMethodLabel(int method)
return handleExtrapNoiseEstimateStatisticProperty(ipRecv)
int olProcessMethodFromName(std::string method)
return handleExtrapToggleProperty(m_indiP_extrapFitPowerLawIndex, m_extrapConfig.m_fitPowerLawIndex, ipRecv, "extrap fit power-law index")
const pcf::IndiProperty & ipRecv
return handleExtrapNoiseEstimateRangeProperty(ipRecv)
return handleExtrapClosedLoopOlEstimateMethodProperty(ipRecv)
int olProcessMethodFromElement(const std::string &element)
std::string extrapNoiseEstimateDomainElement(int domain)
static constexpr int c_olProcessPowerLawOnly
std::string extrapNoiseEstimateRangeLabel(int range)
std::string extrapNoiseEstimateRangeName(int range)
std::string extrapClosedLoopOlEstimateMethodElement(int method)
std::string extrapNoiseEstimateStatisticElement(int statistic)
std::string extrapPowerLawCrossoverModeElement(int mode)
std::string extrapNoiseEstimateRangeElement(int range)
static constexpr int c_olProcessLegacy
return handleExtrapNoiseEstimateDomainProperty(ipRecv)
static constexpr int c_extrapNoiseEstimateHighFreq
std::string extrapNoiseEstimateDomainName(int domain)
static constexpr int c_extrapPowerLawCrossoverManual
return handleExtrapNumberProperty(m_indiP_extrapNoiseEstimateLowFreqMaxHz, m_extrapConfig.m_noiseEstimateLowFreqMaxHz, ipRecv, "extrap noise-estimate low-freq max hz")
std::string extrapPowerLawCrossoverModeName(int mode)
static constexpr int c_olProcessNone
static constexpr int c_extrapNoiseEstimateMinimum
static constexpr int c_olProcessMoffatPeaks
return handleExtrapPowerLawCrossoverModeProperty(ipRecv)
static constexpr int c_extrapNoiseEstimatePercentile
static constexpr int c_extrapClosedLoopOlEstimateEtfOnly
std::string olProcessMethodElement(int method)
std::string extrapClosedLoopOlEstimateMethodName(int method)
int extrapPowerLawCrossoverModeFromElement(const std::string &element)
static constexpr int c_extrapNoiseEstimateLowFreq
std::string extrapNoiseEstimateStatisticName(int statistic)
int extrapNoiseEstimateDomainFromElement(const std::string &element)
std::string extrapNoiseEstimateStatisticLabel(int statistic)
int extrapNoiseEstimateStatisticFromElement(const std::string &element)
int extrapNoiseEstimateRangeFromElement(const std::string &element)
std::string extrapPowerLawCrossoverModeLabel(int mode)
static constexpr int c_extrapNoiseEstimateOpenLoop
static constexpr int c_extrapNoiseEstimateClosedLoopPreXfer
static constexpr int c_extrapPowerLawCrossoverAutoSmoothedCrossing
int extrapPowerLawCrossoverModeFromName(std::string mode)
int extrapClosedLoopOlEstimateMethodFromName(std::string method)
std::unique_lock< std::mutex > lock(m_indiMutex)
int extrapNoiseEstimateStatisticFromName(std::string statistic)
int extrapNoiseEstimateDomainFromName(std::string domain)
static constexpr int c_extrapClosedLoopOlEstimateNtfAware
std::string extrapNoiseEstimateDomainLabel(int domain)
std::string olProcessMethodLabel(int method)
std::string olProcessMethodName(int method)
int extrapNoiseEstimateRangeFromName(std::string range)
return handleExtrapMethodProperty(ipRecv)
static constexpr logPrioT LOG_NOTICE
A normal but significant condition.
static constexpr logPrioT LOG_CRITICAL
The process can not continue and will shut down (fatal)
#define XWC_SEM_WAIT_TS_RETVOID(ts, sec, nsec)
Add the wait time to a timespec for a sem_timedwait call, with no value returned on error.
#define SHMIMMONITORT_APP_STARTUP(SHMIMMONITORT)
Call shmimMonitorT::appStartup with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITORT_UPDATE_INDI(SHMIMMONITORT)
Call shmimMonitorT::updateINDI with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITORT_SETUP_CONFIG(SHMIMMONITORT, cfig)
Call shmimMonitorT::setupConfig with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITORT_APP_LOGIC(SHMIMMONITORT)
Call shmimMonitorT::appLogic with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITORT_APP_SHUTDOWN(SHMIMMONITORT)
Call shmimMonitorT::appShutodwn with error checking for a typedef-ed shmimMonitor.
#define SHMIMMONITORT_LOAD_CONFIG(SHMIMMONITORT, cfig)
Call shmimMonitorT::loadConfig with error checking for a typedef-ed shmimMonitor.
static std::string configSection()
static std::string indiPrefix()
static std::string indiPrefix()
static std::string configSection()
A device base class which saves telemetry.
int appShutdown()
Perform telemeter application shutdown.
int loadConfig(appConfigurator &config)
Load the device section from an application configurator.
int appLogic()
Perform telemeter application logic.
int setupConfig(appConfigurator &config)
Setup an application configurator for the device section.
int appStartup()
Starts the telemetry log thread.
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()
static std::string configSection()
static std::string configSection()
static std::string indiPrefix()
static std::string indiPrefix()
static std::string configSection()
static std::string configSection()
static std::string indiPrefix()
static std::string configSection()
static std::string indiPrefix()
static std::string indiPrefix()
static std::string configSection()
static std::string indiPrefix()
static std::string configSection()
static std::string configSection()
static std::string indiPrefix()
static std::string indiPrefix()
static std::string configSection()
static std::string configSection()
static std::string indiPrefix()
@ OPERATING
The device is operating, other than homing.
static std::string indiPrefix()
static std::string configSection()
Tag type for the live WFS average shmim monitor.
static std::string configSection()
static std::string indiPrefix()
Tag type for the WFS mask shmim monitor.
static std::string indiPrefix()
static std::string configSection()
Software CRITICAL log entry.
Log entry recording modalGainOpt control state.