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.