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 );
702 extractIntensityImageAccum( sensorImage,
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 );
714 extractIntensityImageAccum( sensorImage,
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 );
726 extractIntensityImageAccum( sensorImage,
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 );
739 extractIntensityImageAccum( sensorImage,
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 );
833 extractIntensityImageAccum( sensorImage,
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 );
845 extractIntensityImageAccum( sensorImage,
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 );
857 extractIntensityImageAccum( sensorImage,
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 );
869 extractIntensityImageAccum( sensorImage,
875 0.5 * _wfSz - 1.5 * _quadSz + dSz,
876 0.5 * _wfSz - 1.5 * _quadSz + dSz );
880 wfsImage += sensorImage;
A Pyramid Sensor Simulation.
int roTime()
Get the PyWFS detector readout time, in time steps.
realT lambda()
Get the PyWFS central wavelength.
floatT _simStep
The simulation stepsize in seconds.
pyramidSensor()
Default c'tor.
floatT D()
Get the telescope diameter.
int _modSteps
Number of steps in the modulation simulation.
wfsImageT wfsImage
The image formed by the WFS.
int wfSz()
Get the wavefront size in pixels.
int _wfSz
Size of the wavefront in pixels.
realT simStep()
Get the simulation step-size, in seconds.
int _roTime
Readout time in loop steps.
mx::imagingArray< std::complex< floatT >, fftwAllocator< std::complex< floatT > >, 0 > complexFieldT
The wavefront complex field type.
int wfPS()
Get the wavefront pixel scale in meters per pixel.
pyramidSensor()
Default c'tor.
void detSize(const uint32_t &nrows, const uint32_t &ncols)
Set the detector columns in pixels.
int iTime()
Get the PyWFS integration time, in time steps.
floatT _wfPS
Wavefront pixel scale, in meters/pixel.
int _iTime
Integration time in loop steps.
floatT modRadius()
Get the radius of modulation.
void linkSystem(AOSysT &AOSys)
Link this WFS to an AO system simulation.
realT wfPS()
Get the wavefront pixel scale in meters per pixel.
int wfSz()
Get the wavefront size in pixels.
uint32_t detCols()
Get the detector columns in pixels.
int modSteps()
Get the number of modulation steps.
int roTime()
Get the PyWFS detector readout time, in time steps.
int modSteps()
Get the number of modulation steps.
floatT _lambda
Central wavelength, in meters.
int iTime()
Get the PyWFS integration time, in time steps.
floatT simStep()
Get the simulation step-size, in seconds.
wavefront< floatT > wavefrontT
The wavefront data type.
int quadSz()
Get the quadrant size in pixels.
bool senseWavefront(wavefrontT &pupilPlane)
Sense the wavefront aberrations.
uint32_t detRows()
Get the detector rows in pixels.
floatT _D
Telescope diameter, in meters.
floatT _modRadius
Radius of the modulation in pixels.
int detRows()
Get the detector rows in pixels.
realT modRadius()
Get the radius of modulation.
std::complex< realT > complexT
The complex floating point type used for calculations.
bool senseWavefrontCal(wavefrontT &pupilPlane)
Sense the wavefront aberrations in calibration mode.
int detCols()
Get the detector columns in pixels.
bool senseWavefront(wavefrontT &pupilPlane)
Sense the wavefront aberrations.
realT D()
Get the telescope diameter.
_detectorT detectorT
The wavefront sensor detector image type.
bool senseWavefrontCal(wavefrontT &pupilPlane)
Sense the wavefront aberrations in a calibration mode.
floatT lambda()
Get the PyWFS central wavelength.
int _quadSz
The size of the PyWFS quadrant.
detectorT detector
The WFS detector.
Eigen::Array< floatT, Eigen::Dynamic, Eigen::Dynamic > wfsImageT
The wavefront sensor detector image type.
wfsImageT detectorImage
The image on the detector, resized from wfsImage.
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.
Structure containing the phase and amplitude of a wavefront.