8#ifndef __pyramidSensor_hpp__
9#define __pyramidSensor_hpp__
11#include "mx/imagingUtils.hpp"
12#include "mx/fraunhoferImager.hpp"
13#include "mx/timeUtils.hpp"
14#include "mx/fitsFile.hpp"
16#include "../../math/constants.hpp"
18#include "wavefront.hpp"
20#include "mx/imageTransforms.hpp"
23#define BREAD_CRUMB std::cout << "DEBUG: " << __FILE__ << " " << __LINE__ << "\n";
35template <
typename _
floatT,
typename _detectorT>
39 typedef _floatT floatT;
41 typedef std::complex<floatT>
complexT;
47 typedef mx::imagingArray<std::complex<floatT>, fftwAllocator<std::complex<floatT>>, 0>
complexFieldT;
50 typedef Eigen::Array<floatT, Eigen::Dynamic, Eigen::Dynamic>
wfsImageT;
83 mx::fraunhoferImager<complexFieldT> fi;
86 std::vector<complexFieldT> tilts;
94 std::vector<wavefrontT> _wavefronts;
139 void detSize(
int nrows,
int ncols );
157 void iTime(
int it );
171 template <
typename AOSysT>
197 void wfPS( floatT ps );
258 void doSenseWavefront();
264template <
typename _
floatT,
typename _detectorT>
288 ds9_interface_init( &ds9i );
289 ds9_interface_set_title( &ds9i,
"PyWFS" );
292template <
typename _
floatT,
typename _detectorT>
298template <
typename _
floatT,
typename _detectorT>
306 fi.setWavefrontSizePixels( _wfSz );
311template <
typename _
floatT,
typename _detectorT>
317template <
typename _
floatT,
typename _detectorT>
323template <
typename _
floatT,
typename _detectorT>
326 if( _detRows == nrows && _detCols == ncols )
332 detector.setSize( _detRows, _detCols );
333 detectorImage.resize( _detRows, _detCols );
336template <
typename _
floatT,
typename _detectorT>
342template <
typename _
floatT,
typename _detectorT>
348template <
typename _
floatT,
typename _detectorT>
349template <
typename AOSysT>
352 AOSys.wfs.wfPS( AOSys._wfPS );
353 AOSys.wfs.D( AOSys._D );
356template <
typename _
floatT,
typename _detectorT>
362template <
typename _
floatT,
typename _detectorT>
368template <
typename _
floatT,
typename _detectorT>
374template <
typename _
floatT,
typename _detectorT>
380template <
typename _
floatT,
typename _detectorT>
386template <
typename _
floatT,
typename _detectorT>
394template <
typename _
floatT,
typename _detectorT>
400template <
typename _
floatT,
typename _detectorT>
408template <
typename _
floatT,
typename _detectorT>
414template <
typename _
floatT,
typename _detectorT>
422 wfsImage.resize( 2 * _quadSz, 2 * _quadSz );
425template <
typename _
floatT,
typename _detectorT>
430 _floatT dang = 2 * pi / _modSteps;
433 tilts.resize( _modSteps );
435 std::cout <<
"WF Size: " << _wfSz <<
"\n";
436 std::cout <<
"WF PS: " << _wfPS <<
"\n";
437 std::cout <<
"Lambda: " << _lambda <<
"\n";
439 std::cout <<
"Pyr. PS: " << mx::fftPlateScale<floatT>( _wfSz, _wfPS, _lambda ) * 206265. <<
" (mas/pix)\n";
440 std::cout <<
"Mod rad: " << _modRadius * ( _lambda / _D ) / mx::fftPlateScale<floatT>( _wfSz, _wfPS, _lambda )
443 for(
int i = 0; i < _modSteps; ++i )
445 dx = _modRadius * ( _lambda / _D ) / mx::fftPlateScale<floatT>( _wfSz, _wfPS, _lambda ) *
446 cos( 0.5 * dang + dang * i );
447 dy = _modRadius * ( _lambda / _D ) / mx::fftPlateScale<floatT>( _wfSz, _wfPS, _lambda ) *
448 sin( 0.5 * dang + dang * i );
450 tilts[i].resize( _wfSz, _wfSz );
451 tilts[i].set( std::complex<_floatT>( 0, 1 ) );
453 tiltWavefront( tilts[i], dx, dy );
459template <
typename _
floatT,
typename _detectorT>
465template <
typename _
floatT,
typename _detectorT>
470 std::cerr <<
"iTime must be >= 1. Correcting\n";
476 _wavefronts.resize( _iTime + 2 );
479 detector.expTime( _simStep * _iTime );
482template <
typename _
floatT,
typename _detectorT>
488template <
typename _
floatT,
typename _detectorT>
493 std::cerr <<
"roTime must be >= 1. Correcting\n";
500template <
typename _
floatT,
typename _detectorT>
506template <
typename _
floatT,
typename _detectorT>
512 detector.expTime( _simStep * _iTime );
515template <
typename _
floatT,
typename _detectorT>
520 if( _lastWavefront >= _wavefronts.size() )
522 _wavefronts[_lastWavefront].amplitude = pupilPlane.amplitude;
523 _wavefronts[_lastWavefront].phase = pupilPlane.phase;
540 if( _roTime_counter >= _roTime )
542 std::cerr <<
"PyWFS: reading\n";
543 detector.exposeImage( detectorImage, wfsImage );
544 ds9_interface_display_raw( &ds9i,
546 detectorImage.data(),
547 detectorImage.rows(),
548 detectorImage.cols(),
550 mx::getFitsBITPIX<floatT>() );
558 if( _iTime_counter >= _iTime )
560 std::cerr <<
"PyWFS: sensing\n";
571template <
typename _
floatT,
typename _detectorT>
577 _wavefronts[0].amplitude = pupilPlane.amplitude;
578 _wavefronts[0].phase = pupilPlane.phase;
580 _wavefronts[1].amplitude = pupilPlane.amplitude;
581 _wavefronts[1].phase = pupilPlane.phase;
585 detector.exposeImage( detectorImage, wfsImage );
593template <
typename _
floatT,
typename _detectorT>
594void pyramidSensor<_floatT, _detectorT>::doSenseWavefront()
598 if( tiltsMade ==
false )
604 wavefrontT pupilPlane;
607 int _firstWavefront = _lastWavefront - _iTime;
608 if( _firstWavefront < 0 )
609 _firstWavefront += _wavefronts.size();
611 pupilPlane.amplitude = _wavefronts[_firstWavefront].amplitude;
612 pupilPlane.phase = _wavefronts[_firstWavefront].phase;
617 for(
int i = 0; i < _iTime; ++i )
620 if( _firstWavefront >= _wavefronts.size() )
623 pupilPlane.amplitude += _wavefronts[_firstWavefront].amplitude;
624 pupilPlane.phase += _wavefronts[_firstWavefront].phase;
627 pupilPlane.amplitude /= ( _iTime + 1 );
628 pupilPlane.phase /= ( _iTime + 1 );
632 if( _modRadius == 0 )
633 return doSenseWavefrontNoMod( pupilPlane );
638 wfsImage.resize( 2 * _quadSz, 2 * _quadSz );
641 complexFieldT pupilPlaneCF;
642 pupilPlane.getWavefront( pupilPlaneCF, _wfSz );
644 complexFieldT focalPlaneCF;
645 focalPlaneCF.resize( _wfSz, _wfSz );
649 complexFieldT tiltedPlane;
650 complexFieldT focalPlane;
651 complexFieldT sensorPlane;
652 complexFieldT temp_ul;
653 complexFieldT temp_ur;
654 complexFieldT temp_ll;
655 complexFieldT temp_lr;
657 wfsImageT sensorImage;
659 tiltedPlane.resize( _wfSz, _wfSz );
660 focalPlane.resize( _wfSz, _wfSz );
661 sensorPlane.resize( _wfSz, _wfSz );
663 temp_ul.resize( _wfSz, _wfSz );
664 temp_ul.set( (complexT)0 );
666 temp_ur.resize( _wfSz, _wfSz );
667 temp_ur.set( (complexT)0 );
669 temp_ll.resize( _wfSz, _wfSz );
670 temp_ll.set( (complexT)0 );
672 temp_lr.resize( _wfSz, _wfSz );
673 temp_lr.set( (complexT)0 );
676 sensorImage.resize( _quadSz * 2, _quadSz * 2 );
677 sensorImage.setZero();
679 int dSz = ( 0.5 * _wfSz - 0.5 * _quadSz + 2 * _quadSz ) - _wfSz;
684 for(
int i = 0; i < _modSteps; ++i )
686 int nelem = _wfSz * _wfSz;
688 complexT *tp_data = tiltedPlane.data();
689 complexT *pp_data = pupilPlaneCF.data();
690 complexT *ti_data = tilts[i].data();
692 for(
int ii = 0; ii < nelem; ++ii )
694 tp_data[ii] = pp_data[ii] * ti_data[ii];
697 fi.propagatePupilToFocal( focalPlane, tiltedPlane );
698 temp_ul.set( complexT( 0, 0 ) );
699 extractBlock( temp_ul, 0, 0.5 * _wfSz, 0, 0.5 * _wfSz, focalPlane, 0, 0 );
701 fi.propagateFocalToPupil( sensorPlane, temp_ul );
708 0.5 * _wfSz - 0.5 * _quadSz,
709 0.5 * _wfSz - 0.5 * _quadSz );
711 temp_ur.set( complexT( 0, 0 ) );
712 extractBlock( temp_ur, 0.5 * _wfSz, 0.5 * _wfSz, 0, 0.5 * _wfSz, focalPlane, 0.5 * _wfSz, 0 );
713 fi.propagateFocalToPupil( sensorPlane, temp_ur );
720 0.5 * _wfSz - 1.5 * _quadSz + dSz,
721 0.5 * _wfSz - 0.5 * _quadSz );
723 temp_ll.set( complexT( 0, 0 ) );
724 extractBlock( temp_ll, 0, 0.5 * _wfSz, 0.5 * _wfSz, 0.5 * _wfSz, focalPlane, 0, 0.5 * _wfSz );
725 fi.propagateFocalToPupil( sensorPlane, temp_ll );
732 0.5 * _wfSz - 0.5 * _quadSz,
733 0.5 * _wfSz - 1.5 * _quadSz + dSz );
735 temp_lr.set( complexT( 0, 0 ) );
737 temp_lr, 0.5 * _wfSz, 0.5 * _wfSz, 0.5 * _wfSz, 0.5 * _wfSz, focalPlane, 0.5 * _wfSz, 0.5 * _wfSz );
738 fi.propagateFocalToPupil( sensorPlane, temp_lr );
745 0.5 * _wfSz - 1.5 * _quadSz + dSz,
746 0.5 * _wfSz - 1.5 * _quadSz + dSz );
757 wfsImage += sensorImage;
764 wfsImage /= _modSteps;
767template <
typename _
floatT,
typename _detectorT>
768void pyramidSensor<_floatT, _detectorT>::doSenseWavefrontNoMod( wavefrontT &pupilPlane )
774 wfsImage.resize( 2 * _quadSz, 2 * _quadSz );
777 complexFieldT pupilPlaneCF;
778 pupilPlane.getWavefront( pupilPlaneCF, _wfSz );
780 complexFieldT focalPlaneCF;
781 focalPlaneCF.resize( _wfSz, _wfSz );
783 complexFieldT tiltedPlane;
784 complexFieldT focalPlane;
785 complexFieldT sensorPlane;
786 complexFieldT temp_ul;
787 complexFieldT temp_ur;
788 complexFieldT temp_ll;
789 complexFieldT temp_lr;
791 wfsImageT sensorImage;
793 tiltedPlane.resize( _wfSz, _wfSz );
794 focalPlane.resize( _wfSz, _wfSz );
795 sensorPlane.resize( _wfSz, _wfSz );
797 temp_ul.resize( _wfSz, _wfSz );
798 temp_ul.set( (complexT)0 );
800 temp_ur.resize( _wfSz, _wfSz );
801 temp_ur.set( (complexT)0 );
803 temp_ll.resize( _wfSz, _wfSz );
804 temp_ll.set( (complexT)0 );
806 temp_lr.resize( _wfSz, _wfSz );
807 temp_lr.set( (complexT)0 );
809 sensorImage.resize( _quadSz * 2, _quadSz * 2 );
810 sensorImage.setZero();
812 int dSz = ( 0.5 * _wfSz - 0.5 * _quadSz + 2 * _quadSz ) - _wfSz;
815 int nelem = _wfSz * _wfSz;
817 complexT *tp_data = tiltedPlane.data();
818 complexT *pp_data = pupilPlaneCF.data();
821 for(
int ii = 0; ii < nelem; ++ii )
823 tp_data[ii] = pp_data[ii];
828 fi.propagatePupilToFocal( focalPlane, tiltedPlane );
829 temp_ul.set( complexT( 0, 0 ) );
830 extractBlock( temp_ul, 0, 0.5 * _wfSz, 0, 0.5 * _wfSz, focalPlane, 0, 0 );
832 fi.propagateFocalToPupil( sensorPlane, temp_ul );
839 0.5 * _wfSz - 0.5 * _quadSz,
840 0.5 * _wfSz - 0.5 * _quadSz );
842 temp_ur.set( complexT( 0, 0 ) );
843 extractBlock( temp_ur, 0.5 * _wfSz, 0.5 * _wfSz, 0, 0.5 * _wfSz, focalPlane, 0.5 * _wfSz, 0 );
844 fi.propagateFocalToPupil( sensorPlane, temp_ur );
851 0.5 * _wfSz - 1.5 * _quadSz + dSz,
852 0.5 * _wfSz - 0.5 * _quadSz );
854 temp_ll.set( complexT( 0, 0 ) );
855 extractBlock( temp_ll, 0, 0.5 * _wfSz, 0.5 * _wfSz, 0.5 * _wfSz, focalPlane, 0, 0.5 * _wfSz );
856 fi.propagateFocalToPupil( sensorPlane, temp_ll );
863 0.5 * _wfSz - 0.5 * _quadSz,
864 0.5 * _wfSz - 1.5 * _quadSz + dSz );
866 temp_lr.set( complexT( 0, 0 ) );
867 extractBlock( temp_lr, 0.5 * _wfSz, 0.5 * _wfSz, 0.5 * _wfSz, 0.5 * _wfSz, focalPlane, 0.5 * _wfSz, 0.5 * _wfSz );
868 fi.propagateFocalToPupil( sensorPlane, temp_lr );
875 0.5 * _wfSz - 1.5 * _quadSz + dSz,
876 0.5 * _wfSz - 1.5 * _quadSz + dSz );
880 wfsImage += sensorImage;
A Pyramid Sensor Simulation.
wavefront< floatT > wavefrontT
The wavefront data type.
int detCols()
Get the detector columns in pixels.
int detRows()
Get the detector rows in pixels.
floatT D()
Get the telescope diameter.
realT lambda()
Get the PyWFS central wavelength.
pyramidSensor()
Default constructor.
int wfSz()
Get the wavefront size in pixels.
bool senseWavefront(wavefrontT &pupilPlane)
Sense the wavefront aberrations.
void detSize(const uint32_t &nrows, const uint32_t &ncols)
Set the detector columns in pixels.
wfsImageT wfsImage
The image formed by the WFS.
int iTime()
Get the PyWFS integration time, in time steps.
realT simStep()
Get the simulation step-size, in seconds.
int wfPS()
Get the wavefront pixel scale in meters per pixel.
int modSteps()
Get the number of modulation steps.
mx::imagingArray< std::complex< floatT >, fftwAllocator< std::complex< floatT > >, 0 > complexFieldT
The wavefront complex field type.
int _quadSz
The size of the PyWFS quadrant.
int iTime()
Get the PyWFS integration time, in time steps.
Eigen::Array< floatT, Eigen::Dynamic, Eigen::Dynamic > wfsImageT
The wavefront sensor detector image type.
floatT lambda()
Get the PyWFS central wavelength.
int _iTime
Integration time in loop steps.
void linkSystem(AOSysT &AOSys)
Link this WFS to an AO system simulation.
pyramidSensor()
Default c'tor.
floatT simStep()
Get the simulation step-size, in seconds.
floatT modRadius()
Get the radius of modulation.
int _wfSz
Size of the wavefront in pixels.
floatT _D
Telescope diameter, in meters.
floatT _simStep
The simulation stepsize in seconds.
realT wfPS()
Get the wavefront pixel scale in meters per pixel.
uint32_t detCols()
Get the detector columns in pixels.
int modSteps()
Get the number of modulation steps.
floatT _lambda
Central wavelength, in meters.
_detectorT detectorT
The wavefront sensor detector image type.
int roTime()
Get the PyWFS detector readout time, in time steps.
floatT _modRadius
Radius of the modulation in pixels.
int _modSteps
Number of steps in the modulation simulation.
bool senseWavefrontCal(wavefrontT &pupilPlane)
Sense the wavefront aberrations in a calibration mode.
detectorT detector
The WFS detector.
int roTime()
Get the PyWFS detector readout time, in time steps.
int quadSz()
Get the quadrant size in pixels.
std::complex< realT > complexT
The complex floating point type used for calculations.
uint32_t detRows()
Get the detector rows in pixels.
realT modRadius()
Get the radius of modulation.
bool senseWavefrontCal(wavefrontT &pupilPlane)
Sense the wavefront aberrations in calibration mode.
bool senseWavefront(wavefrontT &pupilPlane)
Sense the wavefront aberrations.
realT D()
Get the telescope diameter.
floatT _wfPS
Wavefront pixel scale, in meters/pixel.
wfsImageT detectorImage
The image on the detector, resized from wfsImage.
int wfSz()
Get the wavefront size in pixels.
int _roTime
Readout time in loop steps.
constexpr T pi()
Get the value of pi.
constexpr floatT six_fifths()
Return 6/5 in the specified precision.
void extractBlock(imageT1 &dest, int imX0, int imXsz, int imY0, int imYsz, imageT2 &src, int wfX0, int wfY0)
Extract a block from one image and insert it into a second.
void extractIntensityImageAccum(realImageT &im, int imX0, int imXsz, int imY0, int imYsz, complexImageT &wf, int wfX0, int wfY0)
Extract the intensity image from a complex wavefront and accumulate the result.
Structure containing the phase and amplitude of a wavefront.