ocssw  1.0
/disk01/web/ocssw/build/src/libosmi/ctotc.c (r8090/r3)
Go to the documentation of this file.
00001 /*
00002  *----------------------------------------------------------------------
00003  *  @(#) ctotc.c    1.0 20 Mar 93   <shc>
00004  *  Copyright (c) 1993, CSIRO Division of Oceanography.
00005  *----------------------------------------------------------------------
00006  *
00007  * ctotc --
00008  *
00009  *  Rectangular (Cartesian) to topocentric coordinate conversion.
00010  *
00011  * Results:
00012  *
00013  *  Given the rectangular (Cartesian) earth-centred coordinates of an
00014  *  object, the latitude, longitude and height above the geoid of
00015  *  an observer and the Greenwich Hour angle, calculate the topocentric
00016  *  coordinates of the object (azimuth, elevation and range) and,
00017  *  optionally, derivatives of these wrt Cartesian.
00018  *  Units are radians, metres and seconds.
00019  *
00020  *  Azimuth, elevation and range are returned in TOP.  If "DAER"
00021  *  is non-NULL, the 3x3 Jacobian of topocentric coordinates wrt
00022  *  rectangular coordinates is returned in DAER.
00023  *
00024  * Side effects:
00025  *  None.
00026  *
00027  * History:
00028  *  17 Dec 90  <shc>
00029  *     Initial version
00030  *
00031  *  23 Jan 91  <shc>
00032  *     Reduced number of trig routine calls
00033  *
00034  *  20 Mar 93  <shc>
00035  *     Converted from FORTRAN to C
00036  *
00037  *----------------------------------------------------------------------
00038  */
00039 
00040 #include "orbit.h"
00041 
00042 
00043 void
00044 ctotc(r, obs, gha, top, daer)
00045 double r[3];        /* Rectangular coordinates of object (metres) */
00046 struct GEODETIC *obs;   /* Observer's lat, lon (radians) and height (m) */
00047 double gha;     /* Greenwich hour angle (radians) */
00048 struct TOPOCENTRIC *top; /* Resulting az, el and range */
00049 double daer[3][3];  /* Jacobian of (az,el,range) wrt (x,y,z) */
00050 {
00051     int i, j;
00052     double olat, olon, ohgt, clat, clon, slat, slon;
00053     double ens, xo, yo, zo, xos, yos, zos, xlt, ylt, zlt;
00054     double rngsq, range;
00055     double emlt[3][3], dlt[3][3];
00056 /*
00057  * Observer geodetic coordinates (latitude, longitude and height) in
00058  * radians and metres.
00059  */
00060     olat = obs->lat;
00061     olon = AN2PI(obs->lon + gha);
00062     ohgt = obs->height;
00063 
00064     clat = cos(olat);
00065     clon = cos(olon);
00066     slat = sin(olat);
00067     slon = sin(olon);
00068 /*
00069  * Rotation matrix to bring geocentric reference frame
00070  * parallel to local tangent reference frame.
00071  */
00072     emlt[0][0] = - slon;
00073     emlt[0][1] =   clon;
00074     emlt[0][2] =   0.0;
00075     emlt[1][0] = - slat*clon;
00076     emlt[1][1] = - slat*slon;
00077     emlt[1][2] =   clat;
00078     emlt[2][0] =   clat*clon;
00079     emlt[2][1] =   clat*slon;
00080     emlt[2][2] =   slat;
00081 /*
00082  * Geocentric vector to observer
00083  */
00084     ens = EQRAD / sqrt(1.0 - FLT*(2.0 - FLT)*slat*slat);
00085     xo = (ens + ohgt) * clat * clon;
00086     yo = (ens + ohgt) * clat * slon;
00087     zo = (ens*(1.0 - FLT)*(1.0 - FLT) + ohgt) * slat;
00088 /*
00089  * Vector from observer to object
00090  */
00091     xos = r[0] - xo;
00092     yos = r[1] - yo;
00093     zos = r[2] - zo;
00094 /*
00095  * Position of object in local tangent reference frame
00096  */
00097     xlt = emlt[0][0]*xos + emlt[0][1]*yos + emlt[0][2]*zos;
00098     ylt = emlt[1][0]*xos + emlt[1][1]*yos + emlt[1][2]*zos;
00099     zlt = emlt[2][0]*xos + emlt[2][1]*yos + emlt[2][2]*zos;
00100 /*
00101  * Spacecraft azimuth, elevation and range
00102  */
00103     rngsq = xlt*xlt + ylt*ylt + zlt*zlt;
00104     range = sqrt(rngsq);
00105     top->az = AN2PI(atan2(xlt, ylt));
00106     top->el = asin(zlt / range);
00107     top->range = range;
00108 /*
00109  * Optionally calculate derivatives of azimuth, elevation and range
00110  * with respect to the object rectangular coordinates.
00111  */
00112     if (daer != NULL) {
00113         double a1, a2;
00114 /*
00115  * Derivatives of azimuth (DLT[0][*]), elevation (DLT[1][*]) and
00116  * range (DLT[2][*]) wrt object position in local tangent frame.
00117  */
00118         a1 = xlt*xlt + ylt*ylt;
00119         a2 = sqrt(a1);
00120         dlt[0][0] =  ylt / a1;
00121         dlt[0][1] = -xlt / a1;
00122         dlt[0][2] = 0.0;
00123         dlt[1][0] = -zlt*xlt / (rngsq * a2);
00124         dlt[1][1] = -zlt*ylt / (rngsq * a2);
00125         dlt[1][2] = a2 / rngsq;
00126         dlt[2][0] = xlt / range;
00127         dlt[2][1] = ylt / range;
00128         dlt[2][2] = zlt / range;
00129 /*
00130  * Convert derivatives wrt local tangent frame to derivatives wrt
00131  * geocentric reference frame: Product[dlt, emlt].
00132  */
00133         for (i = 0; i < 3; i++) {
00134             for (j = 0; j < 3; j++) {
00135                 daer[i][j] = dlt[i][0]*emlt[0][j] +
00136                          dlt[i][1]*emlt[1][j] +
00137                          dlt[i][2]*emlt[2][j];
00138             }
00139         }
00140     }
00141 
00142     return;
00143 }