Skip to content

Commit

Permalink
Merge pull request isce-framework#2 from isce-3/develop
Browse files Browse the repository at this point in the history
Update from original
  • Loading branch information
jungkyoJung authored and GitHub Enterprise committed Nov 3, 2021
2 parents c07e937 + f9037d7 commit aa5b16a
Show file tree
Hide file tree
Showing 88 changed files with 2,910 additions and 1,598 deletions.
16 changes: 4 additions & 12 deletions cxx/isce3/Headers.cmake
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
set(HEADERS
antenna/detail/WinChirpRgCompPow.h
antenna/detail/WinChirpRgCompPow.icc
antenna/edge_method_cost_func.h
antenna/forward.h
antenna/ElPatternEst.h
antenna/geometryfunc.h
Expand All @@ -18,8 +19,6 @@ core/Baseline.h
core/Basis.h
core/Common.h
core/Constants.h
core/Cube.h
core/Cube.icc
core/DateTime.h
core/DenseMatrix.h
core/detail/BuildOrbit.h
Expand All @@ -41,7 +40,6 @@ core/LUT1d.h
core/LUT1d.icc
core/LUT2d.h
core/Matrix.h
core/Matrix.icc
core/Metadata.h
core/Orbit.h
core/Peg.h
Expand Down Expand Up @@ -125,18 +123,12 @@ io/IH5.icc
io/Raster.h
io/Raster.icc
io/Serialization.h
matchtemplate/ampcor/correlators/correlators.h
matchtemplate/ampcor/correlators/kernels.h
matchtemplate/ampcor/correlators/Sequential.h
matchtemplate/ampcor/correlators/Sequential.icc
matchtemplate/ampcor/dom/dom.h
matchtemplate/ampcor/dom/Raster.h
matchtemplate/ampcor/dom/Raster.icc
matchtemplate/ampcor/dom/SLC.h
matchtemplate/ampcor/dom/SLC.icc
math/Bessel.h
math/ComplexMultiply.h
math/detail/RootFind1dBase.h
math/polyfunc.h
math/RootFind1dNewton.h
math/RootFind1dSecant.h
math/Sinc.h
math/Sinc.icc
polsar/symmetrize.h
Expand Down
16 changes: 3 additions & 13 deletions cxx/isce3/Sources.cmake
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
set(SRCS
antenna/edge_method_cost_func.cpp
antenna/ElPatternEst.cpp
antenna/geometryfunc.cpp
core/Attitude.cpp
Expand Down Expand Up @@ -58,21 +59,10 @@ io/gdal/SpatialReference.cpp
io/IH5.cpp
io/IH5Dataset.cpp
io/Raster.cpp
matchtemplate/ampcor/correlators/c2r.cpp
matchtemplate/ampcor/correlators/correlate.cpp
matchtemplate/ampcor/correlators/detect.cpp
matchtemplate/ampcor/correlators/maxcor.cpp
matchtemplate/ampcor/correlators/migrate.cpp
matchtemplate/ampcor/correlators/nudge.cpp
matchtemplate/ampcor/correlators/offsets.cpp
matchtemplate/ampcor/correlators/r2c.cpp
matchtemplate/ampcor/correlators/refStats.cpp
matchtemplate/ampcor/correlators/sat.cpp
matchtemplate/ampcor/correlators/tgtStats.cpp
matchtemplate/ampcor/dom/Raster.cc
matchtemplate/ampcor/dom/SLC.cc
math/Bessel.cpp
math/polyfunc.cpp
math/RootFind1dNewton.cpp
math/RootFind1dSecant.cpp
polsar/symmetrize.cpp
product/GeoGridParameters.cpp
product/Product.cpp
Expand Down
1 change: 0 additions & 1 deletion cxx/isce3/antenna/detail/WinChirpRgCompPow.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
namespace isce3 { namespace antenna { namespace detail {

// Aliases, typedef:
// fuzzy naming convention by isce3::core::EMtarix module!!!
using RowMatrixXcf = isce3::core::EMatrix2D<std::complex<float>>;

// Functions:
Expand Down
150 changes: 150 additions & 0 deletions cxx/isce3/antenna/edge_method_cost_func.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#include <algorithm>
#include <cmath>
#include <vector>

#include <Eigen/Dense>

#include <isce3/antenna/edge_method_cost_func.h>
#include <isce3/except/Error.h>
#include <isce3/math/RootFind1dNewton.h>
#include <isce3/math/polyfunc.h>

namespace isce3 { namespace antenna {

std::tuple<double, double, bool, int> rollAngleOffsetFromEdge(
const poly1d_t& polyfit_echo, const poly1d_t& polyfit_ant,
const isce3::core::Linspace<double>& look_ang,
std::optional<poly1d_t> polyfit_weight)
{
// check the input arguments
if (polyfit_echo.order != 3 || polyfit_ant.order != 3)
throw isce3::except::InvalidArgument(ISCE_SRCINFO(),
"Requires 3rd-order poly-fit object for both "
"Echo and Antenna!");
constexpr double a_tol {1e-5};
if (std::abs(polyfit_echo.mean - polyfit_ant.mean) > a_tol ||
std::abs(polyfit_echo.norm - polyfit_ant.norm) > a_tol)
throw isce3::except::InvalidArgument(ISCE_SRCINFO(),
"Requires same (mean, std) for Echo and Antenna Poly1d obj!");

if (!(polyfit_echo.norm > 0.0))
throw isce3::except::InvalidArgument(ISCE_SRCINFO(),
"Requires positive std of Echo and Antenna Poly1d obj!");

if (polyfit_weight) {
if (polyfit_weight->order < 0)
throw isce3::except::InvalidArgument(ISCE_SRCINFO(),
"The order of polyfit for weights must be "
"at least 0 (constant weights)!");
if (!(polyfit_weight->norm > 0.0))
throw isce3::except::InvalidArgument(ISCE_SRCINFO(),
"Requires positive std of weight Poly1d obj!");
}

// create a copy polyfit objects "echo" and "ant" with zero mean and unit
// std
auto pf_echo_cp = polyfit_echo;
pf_echo_cp.mean = 0.0;
pf_echo_cp.norm = 1.0;
auto pf_ant_cp = polyfit_ant;
pf_ant_cp.mean = 0.0;
pf_ant_cp.norm = 1.0;

// declare and initialize a look angle vector
Eigen::ArrayXd lka_vec(look_ang.size());
for (int idx = 0; idx < look_ang.size(); ++idx)
lka_vec(idx) = look_ang[idx];

// create a weighting vector from look vector and weighting Poly1d
Eigen::ArrayXd wgt_vec;
if (polyfit_weight) {
Eigen::Map<Eigen::ArrayXd> wgt_coef(
polyfit_weight->coeffs.data(), polyfit_weight->coeffs.size());
wgt_vec = isce3::math::polyval(
wgt_coef, lka_vec, polyfit_weight->mean, polyfit_weight->norm);
// normalize power in dB
wgt_vec -= wgt_vec.maxCoeff();
// convert from dB to linear power scale
wgt_vec = Eigen::pow(10, 0.1 * wgt_vec);
}
// centralized and scaled the look vector based on mean/std of the echo
// Poly1d to be used for both antenna and echo in the cost function.
lka_vec -= polyfit_echo.mean;
const auto std_inv = 1.0 / polyfit_echo.norm;
lka_vec *= std_inv;

// form some derivatives used in the cost function
auto pf_echo_der = pf_echo_cp.derivative();
auto pf_ant_der = pf_ant_cp.derivative();
auto pf_ant_der2 = pf_ant_der.derivative();
// create a memmap of the coeff for the first and second derivatives
Eigen::Map<Eigen::ArrayXd> coef_ant_der(
pf_ant_der.coeffs.data(), pf_ant_der.coeffs.size());
Eigen::Map<Eigen::ArrayXd> coef_ant_der2(
pf_ant_der2.coeffs.data(), pf_ant_der2.coeffs.size());
Eigen::Map<Eigen::ArrayXd> coef_echo_der(
pf_echo_der.coeffs.data(), pf_echo_der.coeffs.size());
// form some arrays over scaled look angles for diff of first derivatives
// and for second derivative
auto ant_echo_der_dif_vec =
isce3::math::polyval(coef_ant_der - coef_echo_der, lka_vec);
auto ant_der2_vec = isce3::math::polyval(coef_ant_der2, lka_vec);

// build cost function in the form of Poly1d object (3th order polynimal!)
auto cf_pf = isce3::core::Poly1d(3, 0.0, 1.0);
// fill up the coeff for the derivative of the WMSE cost function:
// cost(ofs) = pf_wgt*(pf_echo_der(el) - pf_ant_der(el + ofs))**2
// See section 1.1 of the cited reference.
if (polyfit_weight) {
auto tmp1 = wgt_vec * ant_echo_der_dif_vec;
auto tmp2 = wgt_vec * ant_der2_vec;
cf_pf.coeffs[0] = (tmp1 * ant_der2_vec).sum();
cf_pf.coeffs[1] = (tmp2 * ant_der2_vec).sum() +
6 * pf_ant_cp.coeffs[3] * tmp1.sum();
cf_pf.coeffs[2] = 9 * pf_ant_cp.coeffs[3] * tmp2.sum();
cf_pf.coeffs[3] =
18 * pf_ant_cp.coeffs[3] * pf_ant_cp.coeffs[3] * wgt_vec.sum();
} else // no weighting
{
cf_pf.coeffs[0] = (ant_echo_der_dif_vec * ant_der2_vec).sum();
cf_pf.coeffs[1] = ant_der2_vec.square().sum() +
6 * pf_ant_cp.coeffs[3] * ant_echo_der_dif_vec.sum();
cf_pf.coeffs[2] = 9 * pf_ant_cp.coeffs[3] * ant_der2_vec.sum();
cf_pf.coeffs[3] = 18 * pf_ant_cp.coeffs[3] * pf_ant_cp.coeffs[3] *
look_ang.size();
}
// form Root finding object
auto rf_obj =
isce3::math::RootFind1dNewton(1e-4, 20, look_ang.spacing() / 10.);
// solve for the root/roll offset via Newton
auto [roll, f_val, flag, n_iter] = rf_obj.root(cf_pf);
// scale back the roll angle by std of original poly1d object
roll *= polyfit_echo.norm;

return {roll, f_val, flag, n_iter};
}

std::tuple<double, double, bool, int> rollAngleOffsetFromEdge(
const poly1d_t& polyfit_echo, const poly1d_t& polyfit_ant,
double look_ang_near, double look_ang_far, double look_ang_prec,
std::optional<poly1d_t> polyfit_weight)
{
if (!(look_ang_near > 0.0 && look_ang_far > 0.0 && look_ang_prec > 0.0))
throw isce3::except::InvalidArgument(ISCE_SRCINFO(),
"All look angles values must be positive numbers!");
if (look_ang_near >= (look_ang_far - look_ang_prec))
throw isce3::except::InvalidArgument(ISCE_SRCINFO(),
"Near-range look angle shall be smaller than "
"far one by at least one prec!");

const auto ang_size =
static_cast<int>((look_ang_far - look_ang_near) / look_ang_prec) +
1;
auto look_ang = isce3::core::Linspace<double>::from_interval(
look_ang_near, look_ang_far, ang_size);

return rollAngleOffsetFromEdge(
polyfit_echo, polyfit_ant, look_ang, polyfit_weight);
}

}} // namespace isce3::antenna
100 changes: 100 additions & 0 deletions cxx/isce3/antenna/edge_method_cost_func.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/** @file edge_method_cost_func.h
* Cost functions used in EL antenna pointing estimation via edge method
*/
#pragma once

#include <optional>
#include <tuple>

#include <isce3/core/Linspace.h>
#include <isce3/core/Poly1d.h>

/** @namespace isce3::antenna */
namespace isce3 { namespace antenna {

// Aliases
using poly1d_t = isce3::core::Poly1d;

/**
* Estimate roll angle offset via edge method from poly-fitted
* power patterns obtained from echo raw data and antenna pattern.
* The cost function is solved via Newton method and final solution
* is the weighted average of individual solution within look
* (off-nadir) angles [near, far] with desired angle precision all
* defined by isce3 Linspace.
* See equations for cost function in section 1.1 of the reference
* @cite EdgeMethodElPointDoc
* The only difference is that the look angles are in (rad) rather than in
* (deg). Note that the respective magnitudes for both echo and antenna can be
* either 2-way or 1-way power patterns.
* @param[in] polyfit_echo isce3 Poly1d object for polyfitted magnitude
* of either range compressed (preferred) or raw echo data.
* It must be third-order polynomial of relative magnitude/power in (dB)
* as a function of look angle in (rad)
* @param[in] polyfit_ant isce3 Poly1d object for antenna EL power pattern.
* It must be third-order polynomial of relative magnitude/power in (dB)
* as a function of look angle in (rad).
* It must have the same mean and std as that of "polyfit_echo"!
* @param[in] look_ang isce3 Linspace object to cover desired range of
* look angles (rad) with desired precision/spacing.
* @param[in] polyfit_weight (optional) isce3 Poly1d object for weightings used
* in final weighted averaged of individual solutions over desired look angle
* coverage. It shall represent relative magnitude/power in (dB) as a function
* of look angle in (rad).
* The order of the polynomial must be at least 0 (constant weights).
* @return roll angle offset (rad)
* Note that the roll offset shall be added to EL angles in antenna frame
* to align EL power pattern from antenna to the one extracted from echo given
* the cost function optimized for offset applied to polyfitted antenna data.
* @return max cost function value among all iterations
* @return overall convergence flag (true or false)
* @return max number of iterations among all iterations
* @exception InvalidArgument
*/
std::tuple<double, double, bool, int> rollAngleOffsetFromEdge(
const poly1d_t& polyfit_echo, const poly1d_t& polyfit_ant,
const isce3::core::Linspace<double>& look_ang,
std::optional<poly1d_t> polyfit_weight = {});

/**
* Estimate roll angle offset via edge method from poly-fitted
* power patterns obtained from echo raw data and antenna pattern.
* The cost function is solved via Newton method and final solution
* is the weighted average of individual solution within look
* (off-nadir) angles [near, far] with desired angle precision "look_ang_prec".
* See equations for cost function in section 1.1 of the reference
* @cite EdgeMethodElPointDoc
* The only difference is that the look angles are in (rad) rather than in
* (deg). Note that the respective magnitudes for both echo and antenna can be
* either 2-way or 1-way power patterns.
* @param[in] polyfit_echo isce3 Poly1d object for polyfitted magnitude
* of either range compressed (preferred) or raw echo data.
* It must be third-order polynomial of relative magnitude/power in (dB)
* as a function of look angle in (rad)
* @param[in] polyfit_ant isce3 Poly1d object for antenna EL power pattern.
* It must be third-order polynomial of relative magnitude/power in (dB)
* as a function of look angle in (rad).
* It must have the same mean and std as that of "polyfit_echo"!
* @param[in] look_ang_near look angle for near range in (rad)
* @param[in] look_ang_far look angle for far range in (rad)
* @param[in] look_ang_prec look angle precision/resolution in (rad)
* @param[in] polyfit_weight (optional) isce3 Poly1d object for weightings used
* in final weighted averaged of individual solutions over desired look angle
* coverage. It shall represent relative magnitude/power in (dB) as a function
* of look angle in (rad).
* The order of the polynomial must be at least 0 (constant weights).
* @return roll angle offset (rad)
* Note that the roll offset shall be added to EL angles in antenna frame
* to align EL power pattern from antenna to the one extracted from echo given
* the cost function optimized for offset applied to polyfitted antenna data.
* @return max cost function value among all iterations
* @return overall convergence flag (true or false)
* @return max number of iterations among all iterations
* @exception InvalidArgument
*/
std::tuple<double, double, bool, int> rollAngleOffsetFromEdge(
const poly1d_t& polyfit_echo, const poly1d_t& polyfit_ant,
double look_ang_near, double look_ang_far, double look_ang_prec,
std::optional<poly1d_t> polyfit_weight = {});

}} // namespace isce3::antenna
1 change: 0 additions & 1 deletion cxx/isce3/antenna/geometryfunc.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ namespace isce3 { namespace antenna {
* @exception InvalidArgument, RuntimeError
* @cite ReeTechDesDoc
*/

std::tuple<double, double, bool> ant2rgdop(double el_theta, double az_phi,
const isce3::core::Vec3& pos_ecef, const isce3::core::Vec3& vel_ecef,
const isce3::core::Quaternion& quat, double wavelength,
Expand Down
Loading

0 comments on commit aa5b16a

Please sign in to comment.