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;
44 typedef wavefront<floatT> wavefrontT;
47 typedef mx::imagingArray<std::complex<floatT>, fftwAllocator<std::complex<floatT>>, 0> complexFieldT;
50 typedef Eigen::Array<floatT, Eigen::Dynamic, Eigen::Dynamic> wfsImageT;
52 typedef _detectorT detectorT;
83 mx::fraunhoferImager<complexFieldT> fi;
86 std::vector<complexFieldT> tilts;
94 std::vector<wavefrontT> _wavefronts;
109 wfsImageT detectorImage;
139 void detSize(
int nrows,
int ncols );
151 void lambda( floatT l );
157 void iTime(
int it );
163 void roTime(
int rt );
169 void simStep( floatT st );
171 template <
typename AOSysT>
172 void linkSystem( AOSysT &AOSys );
178 bool senseWavefront( wavefrontT &pupilPlane );
183 bool senseWavefrontCal( wavefrontT &pupilPlane );
197 void wfPS( floatT ps );
221 void modSteps(
int mSt );
233 void modRadius( floatT mR );
250 void quadSz(
int sz );
258 void doSenseWavefront();
259 void doSenseWavefrontNoMod( wavefrontT & );
264template <
typename _
floatT,
typename _detectorT>
265pyramidSensor<_floatT, _detectorT>::pyramidSensor()
288 ds9_interface_init( &ds9i );
289 ds9_interface_set_title( &ds9i,
"PyWFS" );
292template <
typename _
floatT,
typename _detectorT>
293int pyramidSensor<_floatT, _detectorT>::wfSz()
298template <
typename _
floatT,
typename _detectorT>
299void pyramidSensor<_floatT, _detectorT>::wfSz(
int sz )
306 fi.setWavefrontSizePixels( _wfSz );
311template <
typename _
floatT,
typename _detectorT>
312int pyramidSensor<_floatT, _detectorT>::detRows()
317template <
typename _
floatT,
typename _detectorT>
318int pyramidSensor<_floatT, _detectorT>::detCols()
323template <
typename _
floatT,
typename _detectorT>
324void pyramidSensor<_floatT, _detectorT>::detSize(
int nrows,
int ncols )
326 if( _detRows == nrows && _detCols == ncols )
332 detector.setSize( _detRows, _detCols );
333 detectorImage.resize( _detRows, _detCols );
336template <
typename _
floatT,
typename _detectorT>
337_floatT pyramidSensor<_floatT, _detectorT>::lambda()
342template <
typename _
floatT,
typename _detectorT>
343void pyramidSensor<_floatT, _detectorT>::lambda( _floatT l )
348template <
typename _
floatT,
typename _detectorT>
349template <
typename AOSysT>
350void pyramidSensor<_floatT, _detectorT>::linkSystem( AOSysT &AOSys )
352 AOSys.wfs.wfPS( AOSys._wfPS );
353 AOSys.wfs.D( AOSys._D );
356template <
typename _
floatT,
typename _detectorT>
357int pyramidSensor<_floatT, _detectorT>::wfPS()
362template <
typename _
floatT,
typename _detectorT>
363void pyramidSensor<_floatT, _detectorT>::wfPS( _floatT ps )
368template <
typename _
floatT,
typename _detectorT>
369_floatT pyramidSensor<_floatT, _detectorT>::D()
374template <
typename _
floatT,
typename _detectorT>
375void pyramidSensor<_floatT, _detectorT>::D( _floatT d )
380template <
typename _
floatT,
typename _detectorT>
381int pyramidSensor<_floatT, _detectorT>::modSteps()
386template <
typename _
floatT,
typename _detectorT>
387void pyramidSensor<_floatT, _detectorT>::modSteps(
int mSt )
394template <
typename _
floatT,
typename _detectorT>
395_floatT pyramidSensor<_floatT, _detectorT>::modRadius()
400template <
typename _
floatT,
typename _detectorT>
401void pyramidSensor<_floatT, _detectorT>::modRadius( _floatT mR )
408template <
typename _
floatT,
typename _detectorT>
409int pyramidSensor<_floatT, _detectorT>::quadSz()
414template <
typename _
floatT,
typename _detectorT>
415void pyramidSensor<_floatT, _detectorT>::quadSz(
int sz )
422 wfsImage.resize( 2 * _quadSz, 2 * _quadSz );
425template <
typename _
floatT,
typename _detectorT>
426void pyramidSensor<_floatT, _detectorT>::makeTilts()
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 ) );
459template <
typename _
floatT,
typename _detectorT>
460int pyramidSensor<_floatT, _detectorT>::iTime()
465template <
typename _
floatT,
typename _detectorT>
466void pyramidSensor<_floatT, _detectorT>::iTime(
int it )
470 std::cerr <<
"iTime must be >= 1. Correcting\n";
476 _wavefronts.resize( _iTime + 2 );
479 detector.expTime( _simStep * _iTime );
482template <
typename _
floatT,
typename _detectorT>
483int pyramidSensor<_floatT, _detectorT>::roTime()
488template <
typename _
floatT,
typename _detectorT>
489void pyramidSensor<_floatT, _detectorT>::roTime(
int rt )
493 std::cerr <<
"roTime must be >= 1. Correcting\n";
500template <
typename _
floatT,
typename _detectorT>
501_floatT pyramidSensor<_floatT, _detectorT>::simStep()
506template <
typename _
floatT,
typename _detectorT>
507void pyramidSensor<_floatT, _detectorT>::simStep( _floatT st )
512 detector.expTime( _simStep * _iTime );
515template <
typename _
floatT,
typename _detectorT>
516bool pyramidSensor<_floatT, _detectorT>::senseWavefront( wavefrontT &pupilPlane )
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>
572bool pyramidSensor<_floatT, _detectorT>::senseWavefrontCal( wavefrontT &pupilPlane )
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;
constexpr T pi()
Get the value of pi.
constexpr floatT six_fifths()
Return 6/5 in the specified precision.
void tiltWavefront(wavefrontT &complexWavefront, typename wavefrontT::Scalar::value_type xTilt, typename wavefrontT::Scalar::value_type yTilt)
Apply a tilt to a wavefront.
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.