visir_spc_optmod.c

00001 /* $Id: visir_spc_optmod.c,v 1.22 2007/03/12 09:58:51 llundin Exp $
00002  *
00003  * This file is part of the VISIR Pipeline
00004  * Copyright (C) 2002,2003 European Southern Observatory
00005  *
00006  * This program is free software; you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation; either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02111-1307  USA
00019  */
00020 
00021 /*
00022  * $Author: llundin $
00023  * $Date: 2007/03/12 09:58:51 $
00024  * $Revision: 1.22 $
00025  * $Name: HEAD $
00026  */
00027 
00028 #ifdef HAVE_CONFIG_H
00029 #include <config.h>
00030 #endif
00031 
00032 /*-----------------------------------------------------------------------------
00033                                    Includes
00034  -----------------------------------------------------------------------------*/
00035 
00036 #include <stddef.h>
00037 #include <math.h>
00038 #include <assert.h>
00039 
00040 #include "visir_spc_optmod.h"
00041 
00042 /*----------------------------------------------------------------------------*/
00057 /*----------------------------------------------------------------------------*/
00058 
00059 /*-----------------------------------------------------------------------------
00060                                    Type definition
00061  -----------------------------------------------------------------------------*/
00062 
00063 enum visir_spc_mode_ {
00064     VISIR_SPC_M_ERR = 0,
00065     VISIR_SPC_M_LSWN,
00066     VISIR_SPC_M_LLWN,
00067     VISIR_SPC_M_LSWQ,
00068     VISIR_SPC_M_LLWQ,
00069     VISIR_SPC_M_MSWN,
00070     VISIR_SPC_M_MLWN,
00071     VISIR_SPC_M_MSWQ,
00072     VISIR_SPC_M_MLWQ,
00073     VISIR_SPC_M_GHR01,
00074     VISIR_SPC_M_GHR02,
00075     VISIR_SPC_M_GHR03,
00076     VISIR_SPC_M_GHR04,
00077     VISIR_SPC_M_GHR05,
00078     VISIR_SPC_M_GHR06,
00079     VISIR_SPC_M_GHR07,
00080     VISIR_SPC_M_GHR08,
00081     VISIR_SPC_M_GHR09,
00082     VISIR_SPC_M_GHR10,
00083     VISIR_SPC_M_GHR11,
00084     VISIR_SPC_M_GHR12,
00085     VISIR_SPC_M_GHR13,
00086     VISIR_SPC_M_GHR14,
00087     VISIR_SPC_M_GHR15,
00088     VISIR_SPC_M_GHR16,
00089     VISIR_SPC_M_GHR17,
00090     VISIR_SPC_M_GHR18,
00091     VISIR_SPC_M_GHR19,
00092     VISIR_SPC_M_GHR20,
00093     VISIR_SPC_M_GHR21,
00094     VISIR_SPC_M_GHR22,
00095     VISIR_SPC_M_GHR23,
00096     VISIR_SPC_M_GHR24,
00097     VISIR_SPC_M_GHR25,
00098     VISIR_SPC_M_GHR26,
00099     VISIR_SPC_M_GHR27,
00100     VISIR_SPC_M_HR01,
00101     VISIR_SPC_M_HR02,
00102     VISIR_SPC_M_HR03,
00103     VISIR_SPC_M_HR04,
00104     VISIR_SPC_M_HR05,
00105     VISIR_SPC_M_HR06,
00106     VISIR_SPC_M_HR07,
00107     VISIR_SPC_M_HR08,
00108     VISIR_SPC_M_HR09,
00109     VISIR_SPC_M_HR10
00110 };
00111 
00112 typedef enum visir_spc_mode_ visir_spc_mode;
00113 
00114 struct visir_optmod_private_ {
00115     /* The Central Wavelength of the settings */
00116     double wlen;
00117 
00118     /* Angles are in radians */
00119     double angle_a;    /* Angle in 1st term */
00120     double angle_b0;   /* Angle in 2nd term, center of 1st pixel */
00121     double angle_bm;   /* Angle in 2nd term, center of spectral range */
00122     double angle_b1;   /* Angle in 2nd term, center of last pixel */
00123 
00124     double angle_scan; /* Scan-angle */
00125     double sinus_sum;  /* sin(a + scan-angle) + sin(b + scan-angle) */
00126 
00127     /* The unit of d has to be equal to that of the wavelength */
00128     double d;         /* Echelle groove spacing @30K [m] */
00129 
00130     /* These settings are only defined in High Resolution Grism mode, i.e. when
00131        mode == VISIR_SPC_R_GHR */
00132     double gg;        /* grism groove spacing @ 30K [m] */
00133     double w;         /* grism wedge [radians] */
00134     double offset;    /* Parameter for grism cross-dispersion */
00135     double factor;    /* Parameter for grism cross-dispersion */
00136 
00137     double dcolbeam;  /* Diameter of collimated beam */
00138     double ld;        /* The (unit-less) Linear Dispersion factor */
00139 
00140     /* The spectroscopy resolution corresponding to the settings */
00141     visir_spc_resol resolution;
00142 
00143     /* The spectroscopy mode corresponding to the settings */
00144     visir_spc_mode mode;
00145 
00146     int    m;         /* Echelle order (1, 2, ..., 18) */
00147 
00148     /* These settings are only defined in High Resolution, i.e. when
00149        mode == VISIR_SPC_R_GHR || mode == VISIR_SPC_R_HR */
00150     int side_is_A;    /* 1 if side is 'A', 0 if side is 'B' */
00151 
00152 };
00153 
00154 typedef struct visir_optmod_private_ visir_optmod_private;
00155 
00156 /*-----------------------------------------------------------------------------
00157                             Functions prototypes
00158  -----------------------------------------------------------------------------*/
00159 
00160 static double visir_spc_optmod_krs5(double);
00161 static void visir_spc_optmod_scan_angle(visir_optmod_private *);
00162 
00165 /*-----------------------------------------------------------------------------
00166                             Function codes
00167  -----------------------------------------------------------------------------*/
00168 
00169 /*----------------------------------------------------------------------------*/
00182 /*----------------------------------------------------------------------------*/
00183 int visir_spc_optmod_init(visir_spc_resol resol, double wlen,
00184                           visir_optmod * pins)
00185 {
00186 
00187     visir_optmod_private * self = (visir_optmod_private*)pins;
00188 
00189     /* The angles are coded in degrees and then converted to radians */
00190     const double rad_per_deg = atan(1)/45;
00191 
00192     visir_spc_mode mode = VISIR_SPC_M_ERR;
00193 
00194 
00195     /* Ensure that the public struct has the proper size */
00196     assert( sizeof(visir_optmod_private) == sizeof(visir_optmod) );
00197 
00198     if (self == NULL) return -1;
00199 
00200     /* Switch on the resolution
00201        Constants here are coded in micron - convert to m */
00202     wlen *= 1e6;
00203     switch (resol) {
00204         case VISIR_SPC_R_LR:
00205           {
00206                  if ( 7.5 <= wlen && wlen <= 10.2) mode = VISIR_SPC_M_LSWN;
00207             else if (10.2 <  wlen && wlen <= 14.5) mode = VISIR_SPC_M_LLWN;
00208             else if (15.0 <= wlen && wlen <= 20.4) mode = VISIR_SPC_M_LSWQ;
00209             else if (20.4 <  wlen && wlen <= 28.0) mode = VISIR_SPC_M_LLWQ;
00210             break;
00211           }
00212 
00213         case VISIR_SPC_R_MR:
00214           {
00215                  if ( 7.5 <= wlen && wlen <= 10.2) mode = VISIR_SPC_M_MSWN;
00216             else if (10.2 <  wlen && wlen <= 14.0) mode = VISIR_SPC_M_MLWN;
00217             else if (15.0 <= wlen && wlen <= 20.4) mode = VISIR_SPC_M_MSWQ;
00218             else if (20.4 <  wlen && wlen <= 28.0) mode = VISIR_SPC_M_MLWQ;
00219             break;
00220           }
00221 
00222         case VISIR_SPC_R_GHR:
00223           {
00224                  if ( 7.6 <= wlen && wlen <=  7.8 ) mode = VISIR_SPC_M_GHR01;
00225             else if ( 7.8  < wlen && wlen <=  8.03) mode = VISIR_SPC_M_GHR02;
00226             else if ( 8.03 < wlen && wlen <=  8.26) mode = VISIR_SPC_M_GHR03;
00227             else if ( 8.26 < wlen && wlen <=  8.52) mode = VISIR_SPC_M_GHR04;
00228             else if ( 8.52 < wlen && wlen <=  8.78) mode = VISIR_SPC_M_GHR05;
00229             else if ( 8.78 < wlen && wlen <=  9.07) mode = VISIR_SPC_M_GHR06;
00230             else if ( 9.07 < wlen && wlen <=  9.36) mode = VISIR_SPC_M_GHR07;
00231             else if ( 9.36 < wlen && wlen <=  9.69) mode = VISIR_SPC_M_GHR08;
00232             else if ( 9.69 < wlen && wlen <= 10.03) mode = VISIR_SPC_M_GHR09;
00233             else if (10.03 < wlen && wlen <= 10.20) mode = VISIR_SPC_M_GHR10;
00234             else if (10.2  < wlen && wlen <= 10.41) mode = VISIR_SPC_M_GHR11;
00235             else if (10.41 < wlen && wlen <= 10.80) mode = VISIR_SPC_M_GHR12;
00236             else if (10.80 < wlen && wlen <= 11.24) mode = VISIR_SPC_M_GHR13;
00237             else if (11.24 < wlen && wlen <= 11.70) mode = VISIR_SPC_M_GHR14;
00238             else if (11.70 < wlen && wlen <= 12.21) mode = VISIR_SPC_M_GHR15;
00239             else if (12.21 < wlen && wlen <= 12.76) mode = VISIR_SPC_M_GHR16;
00240             else if (12.76 < wlen && wlen <= 13.37) mode = VISIR_SPC_M_GHR17;
00241             else if (13.37 < wlen && wlen <= 14.04) mode = VISIR_SPC_M_GHR18;
00242             else if (14.04 < wlen && wlen <= 14.77) mode = VISIR_SPC_M_GHR19;
00243             else if (15.60 < wlen && wlen <= 16.49) mode = VISIR_SPC_M_GHR20;
00244             else if (16.49 < wlen && wlen <= 17.55) mode = VISIR_SPC_M_GHR21;
00245             else if (17.55 < wlen && wlen <= 18.67) mode = VISIR_SPC_M_GHR22;
00246             else if (18.67 < wlen && wlen <= 20.06) mode = VISIR_SPC_M_GHR23;
00247             else if (20.06 < wlen && wlen <= 21.49) mode = VISIR_SPC_M_GHR24;
00248             else if (21.49 < wlen && wlen <= 23.40) mode = VISIR_SPC_M_GHR25;
00249             else if (23.40 < wlen && wlen <= 25.32) mode = VISIR_SPC_M_GHR26;
00250             else if (25.32 < wlen && wlen <= 28.08) mode = VISIR_SPC_M_GHR27;
00251             break;
00252           }
00253         case VISIR_SPC_R_HR:
00254           {
00255                  if ( 7.97 <= wlen && wlen <=  8.27) mode = VISIR_SPC_M_HR01;
00256             else if ( 8.83 <= wlen && wlen <=  9.05) mode = VISIR_SPC_M_HR02;
00257             else if ( 9.52 <= wlen && wlen <=  9.72) mode = VISIR_SPC_M_HR03;
00258                  /* FIXME: VISIR_SPC_M_HR04 really goes up to 12.21 */
00259             else if (11.85 <= wlen && wlen <  12.19) mode = VISIR_SPC_M_HR04;
00260             else if (12.19 <= wlen && wlen <= 12.37) mode = VISIR_SPC_M_HR05;
00261             else if (12.37 <  wlen && wlen <= 12.71) mode = VISIR_SPC_M_HR06;
00262             else if (12.71 <  wlen && wlen <= 12.91) mode = VISIR_SPC_M_HR07;
00263             else if (16.80 <= wlen && wlen <= 17.20) mode = VISIR_SPC_M_HR08;
00264             else if (18.32 <= wlen && wlen <= 18.67) mode = VISIR_SPC_M_HR09;
00265             else if (18.67 <  wlen && wlen <= 19.18) mode = VISIR_SPC_M_HR10;
00266             break;
00267           }
00268         default:;
00269     }
00270     wlen *= 1e-6;
00271 
00272     if (mode == VISIR_SPC_M_ERR) return -2;
00273 
00274     self->resolution = resol;
00275     self->mode = mode;
00276     self->wlen = wlen;
00277     self->m = 0;
00278 
00279     self->angle_a  = 0;
00280     self->angle_b0 = 0;
00281     self->angle_bm = 0;
00282     self->angle_b1 = 0;
00283 
00284     /* Switch on the resolution */
00285     switch (resol) {
00286     case VISIR_SPC_R_LR:
00287         {
00288             self->angle_a  = 6.708;
00289             self->angle_bm = 1.291;
00290             self->angle_b0 = 0.586;
00291             self->angle_b1 = 2.0;
00292             self->dcolbeam = 53000; /* [micron] */
00293             self->ld = 10332;
00294 
00295             /* Switch on the (LR)-mode */
00296             switch (mode) {
00297             case VISIR_SPC_M_LSWN:
00298                 {
00299                     self->d = 129.162;
00300                     self->m = 2;
00301                     break;
00302                 }
00303             case VISIR_SPC_M_LLWN:
00304                 {
00305                     self->d = 172.308;
00306                     self->m = 2;
00307                     break;
00308                 }
00309             case VISIR_SPC_M_LSWQ:
00310                 {
00311                     self->d = 129.162;
00312                     self->m = 1;
00313                     break;
00314                 }
00315             case VISIR_SPC_M_LLWQ:
00316                 {
00317                     self->d = 172.308;
00318                     self->m = 1;
00319                     break;
00320                 }
00321             default:;
00322             }
00323             break;
00324         }
00325     case VISIR_SPC_R_MR:
00326         {
00327             self->angle_a  = 34.208;
00328             self->angle_bm = 28.791;
00329             self->angle_b0 = 28.086;
00330             self->angle_b1 = 29.500;
00331             self->dcolbeam = 53000; /* [micron] */
00332             self->ld = 10332;
00333 
00334             /* Switch on the (MR)-mode */
00335             switch (mode) {
00336             case VISIR_SPC_M_MSWN:
00337                 {
00338                     self->d = 17.1478;
00339                     self->m = 2;
00340                     break;
00341                 }
00342             case VISIR_SPC_M_MLWN:
00343                 {
00344                     self->d = 22.9560;
00345                     self->m = 2;
00346                     break;
00347                 }
00348             case VISIR_SPC_M_MSWQ:
00349                 {
00350                     self->d = 17.1478;
00351                     self->m = 1;
00352                     break;
00353                 }
00354             case VISIR_SPC_M_MLWQ:
00355                 {
00356                     self->d = 22.9560;
00357                     self->m = 1;
00358                     break;
00359                 }
00360             default:;
00361             }
00362             break;
00363         }
00364     case VISIR_SPC_R_GHR:
00365         {
00366             /* Switch on the (HR Grism)-mode */
00367             self->side_is_A = 0;
00368             self->dcolbeam = 125000; /* [micron] */
00369             self->ld = 23403;
00370 
00371             switch (mode) {
00372             case VISIR_SPC_M_GHR01:
00373                 {
00374                     self->d=77.16526;
00375                     self->m=18;
00376                     self->gg=36.8906;
00377                     self->w=9.8;
00378                     self->offset=166.9;
00379                     self->factor=2940;
00380                     break;
00381                 }
00382 
00383             case VISIR_SPC_M_GHR02:
00384                 {
00385                     self->side_is_A = 1;
00386                     self->d=79.93104;
00387                     self->m=18;
00388                     self->gg=36.8906;
00389                     self->w=9.8;
00390                     self->offset=178;
00391                     self->factor=2940;
00392                     break;
00393                 }
00394 
00395             case VISIR_SPC_M_GHR03:
00396                 {
00397                     self->d=77.16526;
00398                     self->m=17;
00399                     self->gg=36.8906;
00400                     self->w=9.8;
00401                     self->offset=166.9;
00402                     self->factor=2940;
00403                     break;
00404                 }
00405 
00406             case VISIR_SPC_M_GHR04:
00407                 {
00408                     self->side_is_A = 1;
00409                     self->d=79.93104;
00410                     self->m=17;
00411                     self->gg=36.8906;
00412                     self->w=9.8;
00413                     self->offset=178;
00414                     self->factor=2940;
00415                     break;
00416                 }
00417 
00418             case VISIR_SPC_M_GHR05:
00419                 {
00420                     self->d=77.16526;
00421                     self->m=16;
00422                     self->gg=36.8906;
00423                     self->w=9.8;
00424                     self->offset=166.9;
00425                     self->factor=2940;
00426                     break;
00427                 }
00428 
00429             case VISIR_SPC_M_GHR06:
00430                 {
00431                     self->side_is_A = 1;
00432                     self->d=79.93104;
00433                     self->m=16;
00434                     self->gg=36.8906;
00435                     self->w=9.8;
00436                     self->offset=178;
00437                     self->factor=2940;
00438                     break;
00439                 }
00440 
00441             case VISIR_SPC_M_GHR07:
00442                 {
00443                     self->d=77.16526;
00444                     self->m=15;
00445                     self->gg=36.8906;
00446                     self->w=9.8;
00447                     self->offset=166.9;
00448                     self->factor=2940;
00449                     break;
00450                 }
00451 
00452             case VISIR_SPC_M_GHR08:
00453                 {
00454                     self->side_is_A = 1;
00455                     self->d=79.93104;
00456                     self->m=15;
00457                     self->gg=36.8906;
00458                     self->w=9.8;
00459                     self->offset=178;
00460                     self->factor=2940;
00461                     break;
00462                 }
00463 
00464             case VISIR_SPC_M_GHR09:
00465                 {
00466                     self->d=77.16526;
00467                     self->m=14;
00468                     self->gg=36.8906;
00469                     self->w=9.8;
00470                     self->offset=166.9;
00471                     self->factor=2940;
00472                     break;
00473                 }
00474 
00475             case VISIR_SPC_M_GHR10:
00476                 {
00477                     self->side_is_A = 1;
00478                     self->d=79.93104;
00479                     self->m=14;
00480                     self->gg=36.8906;
00481                     self->w=9.8;
00482                     self->offset=178;
00483                     self->factor=2940;
00484                     break;
00485                 }
00486 
00487             case VISIR_SPC_M_GHR11:
00488                 {
00489                     self->side_is_A = 1;
00490                     self->d=79.93104;
00491                     self->m=14;
00492                     self->gg=63.5470;
00493                     self->w=7.6;
00494                     self->offset=143.1;
00495                     self->factor=3004;
00496                     break;
00497                 }
00498 
00499             case VISIR_SPC_M_GHR12:
00500                 {
00501                     self->d=77.16526;
00502                     self->m=13;
00503                     self->gg=63.5470;
00504                     self->w=7.6;
00505                     self->offset=131.6;
00506                     self->factor=3004;
00507                     break;
00508                 }
00509 
00510             case VISIR_SPC_M_GHR13:
00511                 {
00512                     self->side_is_A = 1;
00513                     self->d=79.93104;
00514                     self->m=13;
00515                     self->gg=63.5470;
00516                     self->w=7.6;
00517                     self->offset=143.1;
00518                     self->factor=3004;
00519                     break;
00520                 }
00521 
00522             case VISIR_SPC_M_GHR14:
00523                 {
00524                     self->d=77.16526;
00525                     self->m=12;
00526                     self->gg=63.5470;
00527                     self->w=7.6;
00528                     self->offset=131.6;
00529                     self->factor=3004;
00530                     break;
00531                 }
00532 
00533             case VISIR_SPC_M_GHR15:
00534                 {
00535                     self->side_is_A = 1;
00536                     self->d=79.93104;
00537                     self->m=12;
00538                     self->gg=63.5470;
00539                     self->w=7.6;
00540                     self->offset=143.1;
00541                     self->factor=3004;
00542                     break;
00543                 }
00544 
00545             case VISIR_SPC_M_GHR16:
00546                 {
00547                     self->d=77.16526;
00548                     self->m=11;
00549                     self->gg=63.5470;
00550                     self->w=7.6;
00551                     self->offset=131.6;
00552                     self->factor=3004;
00553                     break;
00554                 }
00555 
00556             case VISIR_SPC_M_GHR17:
00557                 {
00558                     self->side_is_A = 1;
00559                     self->d=79.93104;
00560                     self->m=11;
00561                     self->gg=63.5470;
00562                     self->w=7.6;
00563                     self->offset=143.1;
00564                     self->factor=3004;
00565                     break;
00566                 }
00567 
00568             case VISIR_SPC_M_GHR18:
00569                 {
00570                     self->d=77.16526;
00571                     self->m=10;
00572                     self->gg=63.5470;
00573                     self->w=7.6;
00574                     self->offset=131.6;
00575                     self->factor=3004;
00576                     break;
00577                 }
00578 
00579             case VISIR_SPC_M_GHR19:
00580                 {
00581                     self->side_is_A = 1;
00582                     self->d=79.93104;
00583                     self->m=10;
00584                     self->gg=63.5470;
00585                     self->w=7.6;
00586                     self->offset=143.1;
00587                     self->factor=3004;
00588                     break;
00589                 }
00590 
00591             case VISIR_SPC_M_GHR20:
00592                 {
00593                     self->side_is_A = 1;
00594                     self->d=79.93104;
00595                     self->m=9;
00596                     self->gg=217.8772;
00597                     self->w=4.1;
00598                     self->offset=120.3;
00599                     self->factor=2980;
00600                     break;
00601                 }
00602 
00603             case VISIR_SPC_M_GHR21:
00604                 {
00605                     self->d=77.16526;
00606                     self->m=8;
00607                     self->gg=217.8772;
00608                     self->w=4.1;
00609                     self->offset=108.7;
00610                     self->factor=2980;
00611                     break;
00612                 }
00613 
00614             case VISIR_SPC_M_GHR22:
00615                 {
00616                     self->side_is_A = 1;
00617                     self->d=79.93104;
00618                     self->m=8;
00619                     self->gg=217.8772;
00620                     self->w=4.1;
00621                     self->offset=120.3;
00622                     self->factor=2980;
00623                     break;
00624                 }
00625 
00626             case VISIR_SPC_M_GHR23:
00627                 {
00628                     self->d=77.16526;
00629                     self->m=7;
00630                     self->gg=217.8772;
00631                     self->w=4.1;
00632                     self->offset=108.7;
00633                     self->factor=2980;
00634                     break;
00635                 }
00636 
00637             case VISIR_SPC_M_GHR24:
00638                 {
00639                     self->side_is_A = 1;
00640                     self->d=79.93104;
00641                     self->m=7;
00642                     self->gg=217.8772;
00643                     self->w=4.1;
00644                     self->offset=120.3;
00645                     self->factor=2980;
00646                     break;
00647                 }
00648 
00649             case VISIR_SPC_M_GHR25:
00650                 {
00651                     self->d=77.16526;
00652                     self->m=6;
00653                     self->gg=217.8772;
00654                     self->w=4.1;
00655                     self->offset=108.7;
00656                     self->factor=2980;
00657                     break;
00658                 }
00659 
00660             case VISIR_SPC_M_GHR26:
00661                 {
00662                     self->side_is_A = 1;
00663                     self->d=79.93104;
00664                     self->m=6;
00665                     self->gg=217.8772;
00666                     self->w=4.1;
00667                     self->offset=120.3;
00668                     self->factor=2980;
00669                     break;
00670                 }
00671 
00672             case VISIR_SPC_M_GHR27:
00673                 {
00674                     self->d=77.16526;
00675                     self->m=5;
00676                     self->gg=217.8772;
00677                     self->w=4.1;
00678                     self->offset=108.7;
00679                     self->factor=2980;
00680                     break;
00681                 }
00682             default:;
00683             }
00684 
00685             if (self->side_is_A) {
00686                 /* side 'A' */
00687                 self->angle_a  = 62.1299;
00688                 self->angle_bm = 64.8519;
00689                 self->angle_b0 = 64.5393;
00690                 self->angle_b1 = 65.1641;
00691             } else {
00692                 /* side 'B' */
00693                 self->angle_a  = 64.8701;
00694                 self->angle_bm = 62.1483;
00695                 self->angle_b0 = 62.4609;
00696                 self->angle_b1 = 61.8361;
00697             }
00698             self->w *= rad_per_deg;
00699 
00700             /* Length constants are coded in micron - convert to m */
00701             self->gg *= 1e-6;
00702             break;
00703         }
00704     case VISIR_SPC_R_HR:
00705         {
00706             /* Switch on the (HR Long Slit)-mode */
00707             self->side_is_A = 0;
00708             self->dcolbeam = 125000; /* [micron] */
00709             self->ld = 23403;
00710 
00711             switch (mode) {
00712             case VISIR_SPC_M_HR01:
00713                 {
00714                     self->m=17;
00715                     break;
00716                 }
00717             case VISIR_SPC_M_HR02:
00718                 {
00719                     self->side_is_A = 1;
00720                     self->m=16;
00721                     break;
00722                 }
00723             case VISIR_SPC_M_HR03:
00724                 {
00725                     self->side_is_A = 1;
00726                     self->m=15;
00727                     break;
00728                 }
00729             case VISIR_SPC_M_HR04:
00730                 {
00731                     self->side_is_A = 1;
00732                     self->m=12;
00733                     break;
00734                 }
00735             case VISIR_SPC_M_HR05:
00736                 {
00737                     self->m=11;
00738                     break;
00739                 }
00740             case VISIR_SPC_M_HR06:
00741                 {
00742                     self->m=11;
00743                     break;
00744                 }
00745             case VISIR_SPC_M_HR07:
00746                 {
00747                     self->side_is_A = 1;
00748                     self->m=11;
00749                     break;
00750                 }
00751             case VISIR_SPC_M_HR08:
00752                 {
00753                     self->m=8;
00754                     break;
00755                 }
00756             case VISIR_SPC_M_HR09:
00757                 {
00758                     self->side_is_A = 1;
00759                     self->m=8;
00760                     break;
00761                 }
00762             case VISIR_SPC_M_HR10:
00763                 {
00764                     self->m=7;
00765                     break;
00766                 }
00767             default:;
00768             }
00769             if (self->side_is_A) {
00770                 /* side 'A' */
00771                 self->d=79.93104;
00772                 self->angle_a  = 62.1299;
00773                 self->angle_bm = 64.8519;
00774                 self->angle_b0 = 64.5393;
00775                 self->angle_b1 = 65.1641;
00776             } else {
00777                 /* side 'B' */
00778                 self->d=77.16526;
00779                 self->angle_a  = 64.8701;
00780                 self->angle_bm = 62.1483;
00781                 self->angle_b0 = 62.4609;
00782                 self->angle_b1 = 61.8361;
00783             }
00784             break;
00785         }
00786     default:;
00787     }
00788 
00789     self->angle_a  *= rad_per_deg;
00790     self->angle_b0 *= rad_per_deg;
00791     self->angle_bm *= rad_per_deg;
00792     self->angle_b1 *= rad_per_deg;
00793 
00794     /* Length constants are coded in micron - convert to m */
00795     self->d        *= 1e-6;
00796     self->dcolbeam *= 1e-6;
00797 
00798     assert( self->m > 0);
00799 
00800     visir_spc_optmod_scan_angle(self);
00801 
00802     self->sinus_sum = sin(self->angle_a  + self->angle_scan)
00803                     + sin(self->angle_bm + self->angle_scan);
00804 
00805     return 0;
00806 
00807 }
00808 
00809 
00810 /*----------------------------------------------------------------------------*/
00824 /*----------------------------------------------------------------------------*/
00825 double visir_spc_optmod_wlen(const visir_optmod * pins, double * pwl0, 
00826                              double * pwl1)
00827 {
00828 
00829     const visir_optmod_private * self = (const visir_optmod_private*)pins;
00830 
00831     if (self == NULL) return -1;
00832 
00833     /* The wavelength on the center of the 1st pixel */
00834     if (pwl0) *pwl0 = self->d/self->m*( sin(self->angle_a  + self->angle_scan)
00835                                       + sin(self->angle_b0 + self->angle_scan));
00836   
00837     /* The wavelength on the center of the last pixel */
00838     if (pwl1) *pwl1 = self->d/self->m*( sin(self->angle_a  + self->angle_scan)
00839                                       + sin(self->angle_b1 + self->angle_scan));
00840 
00841     /* The wavelength on the detector-center according to the model */
00842     return self->d / self->m * self->sinus_sum;
00843 
00844 }
00845 
00846 /*----------------------------------------------------------------------------*/
00865 /*----------------------------------------------------------------------------*/
00866 double visir_spc_optmod_cross_dispersion(const visir_optmod * pins, double wlen)
00867 {
00868 
00869     double sinbeta;
00870     double rf_index;
00871     const visir_optmod_private * self = (const visir_optmod_private*)pins;
00872 
00873     if (self == NULL) return -1;
00874 
00875     if (self->resolution != VISIR_SPC_R_GHR) return -2;
00876     if (wlen <= 0) return -3;
00877 
00878     assert( self->gg != 0 );
00879 
00880     rf_index = visir_spc_optmod_krs5(wlen);
00881 
00882     if (rf_index < 1) return -8;
00883 
00884     sinbeta = sin(self->w) * rf_index - wlen / self->gg;
00885 
00886     /* Correct any rounding errors */
00887     if (sinbeta < -1) return -9;
00888     if (sinbeta >  1) return -10;
00889 
00890     return self->offset + self->factor * tan(asin(sinbeta) - self->w);
00891 
00892 }
00893 
00894 
00895 /*----------------------------------------------------------------------------*/
00918 /*----------------------------------------------------------------------------*/
00919 double visir_spc_optmod_echelle(const visir_optmod * pins, double wlen,
00920                                 int ioffset)
00921 {
00922 
00923     int order;
00924     const visir_optmod_private * self = (const visir_optmod_private*)pins;
00925 
00926     if (self == NULL) return -1;
00927     if (self->resolution != VISIR_SPC_R_GHR) return -2;
00928     if (wlen <= 0) return -3;
00929     if (ioffset < -4) return -4;
00930     if (ioffset >  4) return -5;
00931 
00932     order = ioffset + self->m;
00933 
00934     /* There are 18 echelle orders */
00935     if (order <    1) return -6;
00936     if (order >   18) return -7;
00937 
00938     return wlen * self->m / (double) order;
00939 
00940 }
00941 
00942 /*----------------------------------------------------------------------------*/
00957 /*----------------------------------------------------------------------------*/
00958 int visir_spc_optmod_side_is_A(const visir_optmod * pins)
00959 {
00960     const visir_optmod_private * self = (const visir_optmod_private*)pins;
00961 
00962     if (self == NULL) return -1;
00963 
00964     if (self->resolution != VISIR_SPC_R_GHR &&
00965         self->resolution != VISIR_SPC_R_HR) return -2;
00966 
00967     return self->side_is_A;
00968 
00969 }
00970 
00971 /*----------------------------------------------------------------------------*/
00986 /*----------------------------------------------------------------------------*/
00987 int visir_spc_optmod_get_echelle_order(const visir_optmod * pins)
00988 {
00989     const visir_optmod_private * self = (const visir_optmod_private*)pins;
00990 
00991     if (self == NULL) return -1;
00992 
00993     if (self->resolution != VISIR_SPC_R_GHR &&
00994         self->resolution != VISIR_SPC_R_HR) return -2;
00995 
00996     return self->m;
00997 }
00998 
00999 
01000 /*----------------------------------------------------------------------------*/
01012 /*----------------------------------------------------------------------------*/
01013 
01014 double visir_spc_optmod_resolution(const visir_optmod * pins)
01015 {
01016     const visir_optmod_private * self = (const visir_optmod_private*)pins;
01017 
01018     if (self == NULL) return -1;
01019 
01020     return self->dcolbeam * self->sinus_sum
01021         /(2.0 * self->wlen * cos(self->angle_a  + self->angle_scan));
01022 }
01023 
01024 /*----------------------------------------------------------------------------*/
01037 /*----------------------------------------------------------------------------*/
01038 
01039 double visir_spc_optmod_dispersion(const visir_optmod * pins)
01040 {
01041     const visir_optmod_private * self = (const visir_optmod_private*)pins;
01042 
01043     if (self == NULL) return -1;
01044 
01045     return self->ld * self->sinus_sum
01046         /(self->wlen * cos(self->angle_bm + self->angle_scan));
01047 }
01048 
01051 /*----------------------------------------------------------------------------*/
01058 /*----------------------------------------------------------------------------*/
01059 static double visir_spc_optmod_krs5(double wlen) {
01060 
01061     const double a0 =  5.96032159;
01062     const double a1 = -5.36135205e-4;
01063     const double a2 =  1.77047634;
01064     const double a3 = -2.79310980e1;
01065     const double a4 = -1.28684883;
01066     const double a5 = -4.34541795e-2;
01067 
01068     double n2 = 0;
01069 
01070 
01071     assert( wlen > 0 );
01072 
01073     /* The above constants are for a wavelength in microns */
01074     wlen *= 1e6;
01075 
01076     wlen *= wlen;
01077 
01078     n2 = a0 + a1 * wlen + (((a5/wlen + a4)/wlen + a3)/ wlen + a2)/wlen;
01079 
01080     /* The refractive index is greater than 1 */
01081     return n2 > 1 ? sqrt(n2) : -1;
01082 
01083 }
01084 
01085 /*----------------------------------------------------------------------------*/
01092 /*----------------------------------------------------------------------------*/
01093 static void visir_spc_optmod_scan_angle(visir_optmod_private * self)
01094 {
01095 
01096     /* Determine the Scan-angle from Mode and Central Wavelength */
01097 
01098     const double mld = self->m * self->wlen / self->d;
01099     const double sab = sin(self->angle_bm) + sin(self->angle_a);
01100     const double cab = cos(self->angle_bm) + cos(self->angle_a);
01101     const double A = sab * sab + cab * cab;
01102     /*
01103       const double B = -2 * mld * cab;
01104     */
01105     const double C = mld * mld - sab * sab;
01106 
01107     double D = A - mld * mld; /* D = B^2 - 4 * A * C */
01108     double u1, u2;
01109 
01110     /* D can only become negative due to rounding errors */
01111     D = D > 0 ? sqrt(D) : 0;
01112     D *= fabs(sab);
01113 
01114     /* A, cab, mld & D are all positive */
01115     u1 = (cab * mld + D) / A;
01116 
01117     /* u2 may be a lot smaller than both D/A and cab * mld/A, so subtraction
01118        of those two terms may lead to loss of precision. u2 is instead
01119        computed by use of the fact that C = A * u1 * u2 */
01120     u2 = C / A / u1;           
01121 
01122     /* u1 is not a physically meaningful solution, it is just an
01123        intermediate result */
01124 
01125     self->angle_scan = asin(u2);
01126 
01127 }

Generated on Thu Mar 24 11:59:39 2011 for VISIR Pipeline Reference Manual by  doxygen 1.5.8