mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
pyramidSensor.hpp
Go to the documentation of this file.
1 /** \file pyramidSensor.hpp
2  * \author Jared R. Males (jaredmales@gmail.com)
3  * \brief Declaration and definition of a standard 4 quadrant pyramid WFS.
4  * \ingroup mxAO_sim_files
5  *
6  */
7 
8 #ifndef __pyramidSensor_hpp__
9 #define __pyramidSensor_hpp__
10 
11 
12 #include "../../wfp/imagingUtils.hpp"
13 #include "../../wfp/fraunhoferPropagator.hpp"
14 #include "../../sys/timeUtils.hpp"
15 #include "../../ioutils/fits/fitsFile.hpp"
16 #include "../../improc/imageTransforms.hpp"
17 #include "../../math/constants.hpp"
18 
19 #include "wavefront.hpp"
20 
21 
22 #ifdef DEBUG
23 #define BREAD_CRUMB std::cout << "DEBUG: " << __FILE__ << " " << __LINE__ << "\n";
24 #else
25 #define BREAD_CRUMB
26 #endif
27 
28 
29 namespace mx
30 {
31 namespace AO
32 {
33 namespace sim
34 {
35 
36 template<typename _realT>
37 struct wfsImageT
38 {
39  typedef _realT realT;
40 
41  unsigned iterNo;
42 
43  ///The wavefront sensor detector image type
44  typedef Eigen::Array< realT, Eigen::Dynamic, Eigen::Dynamic> imageT;
45 
46  imageT image;
47 
48  imageT tipImage;
49 };
50 
51 template<typename _realT, typename _detectorT>
52 class pyramidSensor
53 {
54 public:
55 
56  typedef _realT realT;
57 
58  typedef std::complex<realT> complexT;
59 
60  ///The wavefront data type
61  typedef wavefront<realT> wavefrontT;
62 
63  ///The wavefront complex field type
64  typedef wfp::imagingArray<std::complex<realT>, wfp::fftwAllocator<std::complex<realT> >, 0> complexFieldT;
65 
66  ///The wavefront sensor detector image type
67  //typedef Eigen::Array< realT, Eigen::Dynamic, Eigen::Dynamic> wfsImageT;
68 
69  typedef _detectorT detectorT;
70 
71 protected:
72 
73  /* Standard WFS Interface: */
74  int m_wfSz; ///< Size of the wavefront in pixels
75 
76  int _detRows; ///<The number of rows of the WFS detector. After forming the image the WFS detector plane is re-binned to this.
77  int _detCols; ///<The number of columns of the WFS detector. After forming the image the WFS detector plane is re-binned to this.
78 
79  realT m_lambda; ///< Central wavelength, in meters
80 
81 public:
82 
83  /** \todo when the filter should be set with astrospectrum, and should re-calculate the central wavelength.
84  * \todo need to verify that the wavefront propagation is appropriately chromatic
85  */
86  std::vector<realT> m_wavelengths; ///< Vector of wavelengths in the WFS bandpass
87  std::vector<realT> _wavelengthWeights; ///< The relative weights of the wavelengths
88 
89 protected:
90 
91  int _iTime; ///<Integration time in loop steps
92 
93  int _roTime; ///<Readout time in loop steps
94 
95  realT _simStep; ///<The simulation stepsize in seconds.
96 
97 
98  /* PyWFS Specific: */
99 
100  realT m_wfPS; ///< Wavefront pixel scale, in meters/pixel
101 
102  realT _D; ///< Telescope diameter, in meters
103 
104  /** \name Modulation
105  * Pyramid sensor modulation setup
106  *
107  * @{
108  */
109 protected:
110 
111  int m_modSteps {20}; ///<Number of steps in the modulation simulation
112 
113  realT m_perStep {1}; ///< The minimum number of lamba/D per step to take.
114 
115  realT m_modRadius {3.0}; ///<Radius of the modulation in pixels
116 
117  realT m_effRad, m_rmsRad, m_bestRad, m_bestAng;
118 
119  std::vector<realT> m_modShift_x; ///< the x-coords of the continuous modulation path
120  std::vector<realT> m_modShift_y; ///< the y-coords of the continuous modulation path
121 
122 public:
123 
124  ///Get the minimum number of modulation steps
125  /**
126  * \returns m_perStep;
127  */
128  realT perStep();
129 
130  ///Set the minimum number of modulation steps
131  /**
132  * \param mSt is the new number of modulation steps
133  */
134  void perStep(realT prStp /**< The minimum number of lamba/D per step to take*/ );
135 
136  ///Get the number of modulation steps
137  /**
138  * \returns m_modSteps, which is defined by perStep.
139  */
140  int modSteps();
141 
142  ///Get the radius of modulation
143  /**
144  * \returns m_modRadius;
145  */
146  realT modRadius();
147 
148  ///Set the modulation radius
149  /**
150  * \param mR is the new modulation radius in lambda/D
151  */
152  void modRadius(realT mR /**< [in] the new value of modulation radius */ );
153 
154  ///@}
155 
156  int m_quadSz; ///<The size of the PyWFS quadrant
157 
158 
159  wfp::fraunhoferPropagator<complexFieldT> m_frProp;
160 
161  bool m_opdMaskMade {false};
162  complexFieldT m_opdMask;
163 
164  bool m_tiltsMade {false};
165  std::vector<complexFieldT> m_tilts;
166 
167  bool m_preAllocated {false};
168  complexFieldT m_pupilPlaneCF;
169 
170  //Pre-allocated working memory:
171 
172  std::vector<complexFieldT> m_th_tiltedPlane; ///< Thread-local modulated wavefront
173 
174  std::vector<complexFieldT> m_th_focalPlane; ///< Thread-local tip wavefront, used for FFT tilting
175 
176  std::vector<typename wfsImageT<realT>::imageT> m_th_focalImage; ///< Thread-local tip image
177 
178  std::vector<complexFieldT> m_th_sensorPlane; ///< Thread-local sensor-pupil-plane wavefront
179 
180  std::vector<typename wfsImageT<realT>::imageT> m_th_sensorImage; ///< Thread-local sensor-pupil-plane intensity image
181 
182 
183  int _iTime_counter;
184 
185  int _reading;
186 
187  int _roTime_counter;
188 
189  std::vector<wavefrontT> _wavefronts;
190 
191  int _lastWavefront;
192 
193 public:
194  ///Default c'tor
195  pyramidSensor();
196 
197  /* The standard WFS interface: */
198 
199  detectorT detector;
200 
201  ///The image on the detector, resized from m_wfsImage
202  wfsImageT<realT> detectorImage;
203 
204  ///Get the wavefront size in pixels
205  /**
206  * \returns the wavefront size in pixels
207  */
208  int wfSz();
209 
210  ///Set the wavefront size in pixels.
211  /**
212  * \param sz is the new size
213  */
214  void wfSz( int sz /**< */ );
215 
216  ///Get the detector rows in pixels
217  /**
218  * \returns _detRows
219  */
220  int detRows();
221 
222  ///Get the detector columns in pixels
223  /**
224  * \returns _detCols
225  */
226  int detCols();
227 
228  ///Set the detector columns in pixels.
229  /**
230  * \param sz is the new size
231  */
232  void detSize( int nrows, ///<
233  int ncols ///<
234  );
235 
236  ///Get the PyWFS central wavelength
237  /**
238  * \returns the central wavelength in meters
239  */
240  realT lambda();
241 
242  ///Set the PyWFS central wavelength
243  /**
244  * \param d is the new central wavelength in meters
245  */
246  void lambda(realT l /**< */ );
247 
248  ///Get the PyWFS integration time, in time steps
249  int iTime();
250 
251  ///Set the PyWFS integration time, in time steps
252  void iTime(int it /**< */ );
253 
254  ///Get the PyWFS detector readout time, in time steps
255  int roTime();
256 
257  ///Set the PyWFS detector readout time, in time steps
258  void roTime(int rt /**< */ );
259 
260  ///Get the simulation step-size, in seconds.
261  realT simStep();
262 
263  ///Set the simulation step-size, in seconds.
264  void simStep(realT st /**< */ );
265 
266  template<typename AOSysT>
267  void linkSystem(AOSysT & AOSys /**< */ );
268 
269 
270  ///Sense the wavefront aberrations
271  /** Returns true if a new wavefront measurement is ready.
272  * Retruns false if still integrating.
273  */
274  bool senseWavefront(wavefrontT & pupilPlane /**< */ );
275 
276  ///Sense the wavefront aberrations in a calibration mode
277  /** Allows for faster calibrations.
278  */
279  bool senseWavefrontCal(wavefrontT & pupilPlane /**< */ );
280 
281 
282  /* The PyWFS Specific Interface */
283 
284  ///Get the wavefront pixel scale in meters per pixel
285  /**
286  * \returns the wavefront pixel scale in meters/pixel
287  */
288  int wfPS();
289 
290  ///Set the wavefront pixel scale in meters per pixel
291  /**
292  * \param ps is the pixel scale
293  */
294  void wfPS(realT ps /**< */ );
295 
296  ///Get the telescope diameter
297  /**
298  * \returns the telescope diameter in meters
299  */
300  realT D();
301 
302  ///Set the telescope diameter
303  /**
304  * \param d is the new size in meters
305  */
306  void D(realT d /**< */ );
307 
308 
309 
310  ///Get the quadrant size in pixels
311  /** This is the size of the quadrant in un-binned wavefront space
312  *
313  *
314  * \returns m_quadSz
315  */
316  int quadSz();
317 
318  ///Set the quadrant size in pixels.
319  /** This is the size of the quadrant in un-binned wavefront space
320  * It should be at least the size of the Pupil. Make larger than the pupil
321  * to have smaller pupil images on the PyWFS detector.
322  *
323  * \param sz is the new size
324  */
325  void quadSz(int sz /**< */ );
326 
327 
328  template<typename pupilT>
329  void makeRefTipImage( pupilT & pupil);
330 
331  int ref;
332 
333 //protected:
334 
335  ///The image formed by the WFS
336  wfsImageT<realT> m_wfsImage;
337 
338  wfsImageT<realT> wfsTipImage;
339 
340  wfsImageT<realT> refTipImage;
341 
342  void makeOpdMask();
343 
344  void makeTilts();
345 
346  void allocThreadMem();
347 
348  void preAllocate();
349 
350 public:
351  void doSenseWavefront();
352  void doSenseWavefront(wavefrontT & /**< */);
353  void doSenseWavefrontNoMod(wavefrontT & /**< */ );
354 
355  bool firstRun;
356 
357 };
358 
359 template<typename realT, typename detectorT>
360 pyramidSensor<realT, detectorT>::pyramidSensor()
361 {
362  m_wfSz = 0;
363  _detRows = 0;
364  _detCols = 0;
365  m_lambda = 0;
366 
367 
368  m_modSteps = 16;
369  m_modRadius = 16;
370 
371 
372  iTime(1);
373  _iTime_counter = 0;
374 
375  _reading =0;
376  _roTime = 1;
377  _roTime_counter = 0;
378 
379  _simStep = 0.001;
380 
381  m_opdMaskMade = false;
382 
383  firstRun = true;
384 
385  ref = 1;
386 
387  m_frProp.wholePixel(0);
388 
389 }
390 
391 template<typename realT, typename detectorT>
392 int pyramidSensor<realT, detectorT>::wfSz()
393 {
394  return m_wfSz;
395 }
396 
397 template<typename realT, typename detectorT>
398 void pyramidSensor<realT, detectorT>::wfSz(int sz)
399 {
400  if( m_wfSz == sz) return;
401 
402  m_wfSz = sz;
403 
404  m_frProp.setWavefrontSizePixels(m_wfSz);
405 
406  m_tiltsMade = false;
407  m_opdMaskMade = false;
408  m_preAllocated = false;
409 }
410 
411 template<typename realT, typename detectorT>
412 int pyramidSensor<realT, detectorT>::detRows()
413 {
414  return _detRows;
415 }
416 
417 
418 template<typename realT, typename detectorT>
419 int pyramidSensor<realT, detectorT>::detCols()
420 {
421  return _detCols;
422 }
423 
424 template<typename realT, typename detectorT>
425 void pyramidSensor<realT, detectorT>::detSize(int nrows, int ncols)
426 {
427  if( _detRows == nrows && _detCols == ncols) return;
428 
429  _detRows = nrows;
430  _detCols = ncols;
431 
432  detector.setSize(_detRows, _detCols);
433  detectorImage.image.resize(_detRows, _detCols);
434 
435 
436 }
437 
438 template<typename realT, typename detectorT>
439 realT pyramidSensor<realT, detectorT>::lambda()
440 {
441  return m_lambda;
442 }
443 
444 template<typename realT, typename detectorT>
445 void pyramidSensor<realT, detectorT>::lambda(realT l)
446 {
447  m_lambda = l;
448 
449  //---------------------------------------
450  // Check if wavelength vector is filled
451  //---------------------------------------
452  if( m_wavelengths.size() == 0 )
453  {
454  m_wavelengths.resize(1, m_lambda);
455  _wavelengthWeights.resize(1, 1.0);
456  }
457 }
458 
459 
460 template<typename realT, typename detectorT>
461 template<typename AOSysT>
462 void pyramidSensor<realT, detectorT>::linkSystem(AOSysT & AOSys)
463 {
464  AOSys.wfs.wfPS(AOSys.m_wfPS);
465  AOSys.wfs.D(AOSys._D);
466 
467 }
468 
469 template<typename realT, typename detectorT>
470 int pyramidSensor<realT, detectorT>::wfPS()
471 {
472  return m_wfPS;
473 }
474 
475 template<typename realT, typename detectorT>
476 void pyramidSensor<realT, detectorT>::wfPS(realT ps)
477 {
478  m_wfPS = ps;
479  m_tiltsMade = false;
480 }
481 
482 template<typename realT, typename detectorT>
483 realT pyramidSensor<realT, detectorT>::D()
484 {
485  return _D;
486 }
487 
488 template<typename realT, typename detectorT>
489 void pyramidSensor<realT, detectorT>::D(realT d)
490 {
491  _D = d;
492 }
493 
494 template<typename realT, typename detectorT>
495 realT pyramidSensor<realT, detectorT>::perStep()
496 {
497  return m_perStep;
498 }
499 
500 template<typename realT, typename detectorT>
501 void pyramidSensor<realT, detectorT>::perStep(realT prStp)
502 {
503  m_perStep = prStp;
504 
505  if(m_modRadius <= 0)
506  {
507  m_modSteps = 0;
508  return;
509  }
510 
511  realT radPerStep = m_perStep/m_modRadius;
512 
513  //Get the minimum number of steps to meet m_perStep while having symmetry for the quadrants
514  m_modSteps = 1;
515  while( math::half_pi<realT>()/m_modSteps > radPerStep ) ++m_modSteps;
516  m_modSteps *= 4;
517 
518  m_tiltsMade = false;
519 }
520 
521 template<typename realT, typename detectorT>
522 int pyramidSensor<realT, detectorT>::modSteps()
523 {
524  return m_modSteps;
525 }
526 
527 template<typename realT, typename detectorT>
528 realT pyramidSensor<realT, detectorT>::modRadius()
529 {
530  return m_modRadius;
531 }
532 
533 template<typename realT, typename detectorT>
534 void pyramidSensor<realT, detectorT>::modRadius(realT mR)
535 {
536  m_modRadius = mR ;
537  perStep(m_perStep); //to calculate m_modSteps;
538 
539  m_tiltsMade = false;
540 }
541 
542 
543 template<typename realT, typename detectorT>
544 int pyramidSensor<realT, detectorT>::quadSz()
545 {
546  return m_quadSz;
547 }
548 
549 template<typename realT, typename detectorT>
550 void pyramidSensor<realT, detectorT>::quadSz(int sz)
551 {
552  if( m_quadSz == sz) return;
553 
554  m_quadSz = sz;
555 
556  m_wfsImage.image.resize(2*m_quadSz, 2*m_quadSz);
557 
558  m_opdMaskMade = false;
559  m_preAllocated = false;
560 }
561 
562 template<typename realT, typename detectorT>
563 template<typename pupilT>
564 void pyramidSensor<realT, detectorT>::makeRefTipImage(pupilT & pupil)
565 {
566  wavefrontT currWF;
567  currWF.setAmplitude( pupil );
568  currWF.setPhase( pupil*0 );
569 
570  refTipImage.image.resize(0,0);
571 
572  senseWavefrontCal(currWF);
573 
574  refTipImage = wfsTipImage;
575 
576 }
577 
578 template<typename realT, typename detectorT>
579 void pyramidSensor<realT, detectorT>::makeOpdMask()
580 {
581  complexFieldT opdMaskQ;
582 
583  m_opdMask.resize(m_wfSz, m_wfSz);
584  opdMaskQ.resize( m_wfSz, m_wfSz);
585 
586  //m_opdMask.set(std::complex<realT>(1,0));
587  realT shift = 0.5*(m_quadSz);
588 
589  opdMaskQ.set(std::complex<realT>(0,1));
590  wfp::tiltWavefront(opdMaskQ, shift, shift);
591  wfp::extractBlock(m_opdMask, 0, 0.5*m_wfSz, 0, 0.5*m_wfSz, opdMaskQ, 0 , 0);
592 
593  opdMaskQ.set(std::complex<realT>(0,1));
594  wfp::tiltWavefront( opdMaskQ, -shift, -shift);
595  wfp::extractBlock(m_opdMask, 0.5*m_wfSz, 0.5*m_wfSz, 0.5*m_wfSz, 0.5*m_wfSz-1, opdMaskQ, 0.5*m_wfSz, 0.5*m_wfSz);
596 
597  opdMaskQ.set(std::complex<realT>(0,1));
598  wfp::tiltWavefront( opdMaskQ, shift, -shift);
599  wfp::extractBlock(m_opdMask, 0, 0.5*m_wfSz, 0.5*m_wfSz, 0.5*m_wfSz, opdMaskQ, 0 , 0.5*m_wfSz);
600 
601  opdMaskQ.set(std::complex<realT>(0,1));
602  wfp::tiltWavefront( opdMaskQ, -shift, shift);
603  wfp::extractBlock(m_opdMask, 0.5*m_wfSz, 0.5*m_wfSz, 0, 0.5*m_wfSz, opdMaskQ, 0.5*m_wfSz, 0);
604 
605  /*for(int n =0; n < m_wfSz; ++n)
606  {
607  m_opdMask(0.5*m_wfSz, n) = 0;
608  m_opdMask(n, 0.5*m_wfSz) = 0;
609  }*/
610 
611  m_opdMaskMade = true;
612 
613 
614 }
615 
616 template <typename realT, typename detectorT>
617 void pyramidSensor<realT, detectorT>::makeTilts()
618 {
619  constexpr realT pi = math::pi<realT>();
620 
621  realT dang = 2 * pi / (m_modSteps);
622  realT dx, dy;
623 
624  m_tilts.resize(m_modSteps);
625 
626  std::cout << "WF Size: " << m_wfSz << "\n";
627  std::cout << "WF PS: " << m_wfPS << "\n";
628  std::cout << "Lambda: " << m_lambda << "\n";
629  std::cout << "Pyr. PS: " << wfp::fftPlateScale<realT>(m_wfSz, m_wfPS, m_lambda) * 206265. << " (mas/pix)\n";
630  std::cout << "Mod. steps: " << m_modSteps << "\n";
631  std::cout << "Mod rad: " << m_modRadius * (m_lambda / _D) / wfp::fftPlateScale<realT>(m_wfSz, m_wfPS, m_lambda) << " (pixels)\n";
632 
633  for (int i = 0; i < m_modSteps; ++i)
634  {
635  dx = m_modRadius * (m_lambda / _D) / wfp::fftPlateScale<realT>(m_wfSz, m_wfPS, m_lambda) * cos(0.0 * dang + dang * i);
636  dy = m_modRadius * (m_lambda / _D) / wfp::fftPlateScale<realT>(m_wfSz, m_wfPS, m_lambda) * sin(0.0 * dang + dang * i);
637 
638  m_tilts[i].resize(m_wfSz, m_wfSz);
639  m_tilts[i].set(std::complex<realT>(0, 1));
640 
641  wfp::tiltWavefront(m_tilts[i], dx, dy);
642  }
643 
644  m_tiltsMade = true;
645 }
646 
647 template<typename realT, typename detectorT>
648 void pyramidSensor<realT, detectorT>::allocThreadMem()
649 {
650  m_pupilPlaneCF.resize(m_wfSz, m_wfSz);
651 
652  int maxTh = omp_get_max_threads();
653  m_th_tiltedPlane.resize(maxTh);
654 
655  m_th_focalPlane.resize(maxTh);
656 
657  m_th_focalImage.resize(maxTh);
658 
659  m_th_sensorPlane.resize(maxTh);
660 
661  m_th_sensorImage.resize(maxTh);
662 
663  for(int nTh=0;nTh<maxTh; ++nTh)
664  {
665  m_th_tiltedPlane[nTh].resize(m_wfSz, m_wfSz);
666 
667  m_th_focalPlane[nTh].resize(m_wfSz, m_wfSz);
668 
669  m_th_focalImage[nTh].resize(m_wfSz, m_wfSz);
670 
671  m_th_sensorPlane[nTh].resize(m_wfSz, m_wfSz);
672 
673  m_th_sensorImage[nTh].resize(m_quadSz*2, m_quadSz*2);
674  }
675 
676  m_preAllocated = true;
677 }
678 
679 template<typename realT, typename detectorT>
680 void pyramidSensor<realT, detectorT>::preAllocate()
681 {
682  makeTilts();
683  makeOpdMask();
684  allocThreadMem();
685 }
686 
687 template<typename realT, typename detectorT>
688 int pyramidSensor<realT, detectorT>::iTime()
689 {
690  return _iTime;
691 }
692 
693 template<typename realT, typename detectorT>
694 void pyramidSensor<realT, detectorT>::iTime(int it)
695 {
696  if(it < 1)
697  {
698  std::cerr << "iTime must be >= 1. Correcting\n";
699  it = 1;
700  }
701 
702  _iTime = it;
703 
704  _wavefronts.resize(_iTime+2);
705  _lastWavefront = -1;
706 
707  detector.expTime(_simStep*_iTime);
708 
709 }
710 
711 template<typename realT, typename detectorT>
712 int pyramidSensor<realT, detectorT>::roTime()
713 {
714  return roTime;
715 }
716 
717 template<typename realT, typename detectorT>
718 void pyramidSensor<realT, detectorT>::roTime(int rt)
719 {
720  if(rt < 1)
721  {
722  std::cerr << "roTime must be >= 1. Correcting\n";
723  rt = 1;
724  }
725 
726  _roTime = rt;
727 
728 
729 }
730 
731 template<typename realT, typename detectorT>
732 realT pyramidSensor<realT, detectorT>::simStep()
733 {
734  return simStep;
735 }
736 
737 template<typename realT, typename detectorT>
738 void pyramidSensor<realT, detectorT>::simStep(realT st)
739 {
740 
741  _simStep = st;
742 
743  detector.expTime(_simStep*_iTime);
744 
745 
746 }
747 
748 
749 template<typename realT, typename detectorT>
750 bool pyramidSensor<realT, detectorT>::senseWavefront(wavefrontT & pupilPlane)
751 {
752 
753  ++_lastWavefront;
754  if(_lastWavefront >= _wavefronts.size()) _lastWavefront = 0;
755  _wavefronts[_lastWavefront].amplitude = pupilPlane.amplitude;
756  _wavefronts[_lastWavefront].phase = pupilPlane.phase;
757  _wavefronts[_lastWavefront].iterNo = pupilPlane.iterNo;
758 
759  //Always skip the first one for averaging to center of iTime.
760  if(firstRun)
761  {
762  firstRun = false;
763  return false;
764  }
765 
766  ++_iTime_counter;
767 
768 
769  bool rv = false;
770 
771  if(_reading)
772  {
773  ++_roTime_counter;
774 
775  if(_roTime_counter >= _roTime)
776  {
777  detector.exposeImage(detectorImage.image, m_wfsImage.image);
778 
779  detectorImage.tipImage = wfsTipImage.image;
780  detectorImage.iterNo = m_wfsImage.iterNo;
781 
782  _roTime_counter = 0;
783  _reading=0;
784  rv = true;
785  }
786  }
787 
788  if( _iTime_counter >= _iTime)
789  {
790  doSenseWavefront();
791  _iTime_counter = 0;
792 
793  _reading = 1;
794  _roTime_counter = 0;
795  }
796 
797 
798 
799  return rv;
800 
801 }
802 
803 template<typename realT, typename detectorT>
804 bool pyramidSensor<realT, detectorT>::senseWavefrontCal(wavefrontT & pupilPlane)
805 {
806 
807  _lastWavefront =1;
808 
809  _wavefronts[0].amplitude = pupilPlane.amplitude;
810  _wavefronts[0].phase = pupilPlane.phase;
811 
812  _wavefronts[1].amplitude = pupilPlane.amplitude;
813  _wavefronts[1].phase = pupilPlane.phase;
814 
815 
816  BREAD_CRUMB;
817 
818  doSenseWavefront();
819 
820  BREAD_CRUMB;
821 
822  detector.exposeImage(detectorImage.image, m_wfsImage.image);
823 
824  BREAD_CRUMB;
825  detectorImage.tipImage = wfsTipImage.image;
826 
827  BREAD_CRUMB;
828  return true;
829 
830 }
831 
832 template<typename realT, typename detectorT>
833 void pyramidSensor<realT, detectorT>::doSenseWavefront()
834 {
835  BREAD_CRUMB;
836 
837  wavefrontT pupilPlane;
838 
839  /* Here make average wavefront for now */
840  int _firstWavefront = _lastWavefront - _iTime;
841  if(_firstWavefront < 0) _firstWavefront += _wavefronts.size();
842 
843  pupilPlane.amplitude = _wavefronts[_firstWavefront].amplitude;
844  pupilPlane.phase = _wavefronts[_firstWavefront].phase;
845 
846  realT avgIt = _wavefronts[_firstWavefront].iterNo;
847 
848  BREAD_CRUMB;
849 
850  for(int i=0; i<_iTime; ++i)
851  {
852  ++_firstWavefront;
853  if( (size_t) _firstWavefront >= _wavefronts.size()) _firstWavefront = 0;
854 
855  pupilPlane.amplitude += _wavefronts[_firstWavefront].amplitude;
856  pupilPlane.phase += _wavefronts[_firstWavefront].phase;
857  avgIt += _wavefronts[_firstWavefront].iterNo;
858  }
859 
860  BREAD_CRUMB;
861 
862  pupilPlane.amplitude /= (_iTime+1);
863  pupilPlane.phase /= (_iTime+1);
864 
865  avgIt /= (_iTime + 1.0);
866 
867  /*=====================================*/
868  doSenseWavefront(pupilPlane);
869 
870  m_wfsImage.iterNo = avgIt;
871 }
872 
873 template<typename realT, typename detectorT>
874 void pyramidSensor<realT, detectorT>::doSenseWavefront(wavefrontT & pupilPlane)
875 {
876  if(m_modRadius == 0) return doSenseWavefrontNoMod(pupilPlane);
877 
878  if(!m_preAllocated) preAllocate();
879 
880  BREAD_CRUMB;
881 
882  m_wfsImage.image.resize(2*m_quadSz, 2*m_quadSz);
883  m_wfsImage.image.setZero();
884 
885  wfsTipImage.image.resize(m_wfSz, m_wfSz);
886  wfsTipImage.image.setZero();
887 
888  for(size_t l = 0; l<m_wavelengths.size(); ++l)
889  {
890  pupilPlane.lambda = m_lambda;
891  pupilPlane.getWavefront(m_pupilPlaneCF, m_wavelengths[l], m_wfSz);
892 
893  #pragma omp parallel
894  {
895  int nTh = omp_get_thread_num();
896 
897  m_th_sensorImage[nTh].setZero();
898  m_th_focalImage[nTh].setZero();
899 
900  complexT * tp_data;
901  complexT * pp_data;
902  complexT * ti_data;
903  complexT * fp_data;
904  complexT * opd_data;
905 
906  pp_data = m_pupilPlaneCF.data();
907  tp_data = m_th_tiltedPlane[nTh].data();
908  fp_data = m_th_focalPlane[nTh].data();
909  opd_data = m_opdMask.data();
910 
911  int nelem = m_wfSz*m_wfSz;
912 
913  #pragma omp for
914  for(int i=0; i < m_modSteps; ++i)
915  {
916 
917  ti_data = m_tilts[i].data();
918 
919  //---------------------------------------------
920  //Apply the modulating tip
921  //---------------------------------------------
922  for(int ii=0; ii< nelem; ++ii)
923  {
924  tp_data[ii] = pp_data[ii]*ti_data[ii];
925  }
926 
927  //---------------------------------------------
928  //Propagate to Pyramid tip
929  //---------------------------------------------
930 
931  m_frProp.propagatePupilToFocal(m_th_focalPlane[nTh], m_th_tiltedPlane[nTh], true);
932 
933  //---------------------------------------------
934  //Extract the tip image.
935  //---------------------------------------------
936  wfp::extractIntensityImageAccum(m_th_focalImage[nTh], 0, m_wfSz, 0, m_wfSz, m_th_focalPlane[nTh], 0, 0);
937  //---------------------------------------------
938  //Now apply the pyramid OPD
939  //---------------------------------------------
940  for(int ii=0; ii< nelem; ++ii)
941  {
942  fp_data[ii] = fp_data[ii]*opd_data[ii];
943  }
944 
945  //---------------------------------------------
946  //Propagate to sensor plane
947  //---------------------------------------------
948  m_frProp.propagateFocalToPupil(m_th_sensorPlane[nTh], m_th_focalPlane[nTh],true);
949 
950  //---------------------------------------------
951  //Extract the image.
952  //---------------------------------------------
953  wfp::extractIntensityImageAccum(m_th_sensorImage[nTh], 0, 2*m_quadSz, 0, 2*m_quadSz, m_th_sensorPlane[nTh],
954  0.5*m_wfSz-m_quadSz, 0.5*m_wfSz-m_quadSz);
955 
956  }//for
957 
958  BREAD_CRUMB;
959 
960  #pragma omp critical
961  {
962  m_wfsImage.image += m_th_sensorImage[nTh] * _wavelengthWeights[l];
963  wfsTipImage.image += m_th_focalImage[nTh] * _wavelengthWeights[l];
964  }
965  }//#pragma omp parallel
966 
967  } //l for wavelength
968 
969 
970  BREAD_CRUMB;
971 
972  m_wfsImage.image /= m_modSteps;
973  wfsTipImage.image /= m_modSteps;
974 
975 }
976 
977 
978 template<typename realT, typename detectorT>
979 void pyramidSensor<realT, detectorT>::doSenseWavefrontNoMod(wavefrontT & pupilPlane)
980 {
981  BREAD_CRUMB;
982 
983  m_wfsImage.image.resize(2*m_quadSz, 2*m_quadSz);
984  m_wfsImage.image.setZero();
985 
986  complexFieldT m_pupilPlaneCF;
987 
988  pupilPlane.getWavefront(m_pupilPlaneCF, m_wfSz);
989 
990  if(!m_opdMaskMade) makeOpdMask();
991 
992  complexFieldT tiltedPlane;
993  complexFieldT focalPlane;
994  complexFieldT sensorPlane;
995 
996  tiltedPlane.resize(m_wfSz, m_wfSz);
997  focalPlane.resize(m_wfSz, m_wfSz);
998  sensorPlane.resize(m_wfSz, m_wfSz);
999 
1000  int nelem = m_wfSz*m_wfSz;
1001 
1002  complexT * tp_data = tiltedPlane.data();
1003  complexT * pp_data = m_pupilPlaneCF.data();
1004  complexT * opd_data = m_opdMask.data();
1005  complexT * fp_data = focalPlane.data();
1006 
1007  BREAD_CRUMB;
1008 
1009  //---------------------------------------------
1010  //Apply NO modulator tilt
1011  //---------------------------------------------
1012  for(int ii=0; ii< nelem; ++ii)
1013  {
1014  tp_data[ii] = pp_data[ii];
1015  }
1016 
1017  BREAD_CRUMB;
1018 
1019  //---------------------------------------------
1020  //Propagate to Pyramid tip
1021  //---------------------------------------------
1022  m_frProp.propagatePupilToFocal(focalPlane, tiltedPlane, true);
1023 
1024 
1025  BREAD_CRUMB;
1026 
1027  //---------------------------------------------
1028  //Now apply the pyramid OPD
1029  //---------------------------------------------
1030  for(int ii=0; ii< nelem; ++ii)
1031  {
1032  fp_data[ii] = fp_data[ii]*opd_data[ii];
1033  }
1034 
1035 
1036  BREAD_CRUMB;
1037 
1038  //---------------------------------------------
1039  //Propagate to sensor plane
1040  //---------------------------------------------
1041  m_frProp.propagateFocalToPupil(sensorPlane, focalPlane, true);
1042 
1043  BREAD_CRUMB;
1044 
1045  //---------------------------------------------
1046  //Extract the image.
1047  //---------------------------------------------
1048  wfp::extractIntensityImageAccum(m_wfsImage.image, 0, 2*m_quadSz, 0, 2*m_quadSz, sensorPlane, 0.5*m_wfSz-m_quadSz, 0.5*m_wfSz-m_quadSz);
1049 
1050  BREAD_CRUMB;
1051 
1052 }
1053 
1054 } //namespace sim
1055 } //namespace AO
1056 } //namespace mx
1057 
1058 #endif //__pyramidSensor_hpp__
1059 
constexpr T pi()
Get the value of pi.
Definition: constants.hpp:52
void tiltWavefront(wavefrontT &complexWavefront, typename wavefrontT::Scalar::value_type xTilt, typename wavefrontT::Scalar::value_type yTilt)
Apply a tilt to a wavefront.
The mxlib c++ namespace.
Definition: mxError.hpp:107