/** Save NGS WFS and other information for later use in MAOS simulations.*/ void skysim_save(const SIM_S *simu, const ASTER_S *aster, const double *ipres, int selaster, int seldtrat, int isky){ const PARMS_S* parms=simu->parms; const int nwvl=parms->maos.nwvl; char path[PATH_MAX]; snprintf(path,PATH_MAX,"Res%d_%d_maos/sky%d",simu->seed_maos,parms->skyc.seed,isky); mymkdir("%s",path); for(int iwfs=0; iwfs<aster[selaster].nwfs; iwfs++){ dcell *sepsf=dcelldup(aster[selaster].wfs[iwfs].pistat->psf); for(int ic=0; ic<sepsf->nx*sepsf->ny; ic++){ dfftshift(sepsf->p[ic]);/*put peak in center. required by MAOS. */ } writebin(sepsf, "%s/pistat_wfs%d",path,iwfs+6); dcellfree(sepsf); writebin(aster->wfs[iwfs].pistat->sanea->p[seldtrat], "%s/nea_tot_wfs%d",path,iwfs+6); writebin(aster[selaster].wfs[iwfs].pistat->sanea->p[seldtrat], "%s/nea_wfs%d",path,iwfs+6); writebin(aster[selaster].wfs[iwfs].pistat->sanea, "%s/neafull_wfs%d",path,iwfs+6); } writebin(aster[selaster].gain->p[seldtrat], "%s/gain",path); writebin(simu->mres->p[isky], "%s/mres",path); writebin(simu->psd_tt,"%s/psd_tt",path); writebin(simu->psd_ps,"%s/psd_ps",path); char fnconf[PATH_MAX]; snprintf(fnconf,PATH_MAX,"%s/base.conf",path); FILE *fp=fopen(fnconf,"w"); fprintf(fp,"sim.seeds=[%d]\n",simu->seed_maos); fprintf(fp,"sim.end=%d\n", parms->maos.nstep); fprintf(fp,"sim.dt=%g\n", parms->maos.dt); fprintf(fp,"sim.zadeg=%g\n", parms->maos.zadeg); fprintf(fp,"sim.mffocus=%d\n", parms->maos.mffocus); fprintf(fp,"sim.ahstfocus=%d\n", parms->maos.ahstfocus); fprintf(fp,"tomo.ahst_wt=3\n"); fprintf(fp,"sim.servotype_lo=2\n");/*type II */ fprintf(fp,"sim.eplo='gain.bin'\n"); fprintf(fp,"powfs0_llt.fnrange='%s'\n", parms->maos.fnrange); fprintf(fp,"atm.r0z=%.4f\n", parms->maos.r0z); fprintf(fp,"atm.size=[128 128]\n"); if(parms->maos.wddeg){ fprintf(fp, "atm.wddeg=["); for(int ips=0; ips<parms->maos.nwddeg; ips++){ fprintf(fp, "%.2f ", parms->maos.wddeg[ips]); } fprintf(fp, "]\n"); } fprintf(fp,"wfs.thetax=[0 0 -33.287 -20.5725 20.5725 33.287"); for(int iwfs=0; iwfs<aster[selaster].nwfs; iwfs++){ fprintf(fp," %.4f", aster[selaster].wfs[iwfs].thetax*206265); } fprintf(fp,"]\n"); fprintf(fp,"wfs.thetay=[0 35 10.8156 -28.3156 -28.3156 10.8156"); for(int iwfs=0; iwfs<aster[selaster].nwfs; iwfs++){ fprintf(fp," %.4f", aster[selaster].wfs[iwfs].thetay*206265); } fprintf(fp,"]\n"); fprintf(fp,"wfs.siglev=[900 900 900 900 900 900"); for(int iwfs=0; iwfs<aster[selaster].nwfs; iwfs++){ fprintf(fp, " %.2f", aster[selaster].wfs[iwfs].siglevtot); } fprintf(fp,"]\n"); fprintf(fp,"wfs.wvlwts=[1 1 1 1 1 1"); for(int iwfs=0; iwfs<aster[selaster].nwfs; iwfs++){ for(int iwvl=0; iwvl<nwvl; iwvl++){ fprintf(fp," %.2f ", aster[selaster].wfs[iwfs].siglev->p[iwvl] /aster[selaster].wfs[iwfs].siglevtot); } } fprintf(fp,"]\n"); fprintf(fp,"wfs.powfs=[0 0 0 0 0 0"); for(int iwfs=0; iwfs<aster[selaster].nwfs; iwfs++){ fprintf(fp, " %d", aster[selaster].wfs[iwfs].ipowfs+1); } fprintf(fp,"]\n"); dmat* rnefs=parms->skyc.rnefs; double rne=IND(rnefs,seldtrat,0); double bkgrnd=aster[selaster].wfs[0].bkgrnd; if(parms->maos.npowfs==1){ fprintf(fp, "powfs.piinfile=[\"\" \"pistat\" ]\n"); fprintf(fp, "powfs.neareconfile=[\"\" \"nea_tot\"]\n"); fprintf(fp, "powfs.phyusenea=[0 1]\n"); fprintf(fp, "powfs.dtrat=[1 %d]\n", (int)parms->skyc.dtrats->p[seldtrat]); fprintf(fp, "powfs.bkgrnd=[0 %.2f]\n", bkgrnd); fprintf(fp, "powfs.rne=[3 %.2f]\n", rne); fprintf(fp, "powfs.phystep=[0 %ld]\n", 50+(long)parms->skyc.dtrats->p[seldtrat]*20); fprintf(fp, "powfs.noisy=[1 1 ]\n"); fprintf(fp, "powfs.pixtheta=[0.5/206265 %g/206265000]\n", parms->skyc.pixtheta[1]*206265000); fprintf(fp, "powfs.pixpsa=[6 %d]\n", parms->skyc.pixpsa[0]); fprintf(fp, "powfs.ncomp=[64 %d]\n", parms->maos.ncomp[0]); fprintf(fp, "powfs.nwvl=[1 %d]\n",nwvl); fprintf(fp, "powfs.wvl=[0.589e-6"); for(int ip=0; ip<1; ip++){ for(int iwvl=0; iwvl<nwvl; iwvl++){ fprintf(fp, " %.4g", parms->maos.wvl[iwvl]); } } fprintf(fp,"]\n"); }else if(parms->maos.npowfs==2){ fprintf(fp, "powfs.piinfile=[\"\" \"pistat\" \"pistat\"]\n"); fprintf(fp, "powfs.neareconfile=[\"\" \"nea_tot\" \"nea_tot\"]\n"); fprintf(fp, "powfs.phyusenea=[0 1 1]\n"); fprintf(fp, "powfs.dtrat=[1 %d %d]\n", (int)parms->skyc.dtrats->p[seldtrat], (int)parms->skyc.dtrats->p[seldtrat]); fprintf(fp, "powfs.bkgrnd=[0 %.2f %.2f]\n", bkgrnd, bkgrnd); fprintf(fp, "powfs.rne=[3 %.2f %.2f]\n", rne,rne); fprintf(fp, "powfs.phystep=[0 %ld %ld]\n", 50+(long)parms->skyc.dtrats->p[seldtrat]*20, 50+(long)parms->skyc.dtrats->p[seldtrat]*20); fprintf(fp, "powfs.noisy=[1 1 1]\n"); fprintf(fp, "powfs.pixtheta=[0.5/206265 %g/206265000 %g/206265000]\n", parms->skyc.pixtheta[0]*206265000, parms->skyc.pixtheta[1]*206265000); fprintf(fp, "powfs.pixpsa=[6 %d %d]\n", parms->skyc.pixpsa[0], parms->skyc.pixpsa[1]); fprintf(fp, "powfs.ncomp=[64 %d %d]\n", parms->maos.ncomp[0], parms->maos.ncomp[1]); fprintf(fp, "powfs.nwvl=[1 %d %d]\n",nwvl,nwvl); fprintf(fp, "powfs.wvl=[0.589e-6"); for(int ip=0; ip<2; ip++){ for(int iwvl=0; iwvl<nwvl; iwvl++){ fprintf(fp, " %.4g", parms->maos.wvl[iwvl]); } } fprintf(fp,"]\n"); fprintf(fp, "powfs.wvlwts=[]\n"); }else{ error("Fill this out please\n"); } fclose(fp); snprintf(fnconf,PATH_MAX,"%s/skyres.txt",path); fp=fopen(fnconf,"w"); fprintf(fp, "TotAll\tNGS\tTT\n"); fprintf(fp, "%g\t%g\t%g\n", sqrt(ipres[0])*1e9, sqrt(ipres[1])*1e9, sqrt(ipres[2])*1e9); fclose(fp); }
/** Update DM command for next cycle using info from last cycle (two cycle delay) in closed loop mode */ static void filter_cl(SIM_T *simu){ /* 2009-11-02: Moved to the end of isim loop to update for next step. only need to cache a single dmerrlast now. 2009-12-23: Updated low fs to do lead filter/type II 2010-01-07: Create an option to merge the last integrator in the hi/lo loop to simulation the actual block diagram. removed dmreal_hi, Mreal_lo; 2010-01-08: Changed the filtering scheme by computing dm command for next cycle instead of maintianing last step error information. 2010-01-13: Implemented apdm. a(n)=a(n-1)+ep*e(n-2) or a(n)=0.5*(a(n-1)+a(n-2))+ep*e(n-2); */ const PARMS_T *parms=simu->parms; RECON_T *recon=simu->recon; assert(parms->sim.closeloop); /*copy dm computed in last cycle. This is used in next cycle (already after perfevl) */ const SIM_CFG_T *simcfg=&(parms->sim); const int isim=simu->isim; {/*Auto adjusting epdm for testing different epdm*/ static int epdm_is_auto=0; if(simcfg->epdm->p[0]<0){ epdm_is_auto=1; simcfg->epdm->p[0]=0.5; } if(epdm_is_auto){ if((isim*10)<parms->sim.end){//initial steps simcfg->epdm->p[0]=0.5; }else if((isim*10)%parms->sim.end==0){ simcfg->epdm->p[0]=(double)isim/(double)parms->sim.end; info("epdm is set to %.1f at step %d\n", simcfg->epdm->p[0], isim); } } } /*Do the servo filtering. First simulate a drop frame*/ int drop=0; if(simu->dmerr && parms->sim.dtrat_skip){ if(parms->sim.dtrat_skip>0){ if((isim+1)%parms->sim.dtrat_skip==0){//evenly drop=1; } }else if(parms->sim.dtrat_skip<0){//use random draws double tmp=randu(simu->misc_rand); if(tmp*(-parms->sim.dtrat_skip)<1.){ drop=1; } } } dcell *dmerr=0; if(drop){ warning("Drop a frame at step %d\n", isim); }else if(simu->dmerr){ dmerr=simu->dmerr; } //always run servo_filter even if dmerr is NULL. int hiout=servo_filter(simu->dmint, dmerr); if(parms->recon.split){ /*Low order in split tomography only. fused integrator*/ if(servo_filter(simu->Mint_lo, simu->Merr_lo) && parms->sim.fuseint){ /*accumulate to the main integrator.*/ addlow2dm(&simu->dmint->mint->p[0], simu, simu->Mint_lo->mpreint, 1); } } /*The following are moved from the beginning to the end because the gradients are now from last step.*/ dcellcp(&simu->dmcmd0,simu->dmint->mint->p[0]); if(!parms->sim.fuseint){ addlow2dm(&simu->dmcmd0,simu,simu->Mint_lo->mint->p[0], 1); } for(int ipowfs=0; ipowfs<parms->npowfs; ipowfs++){ //Record dmpsol for this time step for each powfs before updating it (z^-1). //Do not reference the data, even for dtrat==1 if(!parms->powfs[ipowfs].psol || !parms->powfs[ipowfs].dtrat) continue; double alpha=(isim % parms->powfs[ipowfs].dtrat == 0)?0:1; dcelladd(&simu->wfspsol->p[ipowfs], alpha, simu->dmpsol, 1./parms->powfs[ipowfs].dtrat); } dcellcp(&simu->dmpsol, simu->dmcmd0); if(parms->recon.modal){ dcellzero(simu->dmcmd); dcellmm(&simu->dmcmd, simu->recon->amod, simu->dmcmd0, "nn", 1); //convert DM command from modal to zonal spae }else if(simu->recon->actinterp && !parms->recon.psol){ //Extrapolate to edge actuators dcellzero(simu->dmcmd); dcellmm(&simu->dmcmd, simu->recon->actinterp, simu->dmcmd0, "nn", 1); }else{ dcellcp(&simu->dmcmd, simu->dmcmd0); } //The DM commands are always on zonal modes from this moment if(simu->ttmreal){ ttsplit_do(recon, simu->dmcmd, simu->ttmreal, parms->sim.lpttm); } if(parms->sim.focus2tel && hiout){ dcellcp(&simu->telfocusreal, simu->telfocusint); dcellmm(&simu->telfocusint, recon->RFdm, simu->dmcmd, "nn", parms->sim.epfocus2tel); } if(recon->dither_m){ //Change phase in calc_dither_amp if phase of dithering is changed //this is for step isim+1 double anglei=((isim+1)/recon->dither_dtrat)*(2*M_PI/recon->dither_npoint); dcelladd(&simu->dmcmd, 1, recon->dither_m, sin(anglei)); } if(!parms->dbg.ncpa_preload && recon->dm_ncpa){ info_once("Add NCPA after integrator\n"); dcelladd(&simu->dmcmd, 1, recon->dm_ncpa, 1); } if(parms->sim.dmclip || parms->sim.dmclipia || recon->actstuck){ dcell *tmp=dcelldup(simu->dmcmd); if(recon->actstuck){//zero stuck actuators act_stuck_cmd(recon->aloc, simu->dmerr, recon->actstuck); } clipdm(simu, simu->dmcmd); dcelladd(&tmp, 1, simu->dmcmd, -1); //find what is clipped dcelladd(&simu->dmint->mint->p[0], 1, tmp, -1);//remove from integrator (anti wind up) dcelladd(&simu->dmpsol, 1, tmp, -1);//also feed to PSOL (is this really necessary?) dcellfree(tmp); } /*This is after the integrator output and clipping*/ if(simu->dmhist){ for(int idm=0; idm<parms->ndm; idm++){ if(simu->dmhist->p[idm]){ dhistfill(&simu->dmhist->p[idm], simu->dmcmd->p[idm],0, parms->dm[idm].histbin, parms->dm[idm].histn); } } } /*hysteresis. */ if(simu->hyst){ hyst_dcell(simu->hyst, simu->dmreal, simu->dmcmd); } if(recon->moao && !parms->gpu.moao){ warning_once("moao filter implemented with LPF\n"); if(simu->dm_wfs){ const int nwfs=parms->nwfs; for(int iwfs=0; iwfs<nwfs; iwfs++){ int ipowfs=parms->wfs[iwfs].powfs; int imoao=parms->powfs[ipowfs].moao; if(imoao<0) continue; double g=parms->moao[imoao].gdm; dadd(&simu->dm_wfs->p[iwfs], 1-g, simu->dm_wfs->p[iwfs+nwfs], g); } } if(simu->dm_evl){ const int nevl=parms->evl.nevl; int imoao=parms->evl.moao; double g=parms->moao[imoao].gdm; for(int ievl=0; ievl<nevl; ievl++){ dadd(&simu->dm_evl->p[ievl], 1-g, simu->dm_evl->p[ievl+nevl], g); } } } if(simu->fsmint){ /*fsmerr is from gradients from this time step. so copy before update for correct delay*/ dcellcp(&simu->fsmreal, simu->fsmint->mint->p[0]); servo_filter(simu->fsmint, simu->fsmerr); /*Inject dithering command, for step isim+1*/ for(int iwfs=0; iwfs<parms->nwfs; iwfs++){ const int ipowfs=parms->wfs[iwfs].powfs; if(parms->powfs[ipowfs].dither==1){//T/T dithering. //adjust delay due to propagation, and computation delay. const int adjust=parms->sim.alfsm+1-parms->powfs[ipowfs].dtrat; //Use isim+1 because the command is for next time step. //minus adjust for delay double anglei=(2*M_PI/parms->powfs[ipowfs].dither_npoint); double angle=((isim+1-adjust)/parms->powfs[ipowfs].dtrat)*anglei; simu->fsmreal->p[iwfs]->p[0]-=parms->powfs[ipowfs].dither_amp*cos(angle); simu->fsmreal->p[iwfs]->p[1]-=parms->powfs[ipowfs].dither_amp*sin(angle); } } } }