% -*- mode: Noweb; noweb-code-mode: c-mode -*- \section{Natural guide star adaptive optics} \label{sec:ngsao} In this section, the performance of NGS AO systems are computed. The on--axis wavefront is estimated with a NGS LMMSE. All the systems employ geometric Shack--Hartmann wavefront sensors (SH--WFS). For each system, the on--axis wavefront is estimated several times with a different random draw of the phase screens. The components common to all the systems are defined first: \begin{itemize} \item the science source, <>= source src; src.setup("J",ARCSEC(0) , 0, INFINITY,(N_SIDE_LENSLET+1)*(N_SIDE_LENSLET+1), "SRC"); <>= src.cleanup(); @ \item the atmosphere, <>= atmosphere atm; //atm.setup(20e-2,30,10e3,10,0); atm.gmt_setup(15e-2,60); /* float altitude[] = {0, 10e3}, xi0[] = {0.5, 0.5}, wind_speed[] = {10, 10}, wind_direction[] = {0, 0}; atm.setup(20e-2,30,altitude, xi0, wind_speed, wind_direction); */ <>= atm.cleanup(); @ \item @ the diameter of the telescope, <>= float D = 10; // telescope diameter in meter @ leading to a lenslet size of: <>= float d = D/N_SIDE_LENSLET; @ \item the pupil mask. <>= mask pupil_mask; pupil_mask.setup( (N_SIDE_LENSLET+1)*(N_SIDE_LENSLET+1) ); <>= pupil_mask.cleanup(); @ \item the wavefront sensor centroid container, <>= centroiding cog; cog.setup(N_SIDE_LENSLET,1); <>= cog.cleanup(); @ \item the diffraction limited science imager, <>= imaging imager; imager.setup(N_SIDE_LENSLET+1,1,4,1,1); <>= imager.cleanup(); @ \item the turbulence limited science imager, <>= imaging imager_turb; imager_turb.setup(N_SIDE_LENSLET+1,1,4,1,1); <>= imager_turb.cleanup(); @ \item the science imager for NGSAO LMMSE, <>= imaging imager_ngsao_lmmse; imager_ngsao_lmmse.setup(N_SIDE_LENSLET+1,1,4,1,1); <>= imager_ngsao_lmmse.cleanup(); @ \item the statistical tool. <>= stats S; S.setup(); <>= S.cleanup(); @ \end{itemize} A wide field imager with a set of NGS in a large FOV are also defined: \begin{description} \item[FOV sources] <>= source *fov_src; float z, a; int k_FOV_SRC, N_FOV_SRC = 25; fov_src = (source *)malloc(sizeof(source)*N_FOV_SRC); fov_src[0].setup("J",ARCSEC(0) , 0, INFINITY,(N_SIDE_LENSLET+1)*(N_SIDE_LENSLET+1)); k_FOV_SRC = 0; for (int k_radius=1;k_radius<4;k_radius++) { z = k_radius*10.0; for (int k_angle=0;k_angle<8;k_angle++) { a = 2.0*PI*k_angle/8.0; fov_src[++k_FOV_SRC].setup("J",ARCSEC(z) , a, INFINITY,(N_SIDE_LENSLET+1)*(N_SIDE_LENSLET+1)); } } <>= for (k_FOV_SRC=0;k_FOV_SRC>= imaging fov_imager; fov_imager.setup(N_SIDE_LENSLET+1,1,2,251,1,1); fov_imager.pixel_scale = fov_src[0].wavelength()*N_SIDE_LENSLET/D/2; //fov_imager.set_pointing_direction(0.0,0.0); printf("FOV IMAGER PIXEL SCALE %6.2farcsec\n", fov_imager.pixel_scale*RADIAN2ARCSEC); <>= fov_imager.cleanup(); @ \end{description} @ The Fried geometry for a circular pupil with the intensity [[threshold]] is enforced:: <>= float threshold = 0.5; cog.MASK_SET = fried_geometry_setup(cog.lenslet_mask, pupil_mask.m, N_SIDE_LENSLET, 16, threshold); @ The filtering properties associated with the pupil are set with: <>= pupil_mask.set_filter(); @ The science is propagated through the [[pupil_mask]] to the focal plane of the [[imager]]: <>= src.wavefront.masked(&pupil_mask); imager.propagate(&src); //imager.frame2file("refFrame.bin"); char plotly_name[64], plotly_dir[64]; sprintf(plotly_dir,"NGSAO/D=%.1fm, N=%d (%d samples)/",D,N_SIDE_LENSLET,N_SAMPLE); SET_PLOTLY_NAME(plotly_name,plotly_dir,"frames/diffraction limited"); imager.show_frame(plotly_name); @ A few useful variables are defined here: <>= int NP, NP2, k_SAMPLE; float tau=0.; NP = N_SIDE_LENSLET+1; NP2 = NP*NP; k_SAMPLE = 0; @ The science wavefront is propagated through the atmosphere from [[src]] to [[pupil_mask]]. <>= atm.get_phase_screen(&src,d,NP,d,NP,tau); src.wavefront.masked(); if (k_SAMPLE==(N_SAMPLE-1)) { SET_PLOTLY_NAME(plotly_name,plotly_dir,"phases/science phase screen"); src.wavefront.show_phase(plotly_name); } <>= float science_wf_rms=0.; <>= science_wf_rms += S.var(src.wavefront.phase, &pupil_mask, NP2); @ and then propagated to the focal plane of the imager: <>= imager_turb.propagate(&src); if (k_SAMPLE==(N_SAMPLE-1)) { SET_PLOTLY_NAME(plotly_name,plotly_dir,"frames/turbulence limited"); imager_turb.show_frame(plotly_name); } @ The turbulence wavefront is saved apart for later use: <>= complex_amplitude phase_screen; phase_screen.setup((N_SIDE_LENSLET+1)*(N_SIDE_LENSLET+1)); phase_screen.add_phase(1,src.wavefront.phase); @ All CEO programs must include the following headers which also contains the headers for all the CEO library modules. <
>= #ifndef __CEO_H__ #include "ceo.h" #endif @ The size of the lenslet array is defined in the header: <
>= #define N_SIDE_LENSLET 20 #define _N_LENSLET_ (N_SIDE_LENSLET*N_SIDE_LENSLET) @ The number of atmosphere sample <
>= #define N_SAMPLE 100 #define PLOTLY_LIM (N_SAMPLE-1) // (N_SAMPLE-1) for plotting, higher for disabling plotting @ The main function is: <>= <
> void SET_PLOTLY_NAME(char *name,char *dir,char *path) { strcpy(name, dir); strcat(name,path); } int main(int argc,char *argv[]) { cudaSetDevice(0); <> fprintf(stderr," Samples: %d:\n",N_SAMPLE); for (k_SAMPLE=0;k_SAMPLE> <> } fprintf(stderr,"\n"); <> <> } @ The natural guide star (NGS) is given by: <>= source ngs; ngs.setup("R",ARCSEC(0) , 0, INFINITY, (N_SIDE_LENSLET+1)*(N_SIDE_LENSLET+1), "NGS"); <>= ngs.cleanup(); @ The NGS wavefront gradients are computed with: <>= atm.get_phase_screen_gradient(&cog,N_SIDE_LENSLET,d,&ngs,tau); @ The wavefront is reconstructed from the NGS centroids: <>= LMMSE ngs_lmmse; ngs_lmmse.setup(&atm,&ngs,&src,d,N_SIDE_LENSLET,&pupil_mask,"MINRES"); int cvgce_iteration=0; float elapsed_time=0.; <>= ngs_lmmse.estimation(&cog); elapsed_time += ngs_lmmse.elapsed_time; cvgce_iteration += ngs_lmmse.iSolve.cvgce_iteration; @ The LMMMSE NGS wavefront estimate is subtracted from the science wavefront: <>= //src.wavefront.reset(phase_screen); src.wavefront.add_phase(-1,ngs_lmmse.d__phase_est); if (k_SAMPLE==PLOTLY_LIM) { SET_PLOTLY_NAME(plotly_name,plotly_dir,"phases/LMMSE NGS AO"); src.wavefront.show_phase(plotly_name); } <>= float ngs_wfe_rms_lmmse=0.; <>= ngs_wfe_rms_lmmse += S.var(src.wavefront.phase, &pupil_mask, NP2); //ngs_lmmse.toFile("phaseEstNgsItp.bin"); <>= ngs_lmmse.cleanup(); @ and the residual wavefront corresponding image is computed. <>= imager_ngsao_lmmse.propagate(&src); //imager.frame2file("ngsLmmseFrame.bin"); if (k_SAMPLE==PLOTLY_LIM) { SET_PLOTLY_NAME(plotly_name,plotly_dir,"frames/LMMSE NGS AO"); imager_ngsao_lmmse.show_frame(plotly_name,&imager); } @ wide field imaging: <>= for (k_FOV_SRC=0;k_FOV_SRC>= science_wf_rms = 1E9*sqrtf(science_wf_rms/N_SAMPLE); ngs_wfe_rms_lmmse = 1E9*sqrtf(ngs_wfe_rms_lmmse/N_SAMPLE); elapsed_time /= N_SAMPLE; cvgce_iteration /= N_SAMPLE; printf("------------------------------\n"); printf("___ TURBULENCE WAVEFRONT ___\n"); printf("\n NGS WF RMS: %7.2fnm\n", science_wf_rms); printf("\n___ ON-AXIS WAVEFRONT ESTIMATE FROM NGS ___\n"); printf("\n NGS MMSE WFE RMS: %8.3fnm in %.2fms with %d iterations\n", ngs_wfe_rms_lmmse,elapsed_time,cvgce_iteration); printf("------------------------------\n");