isce3 0.25.0
Loading...
Searching...
No Matches
Geo2Rdr.icc
1#include <cmath>
2#include <limits>
3
4#include <isce3/core/Ellipsoid.h>
5#include <isce3/core/Orbit.h>
6#include <isce3/core/Vector.h>
7#include <isce3/math/RootFind1dBracket.h>
8
9namespace isce3::geometry::detail {
10
11NVCC_HD_WARNING_DISABLE
12template<class DopplerModel>
13CUDA_HOSTDEV isce3::error::ErrorCode
14computeDopplerAztimeDiff(double* dt, double t, double r,
15 const isce3::core::Vec3& rvec,
16 const isce3::core::Vec3& vel,
17 const DopplerModel& doppler, double wvl, double dr)
18{
19 using isce3::error::ErrorCode;
20
21 // Check for out-of-bounds LUT evaluation (LUT2d's internal handling of
22 // out-of-bounds lookup is not thread-safe)
23 if (doppler.boundsError()) {
24 if (not(doppler.contains(t, r) and doppler.contains(t, r + dr))) {
25 return ErrorCode::OutOfBoundsLookup;
26 }
27 }
28
29 // compute Doppler
30 const auto dopfact = rvec.dot(vel);
31 const auto fdop = 0.5 * wvl * doppler.eval(t, r);
32
33 // use forward difference to compute Doppler derivative
34 const auto fdopder = (0.5 * wvl * doppler.eval(t, r + dr) - fdop) / dr;
35
36 // evaluate cost function and its derivative
37 const auto fn = dopfact - fdop * r;
38 const auto c1 = -vel.dot(vel);
39 const auto c2 = (fdop / r) + fdopder;
40 const auto fnprime = c1 + c2 * dopfact;
41
42 // set output value
43 if (dt) {
44 *dt = fn / fnprime;
45 }
46
47 return ErrorCode::Success;
48}
49
50NVCC_HD_WARNING_DISABLE
51template<class Orbit>
52CUDA_HOSTDEV isce3::error::ErrorCode
53updateAztime(double* t, const Orbit& orbit, const isce3::core::Vec3& xyz,
54 isce3::core::LookSide side,
55 double rmin = std::numeric_limits<double>::quiet_NaN(),
56 double rmax = std::numeric_limits<double>::quiet_NaN())
57{
58 using namespace isce3::core;
59 using isce3::error::ErrorCode;
60
61 // compute azimuth time spacing for coarse grid search
62 constexpr static int num_aztime_test = 15;
63 const auto tstart = orbit.startTime();
64 const auto tend = orbit.endTime();
65 const auto dt = (tend - tstart) / (num_aztime_test - 1);
66
67 // find azimuth time with minimum valid range distance to target
68 double r_closest = 1e16;
69 double t_closest = -1000.;
70 for (int k = 0; k < num_aztime_test; ++k) {
71
72 const auto tt = tstart + k * dt;
73 if (tt < tstart or tt > tend) {
74 continue;
75 }
76
77 // interpolate orbit
78 Vec3 pos, vel;
79 orbit.interpolate(&pos, &vel, tt, OrbitInterpBorderMode::FillNaN);
80
81 // compute slant range
82 const auto rvec = xyz - pos;
83
84 // check look side (only first time)
85 if (k == 0) {
86 // (Left && positive) || (Right && negative)
87 if ((side == LookSide::Right) xor (rvec.cross(vel).dot(pos) > 0.)) {
88 return ErrorCode::WrongLookSide;
89 }
90 }
91
92 const auto r = rvec.norm();
93
94 // check validity
95 if (not std::isnan(rmin) and r < rmin) {
96 continue;
97 }
98 if (not std::isnan(rmax) and r > rmax) {
99 continue;
100 }
101
102 // update best guess
103 if (r < r_closest) {
104 r_closest = r;
105 t_closest = tt;
106 }
107 }
108
109 // if we did not find a good guess, use tmid as intial guess
110 *t = (t_closest < 0.) ? orbit.midTime() : t_closest;
111 return ErrorCode::Success;
112}
113
114NVCC_HD_WARNING_DISABLE
115template<class Orbit, class DopplerModel>
116CUDA_HOSTDEV isce3::error::ErrorCode
117geo2rdr(double* t, double* r, const isce3::core::Vec3& llh,
118 const isce3::core::Ellipsoid& ellipsoid, const Orbit& orbit,
119 const DopplerModel& doppler, double wvl, isce3::core::LookSide side,
120 double t0, const Geo2RdrParams& params)
121{
122 using namespace isce3::core;
123 using isce3::error::ErrorCode;
124
125 // convert LLH to ECEF
126 const auto xyz = ellipsoid.lonLatToXyz(llh);
127
128 // get initial azimuth time guess
129 if (t0 >= orbit.startTime() and t0 <= orbit.endTime()) {
130 *t = t0;
131 } else {
132 // perform a coarse grid search over the orbit's span for the azimuth
133 // time point that minimizes the range to the target
134 const auto status = updateAztime(t, orbit, xyz, side);
135 if (status != ErrorCode::Success) {
136 return status;
137 }
138 }
139
140 // Newton step, initialized to zero.
141 double dt = 0.0;
142
143 // begin iterations
144 for (int i = 0; i < params.maxiter; ++i) {
145 // apply Newton step here so that (r,t) are always consistent on return.
146 *t -= dt;
147
148 // interpolate orbit
149 Vec3 pos, vel;
150 orbit.interpolate(&pos, &vel, *t, OrbitInterpBorderMode::FillNaN);
151
152 // compute slant range from satellite to ground point
153 const auto rvec = xyz - pos;
154 *r = rvec.norm();
155
156 // Check look side (only first time)
157 if (i == 0) {
158 // (Left && positive) || (Right && negative)
159 if ((side == LookSide::Right) xor (rvec.cross(vel).dot(pos) > 0.)) {
160 return ErrorCode::WrongLookSide;
161 }
162 }
163
164 // update guess for azimuth time
165 const auto status = computeDopplerAztimeDiff(&dt, *t, *r, rvec, vel,
166 doppler, wvl, params.delta_range);
167 if (status != ErrorCode::Success) {
168 return status;
169 }
170
171 // check for convergence
172 if (std::abs(dt) < params.threshold) {
173 return ErrorCode::Success;
174 }
175 }
176
177 // if we reach this point, no convergence for specified threshold
178 return ErrorCode::FailedToConverge;
179}
180
181
182NVCC_HD_WARNING_DISABLE
183template<class Orbit, class DopplerModel>
184CUDA_HOSTDEV isce3::error::ErrorCode
185geo2rdr_bracket(double* aztime,
186 double* range, const isce3::core::Vec3& x, const Orbit& orbit,
187 const DopplerModel& doppler, double wavelength,
188 isce3::core::LookSide side, const Geo2RdrBracketParams& params)
189{
190 using namespace isce3::core;
191 using isce3::error::ErrorCode;
192
193 const double t0 = params.time_start.value_or([&]() {
194 if (doppler.haveData()) {
195 return std::max(orbit.startTime(), doppler.yStart());
196 }
197 return orbit.startTime();
198 }());
199 const double t1 = params.time_end.value_or([&]() {
200 if (doppler.haveData()) {
201 return std::min(orbit.endTime(), doppler.yEnd());
202 }
203 return orbit.endTime();
204 }());
205
206 // Platform position & velocity, and slant range vector
207 Vec3 xp, v, r;
208
209 // Calculate Doppler at time t and compute the difference with known
210 // Doppler centroid.
211 auto doppler_error = [&](double t) {
212 orbit.interpolate(&xp, &v, t, OrbitInterpBorderMode::FillNaN);
213 r = x - xp;
214 const double rnorm = r.norm();
215 double fd = doppler.eval(t, rnorm);
216 return 2.0 / wavelength * v.dot(r) / rnorm - fd;
217 };
218
219 const auto err = isce3::math::find_zero_brent(
220 t0, t1, doppler_error, params.tol_aztime, aztime);
221 if (err != ErrorCode::Success) {
222 return err;
223 }
224
225 // Compute range at aztime solution (may not be final iteration of solver).
226 orbit.interpolate(&xp, &v, *aztime, OrbitInterpBorderMode::FillNaN);
227 r = x - xp;
228 *range = r.norm();
229
230 // Save left/right check for the end in case orbit is curving, e.g. at pole.
231 // (Left && positive) || (Right && negative)
232 if ((side == LookSide::Right) ^ (r.cross(v).dot(xp) > 0)) {
233 return ErrorCode::WrongLookSide;
234 }
235 return ErrorCode::Success;
236}
237
238} // namespace isce3::geometry::detail
isce3::error::ErrorCode interpolate(Vec3 *position, Vec3 *velocity, double t, OrbitInterpBorderMode border_mode=OrbitInterpBorderMode::Error) const
Interpolate platform position and/or velocity.
Definition Orbit.cpp:71
double startTime() const
Time of first state vector relative to reference epoch (s)
Definition Orbit.h:128
double endTime() const
Time of last state vector relative to reference epoch (s)
Definition Orbit.h:134
double midTime() const
Time of center of orbit relative to reference epoch (s)
Definition Orbit.h:131
CUDA_HOSTDEV void lonLatToXyz(const cartesian_t &llh, cartesian_t &xyz) const
Transform WGS84 Lon/Lat/Hgt to ECEF xyz.
Definition Ellipsoid.h:178

Generated for ISCE3.0 by doxygen 1.13.2.