From 70eda0af910b2733dcf904bb859b7938e5a50716 Mon Sep 17 00:00:00 2001 From: Jesse Mapel <jmapel@usgs.gov> Date: Tue, 28 Apr 2020 15:49:47 -0700 Subject: [PATCH] More stubs (#285) * Added actual methods * Made default build type release * Position and Velocity API done * Fixes from review --- CMakeLists.txt | 8 + include/usgscsm/UsgsAstroSarSensorModel.h | 8 +- src/UsgsAstroSarSensorModel.cpp | 268 ++++++++++++++++++---- tests/SarTests.cpp | 2 +- 4 files changed, 242 insertions(+), 44 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 98a82ae..94cacb3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,14 @@ include(GNUInstallDirs) set(CMAKE_CXX_STANDARD 11) +# Set a default build type if none was specified +set(default_build_type "Release") +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to '${default_build_type}' as none was specified.") + set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE + STRING "Choose the type of build." FORCE) +endif() + # Optional build or link against CSM option (BUILD_CSM "Build the CSM library" ON) if(BUILD_CSM) diff --git a/include/usgscsm/UsgsAstroSarSensorModel.h b/include/usgscsm/UsgsAstroSarSensorModel.h index 118f9f4..af79e94 100644 --- a/include/usgscsm/UsgsAstroSarSensorModel.h +++ b/include/usgscsm/UsgsAstroSarSensorModel.h @@ -195,6 +195,12 @@ class UsgsAstroSarSensorModel : public csm::RasterGM, virtual public csm::Settab virtual void setEllipsoid(const csm::Ellipsoid &ellipsoid); + //////////////////// + // Helper methods // + //////////////////// + void determineSensorCovarianceInImageSpace( + csm::EcefCoord &gp, + double sensor_cov[4]) const; double dopplerShift(csm::EcefCoord groundPt, double tolerance) const; double slantRange(csm::EcefCoord surfPt, double time) const; @@ -204,7 +210,7 @@ class UsgsAstroSarSensorModel : public csm::RasterGM, virtual public csm::Settab double groundRangeToSlantRange(double groundRange, const std::vector<double> &coeffs) const; csm::EcefVector getSpacecraftPosition(double time) const; - csm::EcefVector getSpacecraftVelocity(double time) const; + csm::EcefVector getSunPosition(const double imageTime) const; std::vector<double> getRangeCoefficients(double time) const; //////////////////////////// diff --git a/src/UsgsAstroSarSensorModel.cpp b/src/UsgsAstroSarSensorModel.cpp index c6c2bf6..7209180 100644 --- a/src/UsgsAstroSarSensorModel.cpp +++ b/src/UsgsAstroSarSensorModel.cpp @@ -231,12 +231,12 @@ void UsgsAstroSarSensorModel::replaceModelState(const string& argState) m_nSamples = stateJson["m_nSamples"]; m_exposureDuration = stateJson["m_exposureDuration"]; m_scaledPixelWidth = stateJson["m_scaledPixelWidth"]; - std::string lookStr = stateJson["m_lookDirection"]; + std::string lookStr = stateJson["m_lookDirection"]; if (lookStr.compare("right") == 0 ) { - m_lookDirection = UsgsAstroSarSensorModel::RIGHT; + m_lookDirection = UsgsAstroSarSensorModel::RIGHT; } else if (lookStr.compare("left") == 0) { - m_lookDirection = UsgsAstroSarSensorModel::LEFT; + m_lookDirection = UsgsAstroSarSensorModel::LEFT; } else { std::string message = "Could not determine look direction from state"; @@ -363,7 +363,7 @@ double UsgsAstroSarSensorModel::dopplerShift( csm::EcefVector groundVec(groundPt.x ,groundPt.y, groundPt.z); std::function<double(double)> dopplerShiftFunction = [this, groundVec](double time) { csm::EcefVector spacecraftPosition = getSpacecraftPosition(time); - csm::EcefVector spacecraftVelocity = getSpacecraftVelocity(time); + csm::EcefVector spacecraftVelocity = getSensorVelocity(time); csm::EcefVector lookVector = spacecraftPosition - groundVec; double slantRange = norm(lookVector); @@ -427,9 +427,61 @@ csm::ImageCoordCovar UsgsAstroSarSensorModel::groundToImage( double* achievedPrecision, csm::WarningList* warnings) const { - return csm::ImageCoordCovar(0.0, 0.0, - 1.0, 0.0, - 1.0); + // Ground to image with error propagation + // Compute corresponding image point + csm::EcefCoord gp(groundPt); + + csm::ImageCoord ip = groundToImage(gp, desiredPrecision, achievedPrecision, warnings); + csm::ImageCoordCovar result(ip.line, ip.samp); + + // Compute partials ls wrt XYZ + std::vector<double> prt(6, 0.0); + prt = computeGroundPartials(groundPt); + + // Error propagation + double ltx, lty, ltz; + double stx, sty, stz; + ltx = + prt[0] * groundPt.covariance[0] + + prt[1] * groundPt.covariance[3] + + prt[2] * groundPt.covariance[6]; + lty = + prt[0] * groundPt.covariance[1] + + prt[1] * groundPt.covariance[4] + + prt[2] * groundPt.covariance[7]; + ltz = + prt[0] * groundPt.covariance[2] + + prt[1] * groundPt.covariance[5] + + prt[2] * groundPt.covariance[8]; + stx = + prt[3] * groundPt.covariance[0] + + prt[4] * groundPt.covariance[3] + + prt[5] * groundPt.covariance[6]; + sty = + prt[3] * groundPt.covariance[1] + + prt[4] * groundPt.covariance[4] + + prt[5] * groundPt.covariance[7]; + stz = + prt[3] * groundPt.covariance[2] + + prt[4] * groundPt.covariance[5] + + prt[5] * groundPt.covariance[8]; + + double gp_cov[4]; // Input gp cov in image space + gp_cov[0] = ltx * prt[0] + lty * prt[1] + ltz * prt[2]; + gp_cov[1] = ltx * prt[3] + lty * prt[4] + ltz * prt[5]; + gp_cov[2] = stx * prt[0] + sty * prt[1] + stz * prt[2]; + gp_cov[3] = stx * prt[3] + sty * prt[4] + stz * prt[5]; + + std::vector<double> unmodeled_cov = getUnmodeledError(ip); + double sensor_cov[4]; // sensor cov in image space + determineSensorCovarianceInImageSpace(gp, sensor_cov); + + result.covariance[0] = gp_cov[0] + unmodeled_cov[0] + sensor_cov[0]; + result.covariance[1] = gp_cov[1] + unmodeled_cov[1] + sensor_cov[1]; + result.covariance[2] = gp_cov[2] + unmodeled_cov[2] + sensor_cov[2]; + result.covariance[3] = gp_cov[3] + unmodeled_cov[3] + sensor_cov[3]; + + return result; } csm::EcefCoord UsgsAstroSarSensorModel::imageToGround( @@ -447,7 +499,7 @@ csm::EcefCoord UsgsAstroSarSensorModel::imageToGround( // Compute the in-track, cross-track, nadir, coordinate system to solve in csm::EcefVector spacecraftPosition = getSpacecraftPosition(time); double positionMag = norm(spacecraftPosition); - csm::EcefVector spacecraftVelocity = getSpacecraftVelocity(time); + csm::EcefVector spacecraftVelocity = getSensorVelocity(time); // In-track unit vector csm::EcefVector vHat = normalized(spacecraftVelocity); // Nadir unit vector @@ -479,10 +531,77 @@ csm::EcefCoordCovar UsgsAstroSarSensorModel::imageToGround( double* achievedPrecision, csm::WarningList* warnings) const { - return csm::EcefCoordCovar(0.0, 0.0, 0.0, - 1.0, 0.0, 0.0, - 1.0, 0.0, - 1.0); + // Image to ground with error propagation + // Use numerical partials + const double DELTA_IMAGE = 1.0; + const double DELTA_GROUND = m_scaledPixelWidth; + csm::ImageCoord ip(imagePt.line, imagePt.samp); + + csm::EcefCoord gp = imageToGround(ip, height, desiredPrecision, achievedPrecision, warnings); + + // Compute numerical partials xyz wrt to lsh + ip.line = imagePt.line + DELTA_IMAGE; + ip.samp = imagePt.samp; + csm::EcefCoord gpl = imageToGround(ip, height, desiredPrecision); + double xpl = (gpl.x - gp.x) / DELTA_IMAGE; + double ypl = (gpl.y - gp.y) / DELTA_IMAGE; + double zpl = (gpl.z - gp.z) / DELTA_IMAGE; + + ip.line = imagePt.line; + ip.samp = imagePt.samp + DELTA_IMAGE; + csm::EcefCoord gps = imageToGround(ip, height, desiredPrecision); + double xps = (gps.x - gp.x) / DELTA_IMAGE; + double yps = (gps.y - gp.y) / DELTA_IMAGE; + double zps = (gps.z - gp.z) / DELTA_IMAGE; + + ip.line = imagePt.line; + ip.samp = imagePt.samp; // +DELTA_IMAGE; + csm::EcefCoord gph = imageToGround(ip, height + DELTA_GROUND, desiredPrecision); + double xph = (gph.x - gp.x) / DELTA_GROUND; + double yph = (gph.y - gp.y) / DELTA_GROUND; + double zph = (gph.z - gp.z) / DELTA_GROUND; + + // Convert sensor covariance to image space + double sCov[4]; + determineSensorCovarianceInImageSpace(gp, sCov); + + std::vector<double> unmod = getUnmodeledError(imagePt); + + double iCov[4]; + iCov[0] = imagePt.covariance[0] + sCov[0] + unmod[0]; + iCov[1] = imagePt.covariance[1] + sCov[1] + unmod[1]; + iCov[2] = imagePt.covariance[2] + sCov[2] + unmod[2]; + iCov[3] = imagePt.covariance[3] + sCov[3] + unmod[3]; + + // Temporary matrix product + double t00, t01, t02, t10, t11, t12, t20, t21, t22; + t00 = xpl * iCov[0] + xps * iCov[2]; + t01 = xpl * iCov[1] + xps * iCov[3]; + t02 = xph * heightVariance; + t10 = ypl * iCov[0] + yps * iCov[2]; + t11 = ypl * iCov[1] + yps * iCov[3]; + t12 = yph * heightVariance; + t20 = zpl * iCov[0] + zps * iCov[2]; + t21 = zpl * iCov[1] + zps * iCov[3]; + t22 = zph * heightVariance; + + // Ground covariance + csm::EcefCoordCovar result; + result.x = gp.x; + result.y = gp.y; + result.z = gp.z; + + result.covariance[0] = t00 * xpl + t01 * xps + t02 * xph; + result.covariance[1] = t00 * ypl + t01 * yps + t02 * yph; + result.covariance[2] = t00 * zpl + t01 * zps + t02 * zph; + result.covariance[3] = t10 * xpl + t11 * xps + t12 * xph; + result.covariance[4] = t10 * ypl + t11 * yps + t12 * yph; + result.covariance[5] = t10 * zpl + t11 * zps + t12 * zph; + result.covariance[6] = t20 * xpl + t21 * xps + t22 * xph; + result.covariance[7] = t20 * ypl + t21 * yps + t22 * yph; + result.covariance[8] = t20 * zpl + t21 * zps + t22 * zph; + + return result; } csm::EcefLocus UsgsAstroSarSensorModel::imageToProximateImagingLocus( @@ -513,47 +632,72 @@ csm::ImageCoord UsgsAstroSarSensorModel::getImageStart() const csm::ImageVector UsgsAstroSarSensorModel::getImageSize() const { - return csm::ImageVector(0.0, 0.0); + return csm::ImageVector(m_nLines, m_nSamples); } pair<csm::ImageCoord, csm::ImageCoord> UsgsAstroSarSensorModel::getValidImageRange() const { - return make_pair(csm::ImageCoord(0.0, 0.0), csm::ImageCoord(0.0, 0.0)); + csm::ImageCoord start = getImageStart(); + csm::ImageVector size = getImageSize(); + return make_pair(start, csm::ImageCoord(start.line + size.line, start.samp + size.samp)); } pair<double, double> UsgsAstroSarSensorModel::getValidHeightRange() const { - return make_pair(0.0, 0.0); + return make_pair(m_minElevation, m_maxElevation); } csm::EcefVector UsgsAstroSarSensorModel::getIlluminationDirection(const csm::EcefCoord& groundPt) const { - return csm::EcefVector(0.0, 0.0, 0.0); + csm::EcefVector groundVec(groundPt.x, groundPt.y, groundPt.z); + csm::EcefVector sunPosition = getSunPosition(getImageTime(groundToImage(groundPt))); + csm::EcefVector illuminationDirection = normalized(groundVec - sunPosition); + return illuminationDirection; } double UsgsAstroSarSensorModel::getImageTime(const csm::ImageCoord& imagePt) const { - return 0.0; + return m_startingEphemerisTime + (imagePt.line - 0.5) * m_exposureDuration; } csm::EcefCoord UsgsAstroSarSensorModel::getSensorPosition(const csm::ImageCoord& imagePt) const { - return csm::EcefCoord(0.0, 0.0, 0.0); + double time = getImageTime(imagePt); + return getSensorPosition(time); } csm::EcefCoord UsgsAstroSarSensorModel::getSensorPosition(double time) const { - return csm::EcefCoord(0.0, 0.0, 0.0); + csm::EcefVector sensorVector = getSpacecraftPosition(time); + return csm::EcefCoord(sensorVector.x, sensorVector.y, sensorVector.z); } csm::EcefVector UsgsAstroSarSensorModel::getSensorVelocity(const csm::ImageCoord& imagePt) const { - return csm::EcefVector(0.0, 0.0, 0.0); + double time = getImageTime(imagePt); + return getSensorVelocity(time); } csm::EcefVector UsgsAstroSarSensorModel::getSensorVelocity(double time) const { - return csm::EcefVector(0.0, 0.0, 0.0); + int numVelocities = m_velocities.size(); + csm::EcefVector spacecraftVelocity = csm::EcefVector(); + + // If there are multiple positions, use Lagrange interpolation + if ((numVelocities/3) > 1) { + double velocity[3]; + lagrangeInterp(numVelocities/3, &m_velocities[0], m_t0Ephem, m_dtEphem, + time, 3, 8, velocity); + spacecraftVelocity.x = velocity[0]; + spacecraftVelocity.y = velocity[1]; + spacecraftVelocity.z = velocity[2]; + } + else { + spacecraftVelocity.x = m_velocities[0]; + spacecraftVelocity.y = m_velocities[1]; + spacecraftVelocity.z = m_velocities[2]; + } + return spacecraftVelocity; } csm::RasterGM::SensorPartials UsgsAstroSarSensorModel::computeSensorPartials( @@ -823,6 +967,32 @@ void UsgsAstroSarSensorModel::setEllipsoid(const csm::Ellipsoid &ellipsoid) m_minorAxis = ellipsoid.getSemiMinorRadius(); } +void UsgsAstroSarSensorModel::determineSensorCovarianceInImageSpace( + csm::EcefCoord &gp, + double sensor_cov[4] ) const +{ + int i, j, totalAdjParams; + totalAdjParams = getNumParameters(); + + std::vector<csm::RasterGM::SensorPartials> sensor_partials = computeAllSensorPartials(gp); + + sensor_cov[0] = 0.0; + sensor_cov[1] = 0.0; + sensor_cov[2] = 0.0; + sensor_cov[3] = 0.0; + + for (i = 0; i < totalAdjParams; i++) + { + for (j = 0; j < totalAdjParams; j++) + { + sensor_cov[0] += sensor_partials[i].first * getParameterCovariance(i, j) * sensor_partials[j].first; + sensor_cov[1] += sensor_partials[i].second * getParameterCovariance(i, j) * sensor_partials[j].first; + sensor_cov[2] += sensor_partials[i].first * getParameterCovariance(i, j) * sensor_partials[j].second; + sensor_cov[3] += sensor_partials[i].second * getParameterCovariance(i, j) * sensor_partials[j].second; + } + } +} + csm::EcefVector UsgsAstroSarSensorModel::getSpacecraftPosition(double time) const{ int numPositions = m_positions.size(); csm::EcefVector spacecraftPosition = csm::EcefVector(); @@ -845,27 +1015,6 @@ csm::EcefVector UsgsAstroSarSensorModel::getSpacecraftPosition(double time) cons return spacecraftPosition; } -csm::EcefVector UsgsAstroSarSensorModel::getSpacecraftVelocity(double time) const { - int numVelocities = m_velocities.size(); - csm::EcefVector spacecraftVelocity = csm::EcefVector(); - - // If there are multiple positions, use Lagrange interpolation - if ((numVelocities/3) > 1) { - double velocity[3]; - lagrangeInterp(numVelocities/3, &m_velocities[0], m_t0Ephem, m_dtEphem, - time, 3, 8, velocity); - spacecraftVelocity.x = velocity[0]; - spacecraftVelocity.y = velocity[1]; - spacecraftVelocity.z = velocity[2]; - } - else { - spacecraftVelocity.x = m_velocities[0]; - spacecraftVelocity.y = m_velocities[1]; - spacecraftVelocity.z = m_velocities[2]; - } - return spacecraftVelocity; -} - std::vector<double> UsgsAstroSarSensorModel::getRangeCoefficients(double time) const { int numCoeffs = m_scaleConversionCoefficients.size(); @@ -890,3 +1039,38 @@ std::vector<double> UsgsAstroSarSensorModel::getRangeCoefficients(double time) c } return interpCoeffs; } + +csm::EcefVector UsgsAstroSarSensorModel::getSunPosition(const double imageTime) const +{ + + int numSunPositions = m_sunPosition.size(); + int numSunVelocities = m_sunVelocity.size(); + csm::EcefVector sunPosition = csm::EcefVector(); + + // If there are multiple positions, use Lagrange interpolation + if ((numSunPositions/3) > 1) { + double sunPos[3]; + double endTime = m_t0Ephem + m_nLines * m_exposureDuration; + double sun_dtEphem = (endTime - m_t0Ephem) / (numSunPositions/3); + lagrangeInterp(numSunPositions/3, &m_sunPosition[0], m_t0Ephem, sun_dtEphem, + imageTime, 3, 8, sunPos); + sunPosition.x = sunPos[0]; + sunPosition.y = sunPos[1]; + sunPosition.z = sunPos[2]; + } + else if ((numSunVelocities/3) >= 1){ + // If there is one position triple with at least one velocity triple + // then the illumination direction is calculated via linear extrapolation. + sunPosition.x = (imageTime * m_sunVelocity[0] + m_sunPosition[0]); + sunPosition.y = (imageTime * m_sunVelocity[1] + m_sunPosition[1]); + sunPosition.z = (imageTime * m_sunVelocity[2] + m_sunPosition[2]); + } + else { + // If there is one position triple with no velocity triple, then the + // illumination direction is the difference of the original vectors. + sunPosition.x = m_sunPosition[0]; + sunPosition.y = m_sunPosition[1]; + sunPosition.z = m_sunPosition[2]; + } + return sunPosition; +} diff --git a/tests/SarTests.cpp b/tests/SarTests.cpp index 5cff6a0..a8279c7 100644 --- a/tests/SarTests.cpp +++ b/tests/SarTests.cpp @@ -68,7 +68,7 @@ TEST_F(SarSensorModel, spacecraftPosition) { } TEST_F(SarSensorModel, spacecraftVelocity) { - csm::EcefVector velocity = sensorModel->getSpacecraftVelocity(-0.0025); + csm::EcefVector velocity = sensorModel->getSensorVelocity(-0.0025); EXPECT_NEAR(velocity.x, 0.00000000e+00, 1e-8); EXPECT_NEAR(velocity.y, 0.00000000e+00, 1e-8); EXPECT_NEAR(velocity.z, -3.73740000e+06, 1e-8); -- GitLab