API
 
Loading...
Searching...
No Matches
modalPSDs.hpp
Go to the documentation of this file.
1/** \file modalPSDs.hpp
2 * \brief The MagAO-X modalPSDs app header file
3 *
4 * \ingroup modalPSDs_files
5 */
6
7#ifndef modalPSDs_hpp
8#define modalPSDs_hpp
9
10
11#include "../../libMagAOX/libMagAOX.hpp" //Note this is included on command line to trigger pch
12#include "../../magaox_git_version.h"
13
14#include <mx/sigproc/circularBuffer.hpp>
15#include <mx/sigproc/signalWindows.hpp>
16
17#include <mx/math/fft/fftwEnvironment.hpp>
18#include <mx/math/fft/fft.hpp>
19
20/** \defgroup modalPSDs
21 * \brief An application to calculate rolling PSDs of modal amplitudes
22 *
23 * <a href="../handbook/operating/software/apps/modalPSDs.html">Application Documentation</a>
24 *
25 * \ingroup apps
26 *
27 */
28
29/** \defgroup modalPSDs_files
30 * \ingroup modalPSDs
31 */
32
33namespace MagAOX
34{
35namespace app
36{
37
38/// Class for application to calculate rolling PSDs of modal amplitudes.
39/**
40 * \ingroup modalPSDs
41 */
42class modalPSDs : public MagAOXApp<true>, public dev::shmimMonitor<modalPSDs>
43{
44 //Give the test harness access.
45 friend class modalPSDs_test;
46
47 friend class dev::shmimMonitor<modalPSDs>;
48
49public:
50
51 typedef float realT;
52 typedef std::complex<realT> complexT;
53
54 /// The base shmimMonitor type
56
57 /// The amplitude circular buffer type
58 typedef mx::sigproc::circularBufferIndex<float*, unsigned> ampCircBuffT;
59
60protected:
61
62 /** \name Configurable Parameters
63 *@{
64 */
65
66 std::string m_fpsSource; ///< Device name for getting fps to set circular buffer length. This device should have *.fps.current.
67
68 realT m_psdTime{ 1 }; ///< The length of time over which to calculate PSDs. The default is 1 sec.
69 realT m_psdAvgTime{ 10 }; ///< The time over which to average PSDs. The default is 10 sec.
70
71 //realT m_overSize {10}; ///< Multiplicative factor by which to oversize the circular buffer, to give good mean estimates and account for time-to-calculate.
72
73 realT m_psdOverlapFraction{ 0.5 }; ///< The fraction of the sample time to overlap by.
74
75 int m_nPSDHistory{ 100 }; //
76
77
78 ///@}
79
80 int m_nModes{ 0 }; ///< the number of modes to calculate PSDs for.
81
83
84 //std::vector<ampCircBuffT> m_ampCircBuffs;
85
87 realT m_df{ 1 };
88
89 //unsigned m_tsCircBuffLength {4000}; ///< Length of the time-series circular buffers. This is updated by m_fpsSource and m_psdTime.
90
91 unsigned m_tsSize{ 2000 }; ///< The length of the time series sample over which the PSD is calculated
92 unsigned m_tsOverlapSize{ 1000 }; ///< The number of samples in the overlap
93
94 std::vector<realT> m_win; ///< The window function. By default this is Hann.
95
96 realT* m_tsWork{ nullptr };
97 size_t m_tsWorkSize{ 0 };
98
99 std::complex<realT>* m_fftWork{ nullptr };
100 size_t m_fftWorkSize{ 0 };
101
102 std::vector<realT> m_psd;
103
104 mx::math::fft::fftT< realT, std::complex<realT>, 1, 0> m_fft;
105 mx::math::fft::fftwEnvironment<realT> m_fftEnv;
106
107 /** \name PSD Calculation Thread
108 * Handling of offloads from the average woofer shape
109 * @{
110 */
111 int m_psdThreadPrio{ 0 }; ///< Priority of the PSD Calculation thread.
112 std::string m_psdThreadCpuset; ///< The cpuset to use for the PSD Calculation thread.
113
114 std::thread m_psdThread; ///< The PSD Calculation thread.
115
116 bool m_psdThreadInit{ true }; ///< Initialization flag for the PSD Calculation thread.
117
118 bool m_psdRestarting{ true }; ///< Synchronization flag. This will only become false after a successful call to allocate.
119 bool m_psdWaiting{ false }; ///< Synchronization flag. This is set to true when the PSD thread is safely waiting for allocation to complete.
120
121 pid_t m_psdThreadID{ 0 }; ///< PSD Calculation thread PID.
122
123 pcf::IndiProperty m_psdThreadProp; ///< The property to hold the PSD Calculation thread details.
124
125 /// PS Calculation thread starter function
126 static void psdThreadStart(modalPSDs* p /**< [in] pointer to this */);
127
128 /// PSD Calculation thread function
129 /** Runs until m_shutdown is true.
130 */
131 void psdThreadExec();
132
133 IMAGE* m_freqStream{ nullptr }; ///< The ImageStreamIO shared memory buffer to hold the frequency scale
134
135 mx::improc::eigenImage<realT> m_psdBuffer;
136
137 IMAGE* m_rawpsdStream{ nullptr }; ///< The ImageStreamIO shared memory buffer to hold the raw psds
138
139 IMAGE* m_avgpsdStream{ nullptr }; ///< The ImageStreamIO shared memory buffer to hold the average psds
140
141public:
142 /// Default c'tor.
143 modalPSDs();
144
145 /// D'tor, declared and defined for noexcept.
148
149 virtual void setupConfig();
150
151 /// Implementation of loadConfig logic, separated for testing.
152 /** This is called by loadConfig().
153 */
154 int loadConfigImpl(mx::app::appConfigurator& _config /**< [in] an application configuration from which to load values*/);
155
156 virtual void loadConfig();
157
158 /// Startup function
159 /**
160 *
161 */
162 virtual int appStartup();
163
164 /// Implementation of the FSM for modalPSDs.
165 /**
166 * \returns 0 on no critical error
167 * \returns -1 on an error requiring shutdown
168 */
169 virtual int appLogic();
170
171 /// Shutdown the app.
172 /**
173 *
174 */
175 virtual int appShutdown();
176
177 //shmimMonitor Interface
178protected:
179
180 int allocate(const dev::shmimT& dummy /**< [in] tag to differentiate shmimMonitor parents.*/);
181
182 int allocatePSDStreams();
183
184 int processImage( void* curr_src, ///< [in] pointer to start of current frame.
185 const dev::shmimT& dummy ///< [in] tag to differentiate shmimMonitor parents.
186 );
187
188
189 //INDI Interface
190protected:
191
192 pcf::IndiProperty m_indiP_psdTime;
193 pcf::IndiProperty m_indiP_psdAvgTime;
194 pcf::IndiProperty m_indiP_overSize;
195 pcf::IndiProperty m_indiP_fpsSource;
196 pcf::IndiProperty m_indiP_fps;
197
198public:
199
204
205};
206
207modalPSDs::modalPSDs() : MagAOXApp(MAGAOX_CURRENT_SHA1, MAGAOX_REPO_MODIFIED)
208{
209 return;
210}
211
213{
215
216 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.");
217 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.");
218 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.");
219}
220
221int modalPSDs::loadConfigImpl(mx::app::appConfigurator& _config)
222{
224
225 _config(m_fpsSource, "circBuff.fpsSource");
226 _config(m_fps, "circBuff.defaultFPS");
227 _config(m_psdTime, "circBuff.psdTime");
228
229 return 0;
230}
231
233{
234 loadConfigImpl(config);
235}
236
238{
239 CREATE_REG_INDI_NEW_NUMBERF(m_indiP_psdTime, "psdTime", 0, 60, 0.1, "%0.1f", "PSD time", "PSD Setup");
240 m_indiP_psdTime["current"].set(m_psdTime);
241 m_indiP_psdTime["target"].set(m_psdTime);
242
243 CREATE_REG_INDI_NEW_NUMBERU(m_indiP_psdAvgTime, "psdAvgTime", 0, 60, 0.1, "%0.1f", "PSD Avg. Time", "PSD Setup");
244 m_indiP_psdAvgTime["current"].set(m_psdAvgTime);
245 m_indiP_psdAvgTime["target"].set(m_psdAvgTime);
246
247 if (m_fpsSource != "")
248 {
249 REG_INDI_SETPROP(m_indiP_fpsSource, m_fpsSource, std::string("fps"));
250 }
251
252 CREATE_REG_INDI_RO_NUMBER(m_indiP_fps, "fps", "current", "Circular Buffer");
253 m_indiP_fps.add(pcf::IndiElement("current"));
254 m_indiP_fps["current"] = m_fps;
255
256
258
260
262
263 return 0;
264}
265
267{
269
271
272 std::unique_lock<std::mutex> lock(m_indiMutex);
273
275
276 return 0;
277}
278
308
310{
311 static_cast<void>(dummy);
312
313 m_psdRestarting = true;
314
315 //Prevent reallocation while the psd thread might be calculating
316 while (m_psdWaiting == false && !shutdown()) mx::sys::microSleep(100);
317
318 if (shutdown()) return 0; //If shutdown() is true then shmimMonitor will cleanup
319
320 if (m_fps > 0)
321 {
322 //m_tsCircBuffLength = m_fps * m_psdTime * m_overSize;
325 }
326
327 if (m_tsOverlapSize == 0 || !std::isnormal(m_tsOverlapSize))
328 {
329 log<software_error>({ __FILE__,__LINE__, "bad m_tsOverlapSize value: " + std::to_string(m_tsOverlapSize) });
330 return -1;
331 }
332
333 //Check for unsupported type (must be realT)
335 {
336 //must be a vector of size 1 on one axis
337 log<software_error>({ __FILE__,__LINE__, "unsupported data type: must be realT" });
338 return -1;
339 }
340
341 //Check for unexpected format
343 {
344 //must be a vector of size 1 on one axis
345 log<software_error>({ __FILE__,__LINE__, "unexpected shmim format" });
346 return -1;
347 }
348
349 std::cerr << "connected to " << shmimMonitorT::m_shmimName << " " << shmimMonitorT::m_width << " " << shmimMonitorT::m_height << " " << shmimMonitorT::m_depth << "\n";
350
351
353
354 //Size the circ buff
356
357 //Create the window
358 m_win.resize(m_tsSize);
359 mx::sigproc::window::hann(m_win);
360
361 //Set up the FFT and working memory
362 m_fft.plan(m_tsSize, MXFFT_FORWARD, false);
363
365 m_tsWork = mx::math::fft::fftw_malloc<realT>(m_tsSize);
366
368 m_fftWork = mx::math::fft::fftw_malloc<std::complex<realT>>((m_tsSize / 2 + 1));
369
370 m_psd.resize(m_tsSize / 2 + 1);
371
372 if (m_fps > 0)
373 {
374 m_df = 1.0 / (m_tsSize / m_fps);
375 }
376 else
377 {
378 m_df = 1.0 / (m_tsSize);
379 }
380
381 //Create the shared memory images
382 uint32_t imsize[3];
383
384 //First the frequency
385 imsize[0] = 1;
386 imsize[1] = m_psd.size();
387 imsize[2] = 1;
388
389 if (m_freqStream)
390 {
393 }
394 m_freqStream = static_cast<IMAGE*>(malloc(sizeof(IMAGE)));
395
397 m_freqStream->md->write = 1;
398 for (size_t n = 0; n < m_psd.size(); ++n)
399 {
400 m_freqStream->array.F[n] = n * m_df;
401 }
402
403 //Set the time of last write
404 clock_gettime(CLOCK_REALTIME, &m_freqStream->md->writetime);
405 m_freqStream->md->atime = m_freqStream->md->writetime;
406
407 //Update cnt1
408 m_freqStream->md->cnt1 = 0;
409
410 //Update cnt0
411 m_freqStream->md->cnt0 = 0;
412
413 m_freqStream->md->write = 0;
415
417
418 m_psdRestarting = false;
419
420 return 0;
421}
422
424{
425 if (m_rawpsdStream)
426 {
429 }
430
431 uint32_t imsize[3];
432 imsize[0] = m_psd.size();
433 imsize[1] = m_nModes;
435
436 m_rawpsdStream = static_cast<IMAGE*>(malloc(sizeof(IMAGE)));
437
439
440 if (m_avgpsdStream)
441 {
444 }
445
446 imsize[0] = m_psd.size();
447 imsize[1] = m_nModes;
448 imsize[2] = 1;
449
450 m_avgpsdStream = static_cast<IMAGE*>(malloc(sizeof(IMAGE)));
452
453 m_psdBuffer.resize(m_psd.size(), m_nModes);
454
455 return 0;
456}
457
458int modalPSDs::processImage( void* curr_src,
459 const dev::shmimT& dummy
460 )
461{
462 static_cast<void>(dummy);
463
464 float* f_src = static_cast<float*>(curr_src);
465
466 m_ampCircBuff.nextEntry(f_src);
467
468 return 0;
469}
470
475
476
478{
480
481 while (m_psdThreadInit == true && shutdown() == 0)
482 {
483 sleep(1);
484 }
485
486 while (shutdown() == 0)
487 {
488 if (m_psdRestarting == true || m_ampCircBuff.maxEntries() == 0) m_psdWaiting = true;
489
490 while ((m_psdRestarting == true || m_ampCircBuff.maxEntries() == 0) && !shutdown()) mx::sys::microSleep(100);
491
492 if (shutdown()) break;
493
494 m_psdWaiting = false;
495
496 if (m_ampCircBuff.maxEntries() == 0)
497 {
498 log<software_error>({ __FILE__, __LINE__, "amp circ buff has zero size" });
499 return;
500 }
501
502 std::cerr << "waiting to grow\n";
503 while (m_ampCircBuff.size() < m_ampCircBuff.maxEntries() && m_psdRestarting == false && !shutdown())
504 {
505 //shrinking sleep
506 double stime = (1.0 * m_ampCircBuff.maxEntries() - 1.0 * m_ampCircBuff.size()) / m_fps * 0.5 * 1e9;
507 mx::sys::nanoSleep(stime);
508 }
509
510 std::cerr << "all grown. starting to calculate\n";
511
512 ampCircBuffT::indexT ne0;
513 ampCircBuffT::indexT ne1 = m_ampCircBuff.latest();
515 else ne1 = m_ampCircBuff.size() + ne1 - m_tsSize;
516
517 while (m_psdRestarting == false && !shutdown())
518 {
519 //Used to check if we are getting too behind
521
522 //Calc PSDs here
523 ne0 = ne1;
524
525 std::cerr << "calculating: " << ne0 << " " << m_ampCircBuff.size() << " " << m_tsSize << "\n";
526 double t0 = mx::sys::get_curr_time();
527
528 for (size_t m = 0; m < shmimMonitorT::m_width * shmimMonitorT::m_height; ++m) //Loop over each mode
529 {
530 //get mean going over entire TS
531 realT mn = 0;
532 for (size_t n = 0; n < m_ampCircBuff.size(); ++n)
533 {
534 mn += m_ampCircBuff[n][m];
535 }
536 mn /= m_ampCircBuff.size();
537
538 double var = 0;
539 for (size_t n = 0; n < m_tsSize; ++n)
540 {
541 m_tsWork[n] = (m_ampCircBuff.at(ne0, n)[m] - mn); //load mean subtracted chunk
542 var += pow(m_tsWork[n], 2);
543
544 m_tsWork[n] *= m_win[n];
545 }
546 var /= m_tsSize;
547
549
550 double nm = 0;
551 for (size_t n = 0; n < m_psd.size(); ++n)
552 {
553 m_psd[n] = norm(m_fftWork[n]);
554 nm += m_psd[n] * m_df;
555 }
556
557 for (size_t n = 0; n < m_psd.size(); ++n)
558 {
559 m_psd[n] *= (var / nm);
560 }
561
562 //Put it in the buffer for uploading to shmim
563 for (size_t n = 0; n < m_psd.size(); ++n) m_psdBuffer(n, m) = m_psd[n];
564
565 }
566
567 //------------------------- the raw psds ---------------------------
568 m_rawpsdStream->md->write = 1;
569
570 //Set the time of last write
572 m_rawpsdStream->md->atime = m_rawpsdStream->md->writetime;
573
574 uint64_t cnt1 = m_rawpsdStream->md->cnt1 + 1;
575 if (cnt1 >= m_rawpsdStream->md->size[2]) cnt1 = 0;
576
577 //Move to next pointer
578 float* F = m_rawpsdStream->array.F + m_psdBuffer.rows() * m_psdBuffer.cols() * cnt1;
579
580 memcpy(F, m_psdBuffer.data(), m_psdBuffer.rows() * m_psdBuffer.cols() * sizeof(float));
581
582 //Update cnt1
583 m_rawpsdStream->md->cnt1 = cnt1;
584
585 //Update cnt0
586 ++m_rawpsdStream->md->cnt0;
587
588 m_rawpsdStream->md->write = 0;
590
591 //-------------------------- now average the psds ----------------------------
592
594
595 if (nPSDAverage <= 0) nPSDAverage = 1;
596 else if ((uint64_t)nPSDAverage > m_rawpsdStream->md->size[2]) nPSDAverage = m_rawpsdStream->md->size[2];
597
598 //Move to next pointer
599 F = m_rawpsdStream->array.F + m_psdBuffer.rows() * m_psdBuffer.cols() * cnt1;
600
601 memcpy(m_psdBuffer.data(), F, m_psdBuffer.rows() * m_psdBuffer.cols() * sizeof(float));
602
603 for (int n = 1; n < nPSDAverage; ++n)
604 {
605 if (cnt1 == 0) cnt1 = m_rawpsdStream->md->size[2] - 1;
606 else --cnt1;
607
608 F = m_rawpsdStream->array.F + m_psdBuffer.rows() * m_psdBuffer.cols() * cnt1;
609
610 m_psdBuffer += Eigen::Map<Eigen::Array<float, -1, -1>>(F, m_psdBuffer.rows(), m_psdBuffer.cols());
611 }
612
614
615 m_avgpsdStream->md->write = 1;
616
617 //Set the time of last write
619 m_avgpsdStream->md->atime = m_avgpsdStream->md->writetime;
620
621 //Move to next pointer
622 F = m_avgpsdStream->array.F;
623
624 memcpy(F, m_psdBuffer.data(), m_psdBuffer.rows() * m_psdBuffer.cols() * sizeof(float));
625
626 //Update cnt1
627 m_avgpsdStream->md->cnt1 = 0;
628
629 //Update cnt0
630 ++m_avgpsdStream->md->cnt0;
631
632 m_avgpsdStream->md->write = 0;
634
635 double t1 = mx::sys::get_curr_time();
636 std::cerr << "done " << t1 - t0 << "\n";
637
638 //Have to be cycling within the overlap
639 if (m_ampCircBuff.mono() - mono0 >= m_tsOverlapSize)
640 {
641 log<text_log>("PSD calculations getting behind, skipping ahead.", logPrio::LOG_WARNING);
642 ne0 = m_ampCircBuff.latest();
644 else ne0 = m_ampCircBuff.size() + ne0 - m_tsOverlapSize;
645 }
646
647 //Now wait until we get to next one
649 if (ne1 >= m_ampCircBuff.size())
650 {
651 ne1 -= m_ampCircBuff.size();
652 }
653
654 ampCircBuffT::indexT ce = m_ampCircBuff.latest();
655 //wrapped difference
656 long dn;
657 if (ce >= ne1) dn = ce - ne1;
658 else dn = ce + (m_ampCircBuff.size() - ne1);
659
660 while (dn < m_tsOverlapSize && !shutdown() && m_psdRestarting == false)
661 {
662 double stime = (1.0 * dn) / m_fps * 0.5 * 1e9;
663 mx::sys::nanoSleep(stime);
664
665 ce = m_ampCircBuff.latest();
666
667 if (ce >= ne1) dn = ce - ne1;
668 else dn = ce + (m_ampCircBuff.size() - ne1);
669 }
670 }
671 }
672}
673
674INDI_NEWCALLBACK_DEFN(modalPSDs, m_indiP_psdTime)(const pcf::IndiProperty& ipRecv)
675{
676 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_psdTime, ipRecv);
677
678 realT target;
679
680 if (indiTargetUpdate(m_indiP_psdTime, target, ipRecv, true) < 0)
681 {
682 log<software_error>({ __FILE__,__LINE__ });
683 return -1;
684 }
685
686 if (m_psdTime != target)
687 {
688 std::lock_guard<std::mutex> guard(m_indiMutex);
689
690 m_psdTime = target;
691
692 updateIfChanged(m_indiP_psdTime, "current", m_psdTime, INDI_IDLE);
693 updateIfChanged(m_indiP_psdTime, "target", m_psdTime, INDI_IDLE);
694
695 shmimMonitorT::m_restart = true;
696
697 log<text_log>("set psdTime to " + std::to_string(m_psdTime), logPrio::LOG_NOTICE);
698 }
699
700 return 0;
701} //INDI_NEWCALLBACK_DEFN(modalPSDs, m_indiP_psdTime)
702
703INDI_NEWCALLBACK_DEFN(modalPSDs, m_indiP_psdAvgTime)(const pcf::IndiProperty& ipRecv)
704{
705 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_psdAvgTime, ipRecv);
706
707 realT target;
708
709 if (indiTargetUpdate(m_indiP_psdAvgTime, target, ipRecv, true) < 0)
710 {
711 log<software_error>({ __FILE__,__LINE__ });
712 return -1;
713 }
714
715 if (m_psdAvgTime != target)
716 {
717 std::lock_guard<std::mutex> guard(m_indiMutex);
718
719 m_psdAvgTime = target;
720
721 updateIfChanged(m_indiP_psdTime, "current", m_psdAvgTime, INDI_IDLE);
722 updateIfChanged(m_indiP_psdTime, "target", m_psdAvgTime, INDI_IDLE);
723
724 log<text_log>("set psdAvgTime to " + std::to_string(m_psdAvgTime), logPrio::LOG_NOTICE);
725 }
726
727 return 0;
728} //INDI_NEWCALLBACK_DEFN(modalPSDs, m_indiP_psdAvgTime)
729
730INDI_SETCALLBACK_DEFN(modalPSDs, m_indiP_fpsSource)(const pcf::IndiProperty& ipRecv)
731{
732 INDI_VALIDATE_CALLBACK_PROPS(m_indiP_fpsSource, ipRecv);
733
734 if (ipRecv.find("current") != true) //this isn't valid
735 {
736 log<software_error>({ __FILE__, __LINE__, "No current property in fps source." });
737 return 0;
738 }
739
740 std::lock_guard<std::mutex> guard(m_indiMutex);
741
742 realT fps = ipRecv["current"].get<realT>();
743
744 if (fps != m_fps)
745 {
746 m_fps = fps;
747 log<text_log>("set fps to " + std::to_string(m_fps), logPrio::LOG_NOTICE);
748 updateIfChanged(m_indiP_fps, "current", m_fps, INDI_IDLE);
749 shmimMonitorT::m_restart = true;
750 }
751
752 return 0;
753
754} //INDI_SETCALLBACK_DEFN(modalPSDs, m_indiP_fpsSource)
755
756} //namespace app
757} //namespace MagAOX
758
759#endif //modalPSDs_hpp
#define IMAGESTRUCT_FLOAT
#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 MagAO-X applications.
Definition MagAOXApp.hpp:73
std::string m_configName
The name of the configuration file (minus .conf).
Definition MagAOXApp.hpp:83
stateCodes::stateCodeT state()
Get the current state code.
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.
std::mutex m_indiMutex
Mutex for locking INDI communications.
uint32_t m_depth
The depth of the circular buffer in the stream.
uint32_t m_width
The width of the images in the stream.
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...
uint8_t m_dataType
The ImageStreamIO type code.
Class for application to calculate rolling PSDs of modal amplitudes.
Definition modalPSDs.hpp:43
realT m_psdOverlapFraction
The fraction of the sample time to overlap by.
Definition modalPSDs.hpp:73
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.
Definition modalPSDs.hpp:92
std::complex< realT > * m_fftWork
Definition modalPSDs.hpp:99
mx::math::fft::fftwEnvironment< realT > m_fftEnv
mx::sigproc::circularBufferIndex< float *, unsigned > ampCircBuffT
The amplitude circular buffer type.
Definition modalPSDs.hpp:58
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.
Definition modalPSDs.hpp:94
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.
IMAGE * m_rawpsdStream
The ImageStreamIO shared memory buffer to hold the raw psds.
modalPSDs()
Default c'tor.
int m_nModes
the number of modes to calculate PSDs for.
Definition modalPSDs.hpp:80
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.
Definition modalPSDs.hpp:69
unsigned m_tsSize
The length of the time series sample over which the PSD is calculated.
Definition modalPSDs.hpp:91
virtual void setupConfig()
ampCircBuffT m_ampCircBuff
Definition modalPSDs.hpp:82
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
Definition modalPSDs.hpp:52
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.
Definition modalPSDs.hpp:68
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.
Definition modalPSDs.hpp:55
std::string m_fpsSource
Device name for getting fps to set circular buffer length. This device should have *....
Definition modalPSDs.hpp:66
#define INDI_NEWCALLBACK_DEFN(class, prop)
Define the callback for a new property request.
#define CREATE_REG_INDI_NEW_NUMBERU(prop, name, min, max, step, format, label, group)
Create and register a NEW INDI property as a standard number as unsigned int, using the standard call...
#define CREATE_REG_INDI_NEW_NUMBERF(prop, name, min, max, step, format, label, group)
Create and register a NEW INDI property as a standard number as float, using the standard callback na...
#define INDI_SETCALLBACK_DEFN(class, prop)
Define the callback for a set property request.
#define REG_INDI_SETPROP(prop, devName, propName)
Register a SET INDI property with the class, using the standard callback name.
#define CREATE_REG_INDI_RO_NUMBER(prop, name, label, group)
Create and register a RO INDI property as a number, using the standard callback name.
@ OPERATING
The device is operating, other than homing.
#define INDI_VALIDATE_CALLBACK_PROPS(prop1, prop2)
Standard check for matching INDI properties in a callback.
#define INDI_IDLE
Definition indiUtils.hpp:28
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 constexpr logPrioT LOG_WARNING
A condition has occurred which may become an error, but the process continues.
#define SHMIMMONITOR_APP_SHUTDOWN
Call shmimMonitorT::appShutdown with error checking for shmimMonitor.
#define SHMIMMONITOR_APP_LOGIC
Call shmimMonitorT::appLogic with error checking for shmimMonitor.
#define SHMIMMONITOR_APP_STARTUP
Call shmimMonitorT::appStartup with error checking for shmimMonitor.
#define SHMIMMONITOR_LOAD_CONFIG(cfig)
Call shmimMonitorT::loadConfig with error checking for shmimMonitor.
#define SHMIMMONITOR_UPDATE_INDI
Call shmimMonitorT::updateINDI with error checking for shmimMonitor.
#define SHMIMMONITOR_SETUP_CONFIG(cfig)
Call shmimMonitorT::setupConfig with error checking for shmimMonitor.