Isis 3 Programmer Reference
RadarSlantRangeMap.cpp
Go to the documentation of this file.
1 
23 #include "RadarSlantRangeMap.h"
24 
25 #include "IString.h"
26 #include "iTime.h"
27 #include "PvlSequence.h"
28 
29 using namespace std;
30 
31 namespace Isis {
40  RadarSlantRangeMap::RadarSlantRangeMap(Camera *parent, double groundRangeResolution) :
41  CameraDistortionMap(parent, 1.0) {
42 
43  p_camera = parent;
44  p_et = DBL_MAX;
45  p_a[0] = p_a[1] = p_a[2] = p_a[3] = 0.0;
46 
47  // Need to come up with an initial guess when solving for ground
48  // range given slantrange. We will compute the ground range at the
49  // near and far edges of the image by evaluating the sample-to-
50  // ground-range equation: r_gnd=(S-1)*groundRangeResolution
51  // at the edges of the image. We also need to add some padding to
52  // allow for solving for coordinates that are slightly outside of
53  // the actual image area. Use S=-0.25*p_camera->Samples() and
54  // S=1.25*p_camera->Samples().
55  // The above approach works nicely for a level 1 image but the
56  // sensor model at level2 doesn't have access to the level 1
57  // number of samples. Instead, we will calculate initial guesses
58  // on the fly in SetUndistortedFocalPlane.
59  p_tolerance = 0.1; // Default tolerance is a tenth of a meter
60  p_maxIterations = 30;
61 
62  }
63 
67  bool RadarSlantRangeMap::SetFocalPlane(const double dx, const double dy) {
68  p_focalPlaneX = dx; // dx is a ground range distance in meters
69  p_focalPlaneY = dy; // dy is Doppler shift in htz and should always be 0
70 
71  if (p_et != p_camera->time().Et()) ComputeA();
72  double slantRange = p_a[0] + p_a[1] * dx + p_a[2] * dx * dx + p_a[3] * dx * dx * dx; // meters
73 
74  p_camera->SetFocalLength(slantRange);
75  p_undistortedFocalPlaneX = slantRange / p_rangeSigma;
77 
78  return true;
79  }
80 
85  const double uy) {
86  p_undistortedFocalPlaneX = ux * p_rangeSigma; // ux converts to slant range in meters
87  p_undistortedFocalPlaneY = uy * p_dopplerSigma; // uy converts to Doppler shift in htz and should always be 0
88 
89  if (p_et != p_camera->time().Et()) ComputeA();
90 
91  double slant = p_undistortedFocalPlaneX;
92  // First trap the case where no iteration is needed. Since this occurs at
93  // the first pixel of the image, it's a real possibility to encounter.
94  if (fabs(slant-p_a[0]) < p_tolerance) {
95  p_focalPlaneX = 0.0;
96  p_focalPlaneY = 0.0;
97  return true;
98  }
99  // Now calculate two guesses by the first and second iterations of
100  // Newton's method, where the zeroth iteration is at ground range = 0.
101  // The nature of the slant range function is such that, in the region
102  // of validity (including all image data) the Newton approximations are
103  // always too high, but the second one is within a few meters. We therefore
104  // add 10 m of “windage” to it to bracket the root.
105  // Performing a third Newton iteration would give a satisfactory solution in
106  // the data area but raises the problem of trapping errors outside this region
107  // where the polynomial is not so well behaved.
108  // Use the “min” variables temporarily to hold the first approximation
109  p_initialMinGroundRangeGuess = (slant - p_a[0]) / p_a[1];
110  double minGroundRangeGuess = slant - (p_a[0] + p_initialMinGroundRangeGuess *
111  (p_a[1] + p_initialMinGroundRangeGuess * (p_a[2] + p_initialMinGroundRangeGuess * p_a[3])));
112  // Now the max is the second approximation
113  p_initialMaxGroundRangeGuess = p_initialMinGroundRangeGuess + minGroundRangeGuess /
114  (p_a[1] + p_initialMinGroundRangeGuess * (2.0 * p_a[2] + p_initialMinGroundRangeGuess *
115  3.0 * p_a[3]));
116  double maxGroundRangeGuess = slant - (p_a[0] + p_initialMaxGroundRangeGuess *
117  (p_a[1] + p_initialMaxGroundRangeGuess * (p_a[2] +
118  p_initialMaxGroundRangeGuess * p_a[3])));
119  // Finally, apply the “windage” to bracket the root.
120  p_initialMinGroundRangeGuess = p_initialMaxGroundRangeGuess - 10.0;
121  minGroundRangeGuess = slant - (p_a[0] + p_initialMinGroundRangeGuess *
122  (p_a[1] + p_initialMinGroundRangeGuess * (p_a[2] + p_initialMinGroundRangeGuess * p_a[3])));
123 
124  // If both guesses are on the same side of zero, we need to expand the bracket range
125  // to include a zero-crossing.
126  if ((minGroundRangeGuess < 0.0 && maxGroundRangeGuess < 0.0) ||
127  (minGroundRangeGuess > 0.0 && maxGroundRangeGuess > 0.0)) {
128 
129  int maxBracketIters = 10;
130 
131  float xMin = p_initialMinGroundRangeGuess;
132  float xMax = p_initialMaxGroundRangeGuess;
133 
134  float funcMin = minGroundRangeGuess;
135  float funcMax = maxGroundRangeGuess;
136 
137  for (int j=0; j<maxBracketIters; j++) {
138 
139  //distance between guesses
140  float dist = abs(abs(xMin) - abs(xMax));
141 
142  // move move the x-value of the closest root twice as far away from the other root as it was
143  // before to extend the bracket range.
144  if (abs(funcMin) <= abs(funcMax)) {
145  //min is closer
146  xMin = xMax - 2*dist;
147  }
148  else {
149  //max is closer
150  xMax = xMin + 2*dist;
151  }
152 
153  funcMin = slant -(p_a[0]+ xMin *(p_a[1] + xMin * (p_a[2] + xMin * p_a[3])));
154  funcMax = slant - (p_a[0] + xMax *(p_a[1] + xMax * (p_a[2] + xMax * p_a[3])));
155 
156  // if we've successfully bracketed the root, we can break.
157  if ((funcMin <= 0.0 && funcMax >= 0.0) || (funcMin >= 0.0 && funcMax <= 0.0)){
158  p_initialMinGroundRangeGuess = xMin;
159  p_initialMaxGroundRangeGuess = xMax;
160  minGroundRangeGuess = funcMin;
161  maxGroundRangeGuess = funcMax;
162  break;
163  }
164  }
165  }
166 
167  // If the ground range guesses at the 2 extremes of the image are equal
168  // or they have the same sign, then the ground range cannot be solved for.
169  // The only case where they are equal should be at zero, which we already trapped.
170  if ((minGroundRangeGuess == maxGroundRangeGuess) ||
171  (minGroundRangeGuess < 0.0 && maxGroundRangeGuess < 0.0) ||
172  (minGroundRangeGuess > 0.0 && maxGroundRangeGuess > 0.0)) {
173  return false;
174  }
175 
176  // Use Wijngaarden/Dekker/Brent algorithm to find a root of the function:
177  // g(groundRange) = slantRange - (p_a[0] + groundRange * (p_a[1] +
178  // groundRange * (p_a[2] + groundRange * p_a[3])))
179  // The algorithm used is a combination of the bisection method with the
180  // secant method.
181  int iter = 0;
182  double eps = 3.E-8;
183  double ax = p_initialMinGroundRangeGuess;
184  double bx = p_initialMaxGroundRangeGuess;
185  double fax = minGroundRangeGuess;
186  double fbx = maxGroundRangeGuess;
187  double fcx = fbx;
188  double cx = 0.0;
189  double d = 0.0;
190  double e = 0.0;
191  double tol1;
192  double xm;
193  double p, q, r, s, t;
194 
195  do {
196  iter++;
197  if (fbx * fcx > 0.0) {
198  cx = ax;
199  fcx = fax;
200  d = bx - ax;
201  e = d;
202  }
203  if (fabs(fcx) < fabs(fbx)) {
204  ax = bx;
205  bx = cx;
206  cx = ax;
207  fax = fbx;
208  fbx = fcx;
209  fcx = fax;
210  }
211  tol1 = 2.0 * eps * fabs(bx) + 0.5 * p_tolerance;
212  xm = 0.5 * (cx - bx);
213  if (fabs(xm) <= tol1 || fbx == 0.0) {
214  p_focalPlaneX = bx;
215  p_focalPlaneY = 0.0;
216  return true;
217  }
218  if (fabs(e) >= tol1 && fabs(fax) > fabs(fbx)) {
219  s = fbx / fax;
220  if (ax == cx) {
221  p = 2.0 * xm * s;
222  q = 1.0 - s;
223  }
224  else {
225  q = fax / fcx;
226  r = fbx / fcx;
227  p = s * (2.0 * xm * q * (q - r) - (bx - ax) * (r - 1.0));
228  q = (q - 1.0) * (r - 1.0) * (s - 1.0);
229  }
230  if (p > 0.0) q = -q;
231  p = fabs(p);
232  t = 3.0 * xm * q - fabs(tol1 * q);
233  if (t > fabs(e * q)) t = fabs(e * q);
234  if (2.0 * p < t) {
235  e = d;
236  d = p / q;
237  }
238  else {
239  d = xm;
240  e = d;
241  }
242  }
243  else {
244  d = xm;
245  e = d;
246  }
247  ax = bx;
248  fax = fbx;
249  if (fabs(d) > tol1) {
250  bx = bx + d;
251  }
252  else {
253  if (xm >= 0.0) {
254  t = fabs(tol1);
255  }
256  else {
257  t = -fabs(tol1);
258  }
259  bx = bx + t;
260  }
261  fbx = slant - (p_a[0] + bx * (p_a[1] + bx * (p_a[2] + bx * p_a[3])));
262  }
263  while (iter <= p_maxIterations);
264 
265  return false;
266  }
267 
273  PvlSequence seq;
274  seq = keyword;
275  for (int i = 0; i < seq.Size(); i++) {
276  // TODO: Test array size to be 4 if not throw error
277  std::vector<QString> array = seq[i];
278  double et;
279  utc2et_c(array[0].toLatin1().data(), &et);
280  p_time.push_back(et);
281  p_a0.push_back(toDouble(array[1]));
282  p_a1.push_back(toDouble(array[2]));
283  p_a2.push_back(toDouble(array[3]));
284  p_a3.push_back(toDouble(array[4]));
285  // TODO: Test that times are ordered if not throw error
286  // Make the mrf2isis program sort them if necessary
287  }
288  }
289 
295  double currentEt = p_camera->time().Et();
296 
297  std::vector<double>::iterator pos = lower_bound(p_time.begin(), p_time.end(), currentEt);
298 
299  int index = p_time.size() - 1;
300  if (currentEt <= p_time[0]) {
301  p_a[0] = p_a0[0];
302  p_a[1] = p_a1[0];
303  p_a[2] = p_a2[0];
304  p_a[3] = p_a3[0];
305  }
306  else if (currentEt >= p_time.at(index)) {
307  p_a[0] = p_a0[index];
308  p_a[1] = p_a1[index];
309  p_a[2] = p_a2[index];
310  p_a[3] = p_a3[index];
311  } else {
312  index = pos - p_time.begin();
313  double weight = (currentEt - p_time.at(index-1)) /
314  (p_time.at(index) - p_time.at(index-1));
315  p_a[0] = p_a0[index-1] * (1.0 - weight) + p_a0[index] * weight;
316  p_a[1] = p_a1[index-1] * (1.0 - weight) + p_a1[index] * weight;
317  p_a[2] = p_a2[index-1] * (1.0 - weight) + p_a2[index] * weight;
318  p_a[3] = p_a3[index-1] * (1.0 - weight) + p_a3[index] * weight;
319  }
320  }
321 
325  void RadarSlantRangeMap::SetWeightFactors(double range_sigma, double doppler_sigma) {
326  p_rangeSigma = range_sigma; // meters scaling factor
327  p_dopplerSigma = doppler_sigma; // htz scaling factor
328  }
329 }
void SetWeightFactors(double range_sigma, double doppler_sigma)
Set the weight factors for slant range and Doppler shift.
double p_focalPlaneX
Distorted focal plane x.
Parse and return elements of a Pvl sequence.
Definition: PvlSequence.h:64
void ComputeA()
Set new A-coefficients based on the current ephemeris time.
Namespace for the standard library.
virtual bool SetFocalPlane(const double dx, const double dy)
Set the ground range and compute a slant range.
double toDouble(const QString &string)
Global function to convert from a string to a double.
Definition: IString.cpp:164
int Size() const
Number of arrays in the sequence.
Definition: PvlSequence.h:88
double p_undistortedFocalPlaneX
Undistorted focal plane x.
virtual bool SetUndistortedFocalPlane(const double ux, const double uy)
Set the slant range and compute a ground range.
void SetFocalLength(double v)
Sets the focal length.
Definition: Camera.cpp:3026
A single keyword-value pair.
Definition: PvlKeyword.h:98
Distort/undistort focal plane coordinates.
double p_focalPlaneY
Distorted focal plane y.
double p_undistortedFocalPlaneY
Undistorted focal plane y.
void SetCoefficients(PvlKeyword &keyword)
Load the ground range/slant range coefficients from the RangeCoefficientSet keyword.
Namespace for ISIS/Bullet specific routines.
Definition: Apollo.h:31
double Et() const
Returns the ephemeris time (TDB) representation of the time as a double.
Definition: iTime.h:139
iTime time() const
Returns the ephemeris time in seconds which was used to obtain the spacecraft and sun positions...
Definition: Spice.cpp:809