OB.DAAC Logo
NASA Logo
Ocean Color Science Software

ocssw V2022
locate.c
Go to the documentation of this file.
1 /*
2  *----------------------------------------------------------------------
3  * @(#) locate.c 1.0 11 Aug 95 <shc>
4  * Copyright (c) 1995, CSIRO Division of Oceanography.
5  *----------------------------------------------------------------------
6  *
7  * Locate the rectangular coordinates of the point of intersection of
8  * a satellite scanner ray and the surface of a spheriod. A simple
9  * port to C of the Fortran routine in Puccinelli's paper.
10  *
11  * Inputs:
12  * svec - Satellite state vector (X, Y, Z, Xdot, Ydot, Zdot)
13  * sat - Satellite orientation. Rotations are made in the
14  * order pitch, roll, yaw, and each rotation is made
15  * about the axis system formed by the previous rotation.
16  * scan - Orientation of the scanner look vector relative to the
17  * spacecraft axes. Equivalent to rotating the nadir
18  * vector about the pitch axis through the pitch angle
19  * and then about the roll axis by the roll angle. Yaw
20  * is ignored.
21  *
22  * The reference frame axes are as follows (origin at the satellite):
23  *
24  * Yaw: normal to spheroid
25  * Velocity: coincident with velocity vector
26  * Pitch: yaw x velocity
27  *
28  * Rotations have the normal sense about the axes (e.g. positive pitch
29  * causes the scanner to look ahead of the spacecraft.
30  *
31  * Outputs:
32  * Function returns 1 if the scanner misses the earth, 2 if it
33  * looks directly away from the earth, and 0 if the scanner sees
34  * the earth, in which case the X, Y, Z coordinates of the intercept
35  * of the scanner look vector with the surface of the earth are
36  * returned in "loc".
37  *
38  * Reference:
39  *
40  * 'Ground Location of Satellite Scanner Data',
41  * E. Puccinelli, Photogrammetric Engineering and
42  * Remote Sensing, Vol 42, April 1976, pp 537-543.
43  */
44 
45 #include <math.h>
46 
47 #include "orbit.h"
48 
49 #define TINY (1.0e-10)
50 
51 int
52 locate(svec, sat, scan, loc)
53 double svec[6]; /* Spacecraft state vector */
54 struct ATTITUDE *sat; /* Satellite attitude */
55 struct ATTITUDE *scan; /* Scanner vector angles */
56 double loc[3]; /* Intersection coordinates */
57 {
58  double a, adr, anbla1, anbla2, b, c, cp, cr, csp, csr, cy, d11, d12,
59  d13, d21, d22, d23, d31, d32, d33, delta, ersq, f, gx, gy, gz,
60  m1, m2, m3, phi, prsq, r1, r2, r3, rad, rxy, sdelta, sp, sr,
61  ssp, ssr, sy, u3, vl, ynorm[3], ynorml;
62  ersq = EQRAD * EQRAD;
63  prsq = POLRAD * POLRAD;
64 
65  /* Normal to the spheroid (Desai's algorithm) */
66 
67  ynorm[0] = -svec[0];
68  ynorm[1] = -svec[1];
69  ynorm[2] = -svec[2];
70 
71  if (fabs(svec[2]) > TINY) {
72  rxy = sqrt(svec[0] * svec[0] + svec[1] * svec[1]);
73  if (fabs(rxy) > TINY) {
74  rad = sqrt(svec[0] * svec[0] +
75  svec[1] * svec[1] + svec[2] * svec[2]);
76  delta = atan2(svec[2], rxy);
77  sdelta = sin(delta);
78  adr = EQRAD / rad;
79  anbla1 = adr * sin(2.0 * delta) / 2.0;
80  anbla2 = adr + (0.5 - 2.0 * adr) * sdelta*sdelta;
81  phi = delta + anbla1 * ECCSQ * (1.0 + anbla2 * ECCSQ);
82  ynorm[2] = -rxy * tan(phi);
83  }
84  }
85 
86  /* Satellite attitude trig values */
87 
88  cy = cos(sat->yaw);
89  cp = cos(sat->pitch);
90  cr = cos(sat->roll);
91  sy = sin(sat->yaw);
92  sp = sin(sat->pitch);
93  sr = sin(sat->roll);
94 
95  /* Scanner orientation trig values */
96 
97  csp = cos(scan->pitch);
98  csr = cos(scan->roll);
99  ssp = sin(scan->pitch);
100  ssr = sin(scan->roll);
101 
102  /* Vector m */
103 
104  m1 = csr * ssp;
105  m2 = -ssr;
106  m3 = csp * csr;
107 
108  /* R = M . m */
109 
110  r1 = m1 * (cp * cy + sp * sr * sy) + m2 * (sp * sr * cy - cp * sy) + m3 * cr*sp;
111  r2 = m1 * sy * cr + m2 * cr * cy - m3*sr;
112  r3 = m1 * (cp * sr * sy - sp * cy) + m2 * (sp * sy + cp * sr * cy) + m3 * cp*cr;
113 
114  /* D matrix */
115 
116  ynorml = sqrt(ynorm[0] * ynorm[0] +
117  ynorm[1] * ynorm[1] + ynorm[2] * ynorm[2]);
118 
119  d13 = ynorm[0] / ynorml;
120  d23 = ynorm[1] / ynorml;
121  d33 = ynorm[2] / ynorml;
122 
123  d12 = d23 * svec[5] - d33 * svec[4];
124  d22 = d33 * svec[3] - d13 * svec[5];
125  d32 = d13 * svec[4] - d23 * svec[3];
126 
127  vl = sqrt(d12 * d12 + d22 * d22 + d32 * d32);
128  d12 = d12 / vl;
129  d22 = d22 / vl;
130  d32 = d32 / vl;
131 
132  d11 = d22 * d33 - d23*d32;
133  d21 = d32 * d13 - d33*d12;
134  d31 = d12 * d23 - d13*d22;
135 
136  /* Unit vector g = D * M * m */
137 
138  gx = r1 * d11 + r2 * d12 + r3*d13;
139  gy = r1 * d21 + r2 * d22 + r3*d23;
140  gz = r1 * d31 + r2 * d32 + r3*d33;
141 
142  /* Values for calculating distance from scanner to intercept point */
143 
144  a = prsq * (gx * gx + gy * gy) + ersq * gz*gz;
145  b = prsq * (svec[0] * gx + svec[1] * gy) + ersq * svec[2] * gz;
146  c = prsq * (svec[0] * svec[0] + svec[1] * svec[1]) +
147  ersq * (svec[2] * svec[2] - prsq);
148  f = b * b - a*c;
149 
150  /* If f is negative, the scanner misses the earth */
151 
152  if (f < 0)
153  return (1);
154 
155  /*
156  * Calculate the distance from the scanner to the intercept point.
157  * If u3 is negative, the scanner is looking away from the body.
158  */
159 
160  u3 = -(b + sqrt(f)) / a;
161  if (u3 < 0)
162  return (2);
163 
164  /* Calculate the intercept point */
165  loc[0] = svec[0] + u3*gx;
166  loc[1] = svec[1] + u3*gy;
167  loc[2] = svec[2] + u3*gz;
168  return (0);
169 }
170 
171 
172 #ifdef __TEST__
173 
174 main() {
175  int miss;
176  double svec[6], loc[3];
177  struct ATTITUDE sat, scanner;
178 
179  scanf("%lf %lf %lf %lf %lf %lf", &svec[0], &svec[1], &svec[2],
180  &svec[3], &svec[4], &svec[5]);
181  scanf("%lf %lf %lf", &sat.pitch, &sat.roll, &sat.yaw);
182  scanf("%lf %lf %lf", &scanner.yaw, &scanner.pitch, &scanner.roll);
183 
184  miss = locate(svec, &sat, &scanner, loc);
185 
186  printf("%lf %lf %lf %d\n", loc[0], loc[1], loc[2], miss);
187 }
188 #endif
#define EQRAD
Definition: earth.h:33
MOD_PR01 Production producing one five minute granule of output data in each run It can be configured to produce as many as three five minute granules per run Each execution with one construction record and one date file for each dataset In normal these are created by which splits them out of the hour datasets For LANCE they are created by which merges all session MODIS L0 datasets overlapping the requested time and extracts from the merged data those packets which fall within that time period Each scan of data is stored in the L1A granule that covers the start time of that scan
Definition: MOD_PR01_pr.txt:19
#define TINY
Definition: locate.c:49
int locate(svec, struct ATTITUDE *sat, struct ATTITUDE *scan, loc)
Definition: locate.c:52
double precision function f(R1)
Definition: tmd.lp.f:1454
const double delta
data_t b[NROOTS+1]
Definition: decode_rs.h:77
data_t loc[NROOTS]
Definition: decode_rs.h:78
#define fabs(a)
Definition: misc.h:93
int main(int argc, char *argv[])
Definition: afrt_nc4.cpp:30
#define POLRAD
Definition: earth.h:34
#define ECCSQ
Definition: earth.h:38
no change in intended resolving MODur00064 Corrected handling of bad ephemeris attitude resolving resolving GSFcd00179 Corrected handling of fill values for[Sensor|Solar][Zenith|Azimuth] resolving MODxl01751 Changed to validate LUT version against a value retrieved from the resolving MODxl02056 Changed to calculate Solar Diffuser angles without adjustment for estimated post launch changes in the MODIS orientation relative to incidentally resolving defects MODxl01766 Also resolves MODxl01947 Changed to ignore fill values in SCI_ABNORM and SCI_STATE rather than treating them as resolving MODxl01780 Changed to use spacecraft ancillary data to recognise when the mirror encoder data is being set by side A or side B and to change calculations accordingly This removes the need for seperate LUTs for Side A and Side B data it makes the new LUTs incompatible with older versions of the and vice versa Also resolves MODxl01685 A more robust GRing algorithm is being which will create a non default GRing anytime there s even a single geolocated pixel in a granule Removed obsolete messages from seed as required for compatibility with version of the SDP toolkit Corrected test output file names to end in per delivery and then split off a new MYD_PR03 pcf file for Aqua Added AssociatedPlatformInstrumentSensor to the inventory metadata in MOD01 mcf and MOD03 mcf Created new versions named MYD01 mcf and MYD03 where AssociatedPlatformShortName is rather than Terra The program itself has been changed to read the Satellite Instrument validate it against the input L1A and LUT and to use it determine the correct files to retrieve the ephemeris and attitude data from Changed to produce a LocalGranuleID starting with MYD03 if run on Aqua data Added the Scan Type file attribute to the Geolocation copied from the L1A and attitude_angels to radians rather than degrees The accumulation of Cumulated gflags was moved from GEO_validate_earth_location c to GEO_locate_one_scan c
Definition: HISTORY.txt:464
PGE01 indicating that PGE02 PGE01 V6 for and PGE01 V2 for MOD03 were used to produce the granule By convention adopted in all MODIS Terra PGE02 code versions are The fourth digit of the PGE02 version denotes the LUT version used to produce the granule The source of the metadata environment variable ProcessingCenter was changed from a QA LUT value to the Process Configuration A sign used in error in the second order term was changed to a
Definition: HISTORY.txt:424
Definition: orbit.h:79