36 #include "visir_spc_optmod.h"
64 enum visir_spc_mode_ {
114 typedef enum visir_spc_mode_ visir_spc_mode;
143 visir_spc_resol resolution;
162 static double visir_spc_optmod_krs5(
double);
186 int visir_spc_optmod_init(visir_spc_resol resol,
double wlen,
193 const double rad_per_deg = atan(1)/45;
195 visir_spc_mode mode = VISIR_SPC_M_ERR;
201 if (
self == NULL)
return -1;
207 case VISIR_SPC_R_LRP:
209 mode = VISIR_SPC_M_LRP;
210 wlen = VISIR_SPC_LRP_CWLEN;
216 if ( 7.5 <= wlen && wlen <= 10.2) mode = VISIR_SPC_M_LSWN;
217 else if (10.2 < wlen && wlen <= 14.5) mode = VISIR_SPC_M_LLWN;
218 else if (15.0 <= wlen && wlen <= 20.4) mode = VISIR_SPC_M_LSWQ;
219 else if (20.4 < wlen && wlen <= 28.0) mode = VISIR_SPC_M_LLWQ;
225 if ( 7.5 <= wlen && wlen <= 10.2) mode = VISIR_SPC_M_MSWN;
226 else if (10.2 < wlen && wlen <= 14.0) mode = VISIR_SPC_M_MLWN;
227 else if (15.0 <= wlen && wlen <= 20.4) mode = VISIR_SPC_M_MSWQ;
228 else if (20.4 < wlen && wlen <= 28.0) mode = VISIR_SPC_M_MLWQ;
232 case VISIR_SPC_R_GHR:
234 if ( 7.6 <= wlen && wlen <= 7.8 ) mode = VISIR_SPC_M_GHR01;
235 else if ( 7.8 < wlen && wlen <= 8.03) mode = VISIR_SPC_M_GHR02;
236 else if ( 8.03 < wlen && wlen <= 8.26) mode = VISIR_SPC_M_GHR03;
237 else if ( 8.26 < wlen && wlen <= 8.52) mode = VISIR_SPC_M_GHR04;
238 else if ( 8.52 < wlen && wlen <= 8.78) mode = VISIR_SPC_M_GHR05;
239 else if ( 8.78 < wlen && wlen <= 9.07) mode = VISIR_SPC_M_GHR06;
240 else if ( 9.07 < wlen && wlen <= 9.36) mode = VISIR_SPC_M_GHR07;
241 else if ( 9.36 < wlen && wlen <= 9.69) mode = VISIR_SPC_M_GHR08;
242 else if ( 9.69 < wlen && wlen <= 10.03) mode = VISIR_SPC_M_GHR09;
243 else if (10.03 < wlen && wlen <= 10.20) mode = VISIR_SPC_M_GHR10;
244 else if (10.2 < wlen && wlen <= 10.41) mode = VISIR_SPC_M_GHR11;
245 else if (10.41 < wlen && wlen <= 10.80) mode = VISIR_SPC_M_GHR12;
246 else if (10.80 < wlen && wlen <= 11.24) mode = VISIR_SPC_M_GHR13;
247 else if (11.24 < wlen && wlen <= 11.70) mode = VISIR_SPC_M_GHR14;
248 else if (11.70 < wlen && wlen <= 12.21) mode = VISIR_SPC_M_GHR15;
249 else if (12.21 < wlen && wlen <= 12.76) mode = VISIR_SPC_M_GHR16;
250 else if (12.76 < wlen && wlen <= 13.37) mode = VISIR_SPC_M_GHR17;
251 else if (13.37 < wlen && wlen <= 14.04) mode = VISIR_SPC_M_GHR18;
252 else if (14.04 < wlen && wlen <= 14.77) mode = VISIR_SPC_M_GHR19;
253 else if (15.60 < wlen && wlen <= 16.49) mode = VISIR_SPC_M_GHR20;
254 else if (16.49 < wlen && wlen <= 17.55) mode = VISIR_SPC_M_GHR21;
255 else if (17.55 < wlen && wlen <= 18.67) mode = VISIR_SPC_M_GHR22;
256 else if (18.67 < wlen && wlen <= 20.06) mode = VISIR_SPC_M_GHR23;
257 else if (20.06 < wlen && wlen <= 21.49) mode = VISIR_SPC_M_GHR24;
258 else if (21.49 < wlen && wlen <= 23.40) mode = VISIR_SPC_M_GHR25;
259 else if (23.40 < wlen && wlen <= 25.32) mode = VISIR_SPC_M_GHR26;
260 else if (25.32 < wlen && wlen <= 28.08) mode = VISIR_SPC_M_GHR27;
265 if ( 7.97 <= wlen && wlen <= 8.27) mode = VISIR_SPC_M_HR01;
266 else if ( 8.83 <= wlen && wlen <= 9.05) mode = VISIR_SPC_M_HR02;
267 else if ( 9.52 <= wlen && wlen <= 9.72) mode = VISIR_SPC_M_HR03;
269 else if (11.85 <= wlen && wlen < 12.19) mode = VISIR_SPC_M_HR04;
270 else if (12.19 <= wlen && wlen <= 12.37) mode = VISIR_SPC_M_HR05;
271 else if (12.37 < wlen && wlen <= 12.71) mode = VISIR_SPC_M_HR06;
272 else if (12.71 < wlen && wlen <= 12.91) mode = VISIR_SPC_M_HR07;
273 else if (16.80 <= wlen && wlen <= 17.20) mode = VISIR_SPC_M_HR08;
274 else if (18.32 <= wlen && wlen <= 18.67) mode = VISIR_SPC_M_HR09;
275 else if (18.67 < wlen && wlen <= 19.18) mode = VISIR_SPC_M_HR10;
282 if (mode == VISIR_SPC_M_ERR)
return -2;
284 self->resolution = resol;
296 case VISIR_SPC_R_LRP:
302 self->angle_a = 6.708;
303 self->angle_bm = 1.291;
304 self->angle_b0 = 0.586;
305 self->angle_b1 = 2.0;
306 self->dcolbeam = 53000;
311 case VISIR_SPC_M_LSWN:
317 case VISIR_SPC_M_LLWN:
323 case VISIR_SPC_M_LSWQ:
329 case VISIR_SPC_M_LLWQ:
341 self->angle_a = 34.208;
342 self->angle_bm = 28.791;
343 self->angle_b0 = 28.086;
344 self->angle_b1 = 29.500;
345 self->dcolbeam = 53000;
350 case VISIR_SPC_M_MSWN:
356 case VISIR_SPC_M_MLWN:
362 case VISIR_SPC_M_MSWQ:
368 case VISIR_SPC_M_MLWQ:
378 case VISIR_SPC_R_GHR:
382 self->dcolbeam = 125000;
386 case VISIR_SPC_M_GHR01:
397 case VISIR_SPC_M_GHR02:
409 case VISIR_SPC_M_GHR03:
420 case VISIR_SPC_M_GHR04:
432 case VISIR_SPC_M_GHR05:
443 case VISIR_SPC_M_GHR06:
455 case VISIR_SPC_M_GHR07:
466 case VISIR_SPC_M_GHR08:
478 case VISIR_SPC_M_GHR09:
489 case VISIR_SPC_M_GHR10:
501 case VISIR_SPC_M_GHR11:
513 case VISIR_SPC_M_GHR12:
524 case VISIR_SPC_M_GHR13:
536 case VISIR_SPC_M_GHR14:
547 case VISIR_SPC_M_GHR15:
559 case VISIR_SPC_M_GHR16:
570 case VISIR_SPC_M_GHR17:
582 case VISIR_SPC_M_GHR18:
593 case VISIR_SPC_M_GHR19:
605 case VISIR_SPC_M_GHR20:
617 case VISIR_SPC_M_GHR21:
628 case VISIR_SPC_M_GHR22:
640 case VISIR_SPC_M_GHR23:
651 case VISIR_SPC_M_GHR24:
663 case VISIR_SPC_M_GHR25:
674 case VISIR_SPC_M_GHR26:
686 case VISIR_SPC_M_GHR27:
699 if (self->side_is_A) {
701 self->angle_a = 62.1299;
702 self->angle_bm = 64.8519;
703 self->angle_b0 = 64.5393;
704 self->angle_b1 = 65.1641;
708 self->angle_a = 64.8701;
709 self->angle_bm = 62.1483;
710 self->angle_b0 = 62.4609;
711 self->angle_b1 = 61.8361;
713 self->w *= rad_per_deg;
723 self->dcolbeam = 125000;
727 case VISIR_SPC_M_HR01:
732 case VISIR_SPC_M_HR02:
738 case VISIR_SPC_M_HR03:
744 case VISIR_SPC_M_HR04:
750 case VISIR_SPC_M_HR05:
755 case VISIR_SPC_M_HR06:
760 case VISIR_SPC_M_HR07:
766 case VISIR_SPC_M_HR08:
771 case VISIR_SPC_M_HR09:
777 case VISIR_SPC_M_HR10:
784 if (self->side_is_A) {
787 self->angle_a = 62.1299;
788 self->angle_bm = 64.8519;
789 self->angle_b0 = 64.5393;
790 self->angle_b1 = 65.1641;
794 self->angle_a = 64.8701;
795 self->angle_bm = 62.1483;
796 self->angle_b0 = 62.4609;
797 self->angle_b1 = 61.8361;
804 if (is_aqu && (resol == VISIR_SPC_R_HR || resol == VISIR_SPC_R_GHR)) {
807 self->factor *= 0.127 / 0.0757;
808 self->ld /= 0.127 / 0.0757;
812 if (self->angle_b0 < self->angle_bm) {
813 self->angle_b0 =
self->angle_bm - (
self->angle_bm -
self->angle_b0) * 2.377;
814 self->angle_b1 =
self->angle_bm + (
self->angle_b1 -
self->angle_bm) * 2.377;
817 self->angle_b0 =
self->angle_bm + (
self->angle_b0 -
self->angle_bm) * 2.377;
818 self->angle_b1 =
self->angle_bm - (
self->angle_bm -
self->angle_b1) * 2.377;
823 if (resol != VISIR_SPC_R_LRP) {
824 self->angle_a *= rad_per_deg;
825 self->angle_b0 *= rad_per_deg;
826 self->angle_bm *= rad_per_deg;
827 self->angle_b1 *= rad_per_deg;
831 self->dcolbeam *= 1e-6;
833 assert( self->m > 0);
835 visir_spc_optmod_scan_angle(
self);
837 self->sinus_sum = sin(self->angle_a + self->angle_scan)
838 + sin(self->angle_bm + self->angle_scan);
861 double visir_spc_optmod_wlen(
const visir_optmod * pins,
double * pwl0,
867 if (
self == NULL)
return -1;
869 if (self->mode == VISIR_SPC_M_LRP) {
870 if (pwl0) *pwl0 = VISIR_SPC_LRP_WLEN0;
871 if (pwl1) *pwl1 = VISIR_SPC_LRP_WLEN1;
872 return VISIR_SPC_LRP_CWLEN;
876 if (pwl0) *pwl0 =
self->d/
self->m*( sin(self->angle_a + self->angle_scan)
877 + sin(self->angle_b0 + self->angle_scan));
880 if (pwl1) *pwl1 =
self->d/
self->m*( sin(self->angle_a + self->angle_scan)
881 + sin(self->angle_b1 + self->angle_scan));
884 return self->d /
self->m *
self->sinus_sum;
908 double visir_spc_optmod_cross_dispersion(
const visir_optmod * pins,
double wlen)
915 if (
self == NULL)
return -1;
917 if (self->resolution != VISIR_SPC_R_GHR)
return -2;
918 if (wlen <= 0)
return -3;
920 assert( self->gg != 0 );
922 rf_index = visir_spc_optmod_krs5(wlen);
924 if (rf_index < 1)
return -8;
926 sinbeta = sin(self->w) * rf_index - wlen /
self->gg;
929 if (sinbeta < -1)
return -9;
930 if (sinbeta > 1)
return -10;
932 return self->offset +
self->factor * tan(asin(sinbeta) - self->w);
961 double visir_spc_optmod_echelle(
const visir_optmod * pins,
double wlen,
968 if (
self == NULL)
return -1;
969 if (self->resolution != VISIR_SPC_R_GHR)
return -2;
970 if (wlen <= 0)
return -3;
971 if (ioffset < -4)
return -4;
972 if (ioffset > 4)
return -5;
974 order = ioffset +
self->m;
977 if (order < 1)
return -6;
978 if (order > 18)
return -7;
980 return wlen *
self->m / (double) order;
1000 int visir_spc_optmod_side_is_A(
const visir_optmod * pins)
1004 if (
self == NULL)
return -1;
1006 if (self->resolution != VISIR_SPC_R_GHR &&
1007 self->resolution != VISIR_SPC_R_HR)
return -2;
1009 return self->side_is_A;
1029 int visir_spc_optmod_get_echelle_order(
const visir_optmod * pins)
1033 if (
self == NULL)
return -1;
1035 if (self->resolution != VISIR_SPC_R_GHR &&
1036 self->resolution != VISIR_SPC_R_HR)
return -2;
1056 double visir_spc_optmod_resolution(
const visir_optmod * pins)
1060 if (
self == NULL)
return -1;
1062 return self->mode == VISIR_SPC_M_LRP
1063 ? VISIR_SPC_LRP_RESOL
1064 :
self->dcolbeam *
self->sinus_sum
1065 / (2.0 *
self->wlen * cos(self->angle_a + self->angle_scan));
1083 double visir_spc_optmod_dispersion(
const visir_optmod * pins)
1087 if (
self == NULL)
return -1;
1089 return self->mode == VISIR_SPC_M_LRP
1090 ? VISIR_SPC_LRP_RESOL_DISP
1091 :
self->ld *
self->sinus_sum
1092 / (
self->wlen * cos(self->angle_bm + self->angle_scan));
1105 static double visir_spc_optmod_krs5(
double wlen) {
1107 const double a0 = 5.96032159;
1108 const double a1 = -5.36135205e-4;
1109 const double a2 = 1.77047634;
1110 const double a3 = -2.79310980e1;
1111 const double a4 = -1.28684883;
1112 const double a5 = -4.34541795e-2;
1124 n2 = a0 + a1 * wlen + (((a5/wlen + a4)/wlen + a3)/ wlen + a2)/wlen;
1127 return n2 > 1 ? sqrt(n2) : -1;
1144 const double mld =
self->m *
self->wlen /
self->d;
1145 const double sab = sin(self->angle_bm) + sin(self->angle_a);
1146 const double cab = cos(self->angle_bm) + cos(self->angle_a);
1147 const double A = sab * sab + cab * cab;
1151 const double C = mld * mld - sab * sab;
1153 double D = A - mld * mld;
1157 D = D > 0 ? sqrt(D) : 0;
1161 u1 = (cab * mld + D) / A;
1171 self->angle_scan = asin(u2);