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

U.S. Department of the Interior | U.S. Geological Survey
ISIS | Privacy & Disclaimers | Astrogeology Research Program
To contact us, please post comments and questions on the USGS Astrogeology Discussion Board
To report a bug, or suggest a feature go to: ISIS Github
File Modified: 07/13/2023 15:17:11