11 #include "../../libMagAOX/libMagAOX.hpp"
12 #include "../../magaox_git_version.h"
14 #include <mx/sigproc/circularBuffer.hpp>
15 #include <mx/sigproc/signalWindows.hpp>
17 #include <mx/math/fft/fftwEnvironment.hpp>
18 #include <mx/math/fft/fft.hpp>
55 typedef mx::sigproc::circularBufferIndex<float *, unsigned>
ampCircBuffT;
101 mx::math::fft::fftT< realT, std::complex<realT>, 1, 0>
m_fft;
215 config.add(
"circBuff.fpsSource",
"",
"circBuff.fpsSource", argType::Required,
"circBuff",
"fpsSource",
false,
"string",
"Device name for getting fps to set circular buffer length. This device should have *.fps.current.");
216 config.add(
"circBuff.defaultFPS",
"",
"circBuff.defaultFPS", argType::Required,
"circBuff",
"defaultFPS",
false,
"realT",
"Default FPS at startup, will enable changing average length with psdTime before INDI available.");
217 config.add(
"circBuff.psdTime",
"",
"circBuff.psdTime", argType::Required,
"circBuff",
"psdTime",
false,
"realT",
"The length of time over which to calculate PSDs. The default is 1 sec.");
225 _config(
m_fps,
"circBuff.defaultFPS");
238 createStandardIndiNumber<unsigned>(
m_indiP_psdTime,
"psdTime", 0, 60, 0.1,
"%0.1f");
244 log<software_error>({__FILE__,__LINE__});
248 createStandardIndiNumber<unsigned>(
m_indiP_psdTime,
"psdAvgTime", 0, 60, 0.1,
"%0.1f");
254 log<software_error>({__FILE__,__LINE__});
269 log<software_error>({__FILE__,__LINE__});
280 log<software_error>({__FILE__, __LINE__});
300 log<software_error>({__FILE__, __LINE__});
312 pthread_kill(
m_psdThread.native_handle(), SIGUSR1);
327 static_cast<void>(dummy);
345 log<software_error>({__FILE__,__LINE__,
"bad m_tsOverlapSize value: " + std::to_string(
m_tsOverlapSize)});
353 log<software_error>({__FILE__,__LINE__,
"unsupported data type: must be realT"});
361 log<software_error>({__FILE__,__LINE__,
"unexpected shmim format"});
375 mx::sigproc::window::hann(
m_win);
403 imsize[1] =
m_psd.size();
413 ImageStreamIO_createIm_gpu(
m_freqStream, (
m_configName +
"_freq").c_str(), 3, imsize,
IMAGESTRUCT_FLOAT, -1, 1, IMAGE_NB_SEMAPHORE, 0, CIRCULAR_BUFFER | ZAXIS_TEMPORAL, 0);
415 for(
size_t n = 0; n <
m_psd.size(); ++n)
421 clock_gettime(CLOCK_REALTIME, &
m_freqStream->md->writetime);
452 imsize[0] =
m_psd.size();
457 ImageStreamIO_createIm_gpu(
m_rawpsdStream, (
m_configName +
"_rawpsds").c_str(), 3, imsize,
IMAGESTRUCT_FLOAT, -1, 1, IMAGE_NB_SEMAPHORE, 0, CIRCULAR_BUFFER | ZAXIS_TEMPORAL, 0);
465 imsize[0] =
m_psd.size();
470 ImageStreamIO_createIm_gpu(
m_avgpsdStream, (
m_configName +
"_psds").c_str(), 3, imsize,
IMAGESTRUCT_FLOAT, -1, 1, IMAGE_NB_SEMAPHORE, 0, CIRCULAR_BUFFER | ZAXIS_TEMPORAL, 0);
481 static_cast<void>(dummy);
483 float * f_src =
static_cast<float *
>(curr_src);
517 log<software_error>({__FILE__, __LINE__,
"amp circ buff has zero size"});
529 std::cerr <<
"all grown. starting to calculate\n";
531 ampCircBuffT::indexT ne0;
545 double t0 = mx::sys::get_curr_time();
559 for(
size_t n = 0; n <
m_tsSize; ++n)
571 for(
size_t n=0; n <
m_psd.size(); ++n)
577 for(
size_t n=0; n <
m_psd.size(); ++n)
579 m_psd[n] *= (var/nm);
615 if(nPSDAverage <= 0) nPSDAverage = 1;
623 for(
int n =1; n < nPSDAverage; ++n)
655 double t1 = mx::sys::get_curr_time();
677 if( ce >= ne1 ) dn = ce - ne1;
682 double stime = (1.0*dn)/
m_fps * 0.5 * 1e9;
687 if( ce >= ne1 ) dn = ce - ne1;
696 if(
ipRecv.getName() != m_indiP_psdTime.getName())
698 log<software_error>({__FILE__, __LINE__,
"invalid indi property received"});
704 if( indiTargetUpdate( m_indiP_psdTime, target,
ipRecv,
true) < 0)
706 log<software_error>({__FILE__,__LINE__});
710 if(m_psdTime != target)
712 std::lock_guard<std::mutex> guard(m_indiMutex);
719 shmimMonitorT::m_restart =
true;
730 if(
ipRecv.getName() != m_indiP_psdAvgTime.getName())
732 log<software_error>({__FILE__, __LINE__,
"invalid indi property received"});
738 if( indiTargetUpdate( m_indiP_psdAvgTime, target,
ipRecv,
true) < 0)
740 log<software_error>({__FILE__,__LINE__});
744 if(m_psdAvgTime != target)
746 std::lock_guard<std::mutex> guard(m_indiMutex);
748 m_psdAvgTime = target;
761 if(
ipRecv.getName() != m_indiP_fpsSource.getName())
763 log<software_error>({__FILE__, __LINE__,
"Invalid INDI property."});
767 if(
ipRecv.find(
"current") !=
true )
769 log<software_error>({__FILE__, __LINE__,
"No current property in fps source."});
773 std::lock_guard<std::mutex> guard(m_indiMutex);
782 shmimMonitorT::m_restart =
true;
#define IMAGESTRUCT_FLOAT
The base-class for MagAO-X applications.
std::string m_configName
The name of the configuration file (minus .conf).
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 shutdown()
Get the value of the shutdown flag.
static int log(const typename logT::messageT &msg, logPrioT level=logPrio::LOG_DEFAULT)
Make a log entry.
int createROIndiNumber(pcf::IndiProperty &prop, const std::string &propName, const std::string &propLabel="", const std::string &propGroup="")
Create a ReadOnly INDI Number property.
int registerIndiPropertyReadOnly(pcf::IndiProperty &prop)
Register an INDI property which is read only.
std::mutex m_indiMutex
Mutex for locking INDI communications.
int threadStart(std::thread &thrd, bool &thrdInit, pid_t &tpid, pcf::IndiProperty &thProp, int thrdPrio, const std::string &cpuset, const std::string &thrdName, thisPtr *thrdThis, Function &&thrdStart)
Start a thread, using this class's privileges to set priority, etc.
uint32_t m_depth
The depth of the circular buffer in the stream.
int appStartup()
Startup function.
uint32_t m_width
The width of the images in the stream.
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.
std::string m_shmimName
The name of the shared memory image, is used in /tmp/<shmimName>.im.shm. Derived classes should set a...
int appShutdown()
Shuts down the shmimMonitor thread.
uint8_t m_dataType
The ImageStreamIO type code.
void setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
void loadConfig(mx::app::appConfigurator &config)
load the configuration system results
Class for application to calculate rolling PSDs of modal amplitudes.
realT m_psdOverlapFraction
The fraction of the sample time to overlap by.
pcf::IndiProperty m_psdThreadProp
The property to hold the PSD Calculation thread details.
pcf::IndiProperty m_indiP_psdAvgTime
INDI_NEWCALLBACK_DECL(modalPSDs, m_indiP_overSize)
int loadConfigImpl(mx::app::appConfigurator &_config)
Implementation of loadConfig logic, separated for testing.
pid_t m_psdThreadID
PSD Calculation thread PID.
mx::improc::eigenImage< realT > m_psdBuffer
std::thread m_psdThread
The PSD Calculation thread.
pcf::IndiProperty m_indiP_overSize
unsigned m_tsOverlapSize
The number of samples in the overlap.
std::complex< realT > * m_fftWork
mx::sigproc::circularBufferIndex< float *, unsigned > ampCircBuffT
The amplitude circular buffer type.
mx::math::fft::fftwEnvironment< realT > m_fftEnv
INDI_NEWCALLBACK_DECL(modalPSDs, m_indiP_psdTime)
static void psdThreadStart(modalPSDs *p)
PS Calculation thread starter function.
std::vector< realT > m_win
The window function. By default this is Hann.
virtual int appStartup()
Startup function.
INDI_SETCALLBACK_DECL(modalPSDs, m_indiP_fpsSource)
INDI_NEWCALLBACK_DECL(modalPSDs, m_indiP_psdAvgTime)
IMAGE * m_avgpsdStream
The ImageStreamIO shared memory buffer to hold the average psds.
modalPSDs()
Default c'tor.
int m_nModes
the number of modes to calculate PSDs for.
mx::math::fft::fftT< realT, std::complex< realT >, 1, 0 > m_fft
bool m_psdRestarting
Synchronization flag. This will only become false after a successful call to allocate.
virtual void loadConfig()
pcf::IndiProperty m_indiP_fps
virtual int appLogic()
Implementation of the FSM for modalPSDs.
int processImage(void *curr_src, const dev::shmimT &dummy)
IMAGE * m_freqStream
The ImageStreamIO shared memory buffer to hold the frequency scale.
realT m_psdAvgTime
The time over which to average PSDs. The default is 10 sec.
unsigned m_tsSize
The length of the time series sample over which the PSD is calculated.
virtual void setupConfig()
ampCircBuffT m_ampCircBuff
int m_psdThreadPrio
Priority of the PSD Calculation thread.
std::string m_psdThreadCpuset
The cpuset to use for the PSD Calculation thread.
std::complex< realT > complexT
int allocate(const dev::shmimT &dummy)
bool m_psdWaiting
Synchronization flag. This is set to true when the PSD thread is safely waiting for allocation to com...
pcf::IndiProperty m_indiP_psdTime
pcf::IndiProperty m_indiP_fpsSource
realT m_psdTime
The length of time over which to calculate PSDs. The default is 1 sec.
void psdThreadExec()
PSD Calculation thread function.
bool m_psdThreadInit
Initialization flag for the PSD Calculation thread.
virtual int appShutdown()
Shutdown the app.
~modalPSDs() noexcept
D'tor, declared and defined for noexcept.
std::vector< realT > m_psd
dev::shmimMonitor< modalPSDs > shmimMonitorT
The base shmimMonitor type.
std::string m_fpsSource
Device name for getting fps to set circular buffer length. This device should have *....
#define INDI_NEWCALLBACK(prop)
Get the name of the static callback wrapper for a new property.
#define REG_INDI_SETPROP(prop, devName, propName)
Register a SET INDI property with the class, using the standard callback name.
@ OPERATING
The device is operating, other than homing.
void updateIfChanged(pcf::IndiProperty &p, const std::string &el, const T &newVal, indiDriverT *indiDriver, pcf::IndiProperty::PropertyStateType newState=pcf::IndiProperty::Ok)
Update the value of the INDI element, but only if it has changed.
const pcf::IndiProperty & ipRecv
void nanoSleep(unsigned long nsec)
INDI_NEWCALLBACK_DEFN(acesxeCtrl, m_indiP_windspeed)(const pcf
INDI_SETCALLBACK_DEFN(MagAOXApp< _useINDI >, m_indiP_powerChannel)(const pcf
constexpr static logPrioT LOG_WARNING
A condition has occurred which may become an error, but the process continues.
constexpr static logPrioT LOG_NOTICE
A normal but significant condition.