/***************************************************************** * Subroutine to correct for phase-cal * * * * version 1, August 1, 1991 - cmn * * modified for station-based phase cal treatment - rjc 93.5.6 * * added code for ad hoc phase corrections rjc 94.9.6 * * inverted sign for ap_by_ap pcal for remote stn rjc 2008.10.31 * * save pcal phasor, rather than applying it rjc 2011.12.21 * * fixed multitone phase sign bug rjc 2013.5.9 * * fixed index offset bug for ad hoc code rjc 2018.4.12 * *****************************************************************/ #include #include #include "hops_complex.h" #include "mk4_data.h" #include "param_struct.h" #include "pass_struct.h" void rotate_pcal(struct type_pass *pass) { int ap, fr, i, ip; int stnpol[2][4] = {0, 1, 0, 1, 0, 1, 1, 0}; // [stn][pol] = 0:L, 1:R hops_complex rrpcal[2]; double theta, phaze,thyme,thyme_n,zeta, deltaf, eta[4]; struct data_corel *cor_data; struct interp_sdata *rrisd[2]; extern struct type_status status; extern struct type_param param; // function prototype double diff_file_phase (struct type_pass *, char, double); /* This subroutine rotates to correct data for phasecal differences. If pcal is used each AP, it adjusts so that all APs have the same average phase_cal phase. */ for (fr = 0; fr < pass->nfreq; fr++) { // calculate pc_delay-induced phase differences deltaf = 2e6 * M_PI * (pass->pass_data[fr].frequency - param.ref_freq); eta[0] = (pass->control.pc_delay_l.rem - pass->control.pc_delay_l.ref) * deltaf; eta[1] = (pass->control.pc_delay_r.rem - pass->control.pc_delay_r.ref) * deltaf; eta[2] = (pass->control.pc_delay_r.rem - pass->control.pc_delay_l.ref) * deltaf; eta[3] = (pass->control.pc_delay_l.rem - pass->control.pc_delay_r.ref) * deltaf; for (ap = pass->ap_off; ap < pass->ap_off + pass->num_ap; ap++) { if (param.ah_phase == SINEWAVE) /* evaluate ad hoc phase model */ { /* compute phase at center of AP */ phaze = ((ap + 0.5) * param.acc_period + param.start - param.ah_tref) / param.ah_period * 2.0 * M_PI; zeta = param.ah_amp * sin (phaze); } else if (param.ah_phase == POLYNOMIAL) { zeta = 0.0; thyme = (ap + 0.5) * param.acc_period + param.start - param.ah_tref; thyme_n = 1.0; for (i=0; i<6; i++) { zeta += param.ah_poly[i] * thyme_n; thyme_n *= thyme; } } // in adhoc file mode, find difference phase (f,t) else if (param.ah_phase == PHYLE) { thyme = ((ap + 0.5) * param.acc_period + param.start) / 8.64e4; zeta = diff_file_phase (pass, pass->pass_data[fr].freq_code, thyme); } else zeta = 0.0; /* no ad hoc phase model */ cor_data = &(pass->pass_data[fr].data[ap]); rrisd[0] = &(cor_data->ref_sdata); rrisd[1] = &(cor_data->rem_sdata); /* Any bit set implies data present */ if (cor_data->flag == 0) continue; // skip out to next ap for (ip=0; ip<4; ip++) // loop over four possible pol products { theta = 0.0; for (i=0; i<2; i++) // i index over ref:rem { switch (param.pc_mode[i]) { case NORMAL: case MANUAL: // apply constant pcal to whole scan rrpcal[i] = exp_complex (cmplx_unit_I * status.pc_phase[fr][i][stnpol[i][ip]]); break; case AP_BY_AP: // form difference with correct pol rrpcal[i] = (stnpol[i][ip]) ? rrisd[i]->phasecal_rcp[pass->pci[i][fr]]: rrisd[i]->phasecal_lcp[pass->pci[i][fr]]; rrpcal[i] = conjugate (rrpcal[i]); break; case MULTITONE: rrpcal[i] = rrisd[i]->mt_pcal[stnpol[i][ip]]; break; } theta += (2*i-1) * arg_complex (rrpcal[i]); } // Zero pcal ampl => missing pcal data // so don't rotate if (abs_complex (rrpcal[0]) + abs_complex (rrpcal[1]) == 0.0) theta = 0.0; // save resulting phasor in time-freq array cor_data->pc_phasor[ip] = exp_complex (cmplx_unit_I * (theta - zeta + eta[ip])); } } } }