isce3 0.25.0
Loading...
Searching...
No Matches
Rdr2Geo.icc
1#include <cmath>
2#include <limits>
3
4#include <isce3/core/Basis.h>
5#include <isce3/core/Ellipsoid.h>
6#include <isce3/core/Orbit.h>
7#include <isce3/core/Pixel.h>
8#include <isce3/core/Vector.h>
9#include <isce3/math/RootFind1dBracket.h>
10
11namespace isce3 { namespace geometry { namespace detail {
12
13NVCC_HD_WARNING_DISABLE
14template<class Orbit, class DEMInterpolator>
15CUDA_HOSTDEV isce3::error::ErrorCode
16rdr2geo(isce3::core::Vec3* llh, double t, double r, double fd,
17 const Orbit& orbit, const DEMInterpolator& dem,
18 const isce3::core::Ellipsoid& ellipsoid, double wvl,
19 isce3::core::LookSide side, double h0, const Rdr2GeoParams& params)
20{
21 using namespace isce3::core;
22 using isce3::error::ErrorCode;
23
24 // interpolate orbit at target azimuth time
25 Vec3 pos, vel;
26 const auto status =
27 orbit.interpolate(&pos, &vel, t, OrbitInterpBorderMode::FillNaN);
28 if (status != ErrorCode::Success) {
29 return status;
30 }
31
32 // setup geocentric TCN basis
33 const auto tcnbasis = Basis(pos, vel);
34
35 // compute Doppler factor
36 const auto vmag = vel.norm();
37 const auto dopfact = 0.5 * wvl * fd * r / vmag;
38
39 const auto pixel = Pixel(r, dopfact, 0);
40 return rdr2geo(llh, pixel, tcnbasis, pos, vel, dem, ellipsoid, side, h0,
41 params);
42}
43
44NVCC_HD_WARNING_DISABLE
45template<class DEMInterpolator>
46CUDA_HOSTDEV isce3::error::ErrorCode
47rdr2geo(isce3::core::Vec3* llh, const isce3::core::Pixel& pixel,
48 const isce3::core::Basis& tcnbasis, const isce3::core::Vec3& pos,
49 const isce3::core::Vec3& vel, const DEMInterpolator& dem,
50 const isce3::core::Ellipsoid& ellipsoid, isce3::core::LookSide side,
51 double h0, const Rdr2GeoParams& params)
52{
53 using namespace isce3::core;
54 using isce3::error::ErrorCode;
55
56 // compute platform heading unit vector
57 const auto vhat = vel.normalized();
58
59 // unpack TCN basis vectors
60 const auto& that = tcnbasis.x0();
61 const auto& chat = tcnbasis.x1();
62 const auto& nhat = tcnbasis.x2();
63
64 // pre-compute TCN vector products
65 const auto ndotv = nhat.dot(vhat);
66 const auto vdott = vhat.dot(that);
67
68 // compute major & minor axes of ellipsoid
69 const auto major = ellipsoid.a();
70 const auto minor = major * std::sqrt(1. - ellipsoid.e2());
71
72 // setup orthonormal system at the nadir point
73 const auto sat_dist = pos.norm();
74 const auto eta = [&]() {
75 const auto x = pos[0] / major;
76 const auto y = pos[1] / major;
77 const auto z = pos[2] / minor;
78 return 1. / std::sqrt((x * x) + (y * y) + (z * z));
79 }();
80 const auto radius = eta * sat_dist;
81 const auto height = (1. - eta) * sat_dist;
82
83 // update function - given a target height estimate, compute a new target
84 // LLH estimate
85 auto updateLLH = [&](const double h) {
86 // compute angles
87 const auto a = sat_dist;
88 const auto b = radius + h;
89 const auto cos_theta = 0.5 * (a / pixel.range() + pixel.range() / a -
90 (b / a) * (b / pixel.range()));
91 const auto sin_theta = std::sqrt(1. - cos_theta * cos_theta);
92
93 // compute TCN scale factors
94 const auto gamma = pixel.range() * cos_theta;
95 const auto alpha = (pixel.dopfact() - gamma * ndotv) / vdott;
96 const auto beta = [&]() {
97 const auto x = pixel.range() * sin_theta;
98 const auto beta = std::sqrt((x * x) - (alpha * alpha));
99 return (side == LookSide::Right) ? beta : -beta;
100 }();
101
102 // compute vector from satellite to ground
103 const auto delta = alpha * that + beta * chat + gamma * nhat;
104
105 // estimate target LLH
106 const auto xyz = pos + delta;
107 return ellipsoid.xyzToLonLat(xyz);
108 };
109
110 // iterate
111 bool converged = false;
112 auto h = std::isnan(h0) ? height : h0;
113 Vec3 llh_old;
114 for (int i = 0; i < params.maxiter + params.extraiter; ++i) {
115
116 // near nadir test
117 if (height - h >= pixel.range()) {
118 break;
119 }
120
121 // estimate target LLH
122 auto llh_new = updateLLH(h);
123
124 // snap to interpolated DEM height at target lon/lat
125 llh_new[2] = dem.interpolateLonLat(llh_new[0], llh_new[1]);
126
127 // convert to ECEF coords
128 const auto xyz_new = ellipsoid.lonLatToXyz(llh_new);
129
130 // update target height estimate
131 h = xyz_new.norm() - radius;
132
133 // check for convergence
134 const auto r = (pos - xyz_new).norm();
135 const auto dr = std::abs(pixel.range() - r);
136 if (dr < params.threshold) {
137 converged = true;
138 break;
139 }
140
141 // in extra iterations, use average of new & old estimated target
142 // position
143 if (i > params.maxiter) {
144 const auto xyz_old = ellipsoid.lonLatToXyz(llh_old);
145 const auto xyz_avg = 0.5 * (xyz_old + xyz_new);
146 llh_new = ellipsoid.xyzToLonLat(xyz_avg);
147 h = xyz_avg.norm() - radius;
148 }
149
150 // save old estimate
151 llh_old = llh_new;
152 }
153
154 /*
155 * XXX this seems innocuous to me but causes a bunch of tests to fail
156 *
157 * // failed to converge - set output to NaN
158 * if (not converged) {
159 * constexpr static auto nan = std::numeric_limits<double>::quiet_NaN();
160 * *llh = {nan, nan, nan};
161 * return 0;
162 * }
163 */
164
165 // final computation - output points exactly at pixel range if converged
166 *llh = updateLLH(h);
167
168 return converged ? ErrorCode::Success : ErrorCode::FailedToConverge;
169}
170
171
172NVCC_HD_WARNING_DISABLE
173template<class Orbit, class DEMInterpolator>
174CUDA_HOSTDEV isce3::error::ErrorCode
175rdr2geo_bracket(isce3::core::Vec3* xyz,
176 double aztime, double slantRange, double doppler, const Orbit& orbit,
177 const DEMInterpolator& dem, const isce3::core::Ellipsoid& ellipsoid,
178 double wavelength, isce3::core::LookSide side,
179 const Rdr2GeoBracketParams& params)
180{
181 using namespace isce3::core;
182 using isce3::error::ErrorCode;
183
184 // Interpolate orbit to get radar position and velocity.
185 Vec3 radarXYZ, velocity;
186 const auto errCode = orbit.interpolate(&radarXYZ, &velocity, aztime);
187 if (errCode != ErrorCode::Success) {
188 return errCode;
189 }
190 const double speed = velocity.norm();
191
192 // Construct some useful basis vectors.
193 // For simplicity we'll use geocentric nadir (not geodetic),
194 // which determines our definition of look angle.
195 const Vec3 alongTrack = velocity / speed;
196 const Vec3 right = alongTrack.cross(radarXYZ).normalized();
197 const Vec3 down = alongTrack.cross(right);
198 const Vec3 horizontal = (side == LookSide::Right) ? right : -right;
199
200 // Convert Doppler into equivalent squint angle.
201 const double sinSquint = doppler * wavelength / (2 * speed);
202 // NOTE squint is in [-90, 90] by definition.
203 const double cosSquint = std::sqrt(1.0 - sinSquint * sinSquint);
204
205 // Doppler cone and range sphere intersect to make a circle with
206 // the following parameters.
207 const Vec3 center = radarXYZ + sinSquint * slantRange * alongTrack;
208 const double radius = cosSquint * slantRange;
209
210 // Parameterize points on this circle with an angle similar to look angle.
211 auto getXYZ = [&](double look) {
212 return center + radius * std::sin(look) * horizontal +
213 radius * std::cos(look) * down;
214 };
215
216 // Get ellipsoid associated with DEM.
217 // const auto epsg = dem.epsgCode();
218 // const Ellipsoid ellipsoid = makeProjection(epsg)->ellipsoid();
219 // TODO This API only available on CPU. For now take separate ellipsoid arg
220
221 // Now we just need to find the angle on this circle where it intersects
222 // the DEM. Create an error function we'll feed to a root finder.
223 auto dh = [&](double look) {
224 const Vec3 xyz = getXYZ(look);
225 Vec3 lonLatH;
226 ellipsoid.xyzToLonLat(xyz, lonLatH);
227 return lonLatH[2] - dem.interpolateLonLat(lonLatH[0], lonLatH[1]);
228 };
229
230 // Height error is bounded by arc length.
231 const double tolLook = params.tol_height / radius;
232
233 // Solve.
234 double lookSolution = 0.0;
235 const auto err = isce3::math::find_zero_brent(
236 params.look_min, params.look_max, dh, tolLook, &lookSolution);
237 if (err != ErrorCode::Success) {
238 return err;
239 }
240 *xyz = getXYZ(lookSolution);
241 return ErrorCode::Success;
242}
243
244}}} // namespace isce3::geometry::detail
double interpolateLonLat(double lon, double lat) const
Interpolate at a given longitude and latitude.
Definition DEMInterpolator.cpp:593
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
CUDA_HOSTDEV const Vec3 & x2() const
Return third basis vector.
Definition Basis.h:67
CUDA_HOSTDEV const Vec3 & x0() const
Return first basis vector.
Definition Basis.h:61
CUDA_HOSTDEV const Vec3 & x1() const
Return second basis vector.
Definition Basis.h:64
CUDA_HOSTDEV void xyzToLonLat(const cartesian_t &xyz, cartesian_t &llh) const
Transform ECEF xyz to Lon/Lat/Hgt.
Definition Ellipsoid.h:197
CUDA_HOSTDEV double a() const
Return semi-major axis.
Definition Ellipsoid.h:38
CUDA_HOSTDEV double e2() const
Return eccentricity^2.
Definition Ellipsoid.h:46
CUDA_HOSTDEV void lonLatToXyz(const cartesian_t &llh, cartesian_t &xyz) const
Transform WGS84 Lon/Lat/Hgt to ECEF xyz.
Definition Ellipsoid.h:178
The isce3::geometry namespace.
Definition boundingbox.h:15
base interpolator is an abstract base class
Definition BinarySearchFunc.cpp:5

Generated for ISCE3.0 by doxygen 1.13.2.