Skip to content
Snippets Groups Projects
Commit f3b5cca3 authored by Luc Maisonobe's avatar Luc Maisonobe
Browse files

Sensor line-of-sight for pixels is now time-dependent.

This allows using polynomial calibration models provided by the image
quality fitting process.
parent 1d349350
No related branches found
No related tags found
No related merge requests found
Showing with 214 additions and 125 deletions
/* Copyright 2013-2014 CS Systèmes d'Information
* Licensed to CS Systèmes d'Information (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.rugged.api;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.orekit.time.AbsoluteDate;
/** Line-of-sight which does not depends on time.
* @see LineSensor
* @author Luc Maisonobe
*/
public class FixedLOS implements TimeDependentLOS {
/** Fixed direction for los. */
final Vector3D los;
/** Simple constructor.
* @param los fixed direction for the line of sight
*/
public FixedLOS(final Vector3D los) {
this.los = los;
}
/** {@inheritDoc}} */
public Vector3D getLOS(AbsoluteDate date) {
return los;
}
}
......@@ -39,7 +39,7 @@ public class LineSensor {
private final Vector3D position;
/** Pixels lines-of-sight. */
private final Vector3D[] x;
private final List<TimeDependentLOS> los;
/** Simple constructor.
* @param name name of the sensor
......@@ -48,17 +48,12 @@ public class LineSensor {
* @param datationModel datation model
*/
public LineSensor(final String name, final LineDatation datationModel,
final Vector3D position, final List<Vector3D> los) {
final Vector3D position, final List<TimeDependentLOS> los) {
this.name = name;
this.datationModel = datationModel;
this.position = position;
// normalize lines-of-sight
this.x = new Vector3D[los.size()];
for (int i = 0; i < los.size(); ++i) {
x[i] = los.get(i).normalize();
}
this.los = los;
}
......@@ -73,15 +68,16 @@ public class LineSensor {
* @return number of pixels
*/
public int getNbPixels() {
return x.length;
return los.size();
}
/** Get the pixel normalized line-of-sight.
/** Get the pixel normalized line-of-sight at some date.
* @param date current date
* @param i pixel index (must be between 0 and {@link #getNbPixels()}
* @return pixel normalized line-of-sight
*/
public Vector3D getLos(final int i) {
return x[i];
public Vector3D getLos(final AbsoluteDate date, final int i) {
return los.get(i).getLOS(date).normalize();
}
/** Get the date.
......
......@@ -742,7 +742,7 @@ public class Rugged {
final GeodeticPoint[] gp = new GeodeticPoint[sensor.getNbPixels()];
for (int i = 0; i < sensor.getNbPixels(); ++i) {
final Vector3D obsLInert = scToInert.transformVector(sensor.getLos(i));
final Vector3D obsLInert = scToInert.transformVector(sensor.getLos(date, i));
final Vector3D lInert;
if (aberrationOfLightCorrection) {
// apply aberration of light correction
......@@ -765,7 +765,7 @@ public class Rugged {
if (lightTimeCorrection) {
// compute DEM intersection with light time correction
final Vector3D sP = approximate.transformPosition(sensor.getPosition());
final Vector3D sL = approximate.transformVector(sensor.getLos(i));
final Vector3D sL = approximate.transformVector(sensor.getLos(date, i));
final Vector3D eP1 = ellipsoid.transform(ellipsoid.pointOnGround(sP, sL, 0.0));
final double deltaT1 = eP1.distance(sP) / Constants.SPEED_OF_LIGHT;
final Transform shifted1 = inertToBody.shiftedBy(-deltaT1);
......@@ -1005,7 +1005,7 @@ public class Rugged {
new SensorPixelCrossing(sensor, planeCrossing.getMeanPlaneNormal(),
crossingResult.getTargetDirection().toVector3D(),
MAX_EVAL, COARSE_INVERSE_LOCALIZATION_ACCURACY);
final double coarsePixel = pixelCrossing.locatePixel();
final double coarsePixel = pixelCrossing.locatePixel(crossingResult.getDate());
if (Double.isNaN(coarsePixel)) {
// target is out of search interval
return null;
......@@ -1014,10 +1014,9 @@ public class Rugged {
// fix line by considering the closest pixel exact position and line-of-sight
// (this pixel might point towards a direction slightly above or below the mean sensor plane)
final int lowIndex = FastMath.max(0, FastMath.min(sensor.getNbPixels() - 2, (int) FastMath.floor(coarsePixel)));
final Vector3D lowLOS = sensor.getLos(lowIndex);
final Vector3D highLOS = sensor.getLos(lowIndex + 1);
final Vector3D lowLOS = sensor.getLos(crossingResult.getDate(), lowIndex);
final Vector3D highLOS = sensor.getLos(crossingResult.getDate(), lowIndex + 1);
final Vector3D localZ = Vector3D.crossProduct(lowLOS, highLOS);
final Vector3D localY = Vector3D.crossProduct(localZ, lowLOS);
final DerivativeStructure beta = FieldVector3D.angle(crossingResult.getTargetDirection(), localZ);
final double deltaL = (0.5 * FastMath.PI - beta.getValue()) / beta.getPartialDerivative(1);
final double fixedLine = crossingResult.getLine() + deltaL;
......@@ -1025,11 +1024,17 @@ public class Rugged {
crossingResult.getTargetDirection().getY().taylor(deltaL),
crossingResult.getTargetDirection().getZ().taylor(deltaL)).normalize();
// fix neighbouring pixels
final AbsoluteDate fixedDate = sensor.getDate(fixedLine);
final Vector3D fixedX = sensor.getLos(fixedDate, lowIndex);
final Vector3D fixedZ = Vector3D.crossProduct(fixedX, sensor.getLos(fixedDate, lowIndex + 1));
final Vector3D fixedY = Vector3D.crossProduct(fixedZ, fixedX);
// fix pixel
final double pixelWidth = FastMath.atan2(Vector3D.dotProduct(highLOS, localY),
Vector3D.dotProduct(highLOS, lowLOS));
final double alpha = FastMath.atan2(Vector3D.dotProduct(fixedDirection, localY),
Vector3D.dotProduct(fixedDirection, lowLOS));
final double pixelWidth = FastMath.atan2(Vector3D.dotProduct(highLOS, fixedY),
Vector3D.dotProduct(highLOS, fixedX));
final double alpha = FastMath.atan2(Vector3D.dotProduct(fixedDirection, fixedY),
Vector3D.dotProduct(fixedDirection, fixedX));
final double fixedPixel = lowIndex + alpha / pixelWidth;
return new SensorPixel(fixedLine, fixedPixel);
......
......@@ -101,16 +101,17 @@ class SensorMeanPlaneCrossing {
this.accuracy = accuracy;
this.scToBody = scToBody;
this.midLine = 0.5 * (minLine + maxLine);
final AbsoluteDate midDate = sensor.getDate(midLine);
this.midBodyToInert = scToBody.getBodyToInertial(midDate);
this.midScToInert = scToBody.getScToInertial(midDate);
this.midLine = 0.5 * (minLine + maxLine);
final AbsoluteDate midDate = sensor.getDate(midLine);
this.midBodyToInert = scToBody.getBodyToInertial(midDate);
this.midScToInert = scToBody.getScToInertial(midDate);
this.meanPlaneNormal = computeMeanPlaneNormal();
this.meanPlaneNormal = computeMeanPlaneNormal(midDate);
}
/** Compute the plane containing origin that best fits viewing directions point cloud.
* @param midDate middle date
* <p>
* The normal is oriented such traversing pixels in increasing indices
* order corresponds is consistent with trigonometric order (i.e.
......@@ -118,14 +119,14 @@ class SensorMeanPlaneCrossing {
* </p>
* @return normal of the mean plane
*/
private Vector3D computeMeanPlaneNormal() {
private Vector3D computeMeanPlaneNormal(final AbsoluteDate midDate) {
// build a centered data matrix
// (for each viewing direction, we add both the direction and its
// opposite, thus ensuring the plane will contain origin)
final RealMatrix matrix = MatrixUtils.createRealMatrix(3, 2 * sensor.getNbPixels());
for (int i = 0; i < sensor.getNbPixels(); ++i) {
final Vector3D l = sensor.getLos(i);
final Vector3D l = sensor.getLos(midDate, i);
matrix.setEntry(0, 2 * i, l.getX());
matrix.setEntry(1, 2 * i, l.getY());
matrix.setEntry(2, 2 * i, l.getZ());
......@@ -143,8 +144,8 @@ class SensorMeanPlaneCrossing {
final Vector3D singularVector = new Vector3D(svd.getU().getColumn(2)).normalize();
// check rotation order
final Vector3D first = sensor.getLos(0);
final Vector3D last = sensor.getLos(sensor.getNbPixels() - 1);
final Vector3D first = sensor.getLos(midDate, 0);
final Vector3D last = sensor.getLos(midDate, sensor.getNbPixels() - 1);
if (Vector3D.dotProduct(singularVector, Vector3D.crossProduct(first, last)) >= 0) {
return singularVector;
} else {
......@@ -182,6 +183,9 @@ class SensorMeanPlaneCrossing {
/** Container for mean plane crossing result. */
public static class CrossingResult {
/** Crossing date. */
private final AbsoluteDate crossingDate;
/** Crossing line. */
private final double crossingLine;
......@@ -189,15 +193,24 @@ class SensorMeanPlaneCrossing {
private final FieldVector3D<DerivativeStructure> targetDirection;
/** Simple constructor.
* @param crossingDate crossing date
* @param crossingLine crossing line
* @param targetDirection target direction in spacecraft frame
*/
private CrossingResult(final double crossingLine,
private CrossingResult(final AbsoluteDate crossingDate, final double crossingLine,
final FieldVector3D<DerivativeStructure> targetDirection) {
this.crossingDate = crossingDate;
this.crossingLine = crossingLine;
this.targetDirection = targetDirection;
}
/** Get the crossing date.
* @return crossing date
*/
public AbsoluteDate getDate() {
return crossingDate;
}
/** Get the crossing line.
* @return crossing line
*/
......@@ -246,7 +259,7 @@ class SensorMeanPlaneCrossing {
final double deltaL = (0.5 * FastMath.PI - beta.getValue()) / beta.getPartialDerivative(1);
if (FastMath.abs(deltaL) <= accuracy) {
// return immediately, without doing any additional evaluation!
return new CrossingResult(crossingLine, targetDirection);
return new CrossingResult(sensor.getDate(crossingLine), crossingLine, targetDirection);
}
crossingLine += deltaL;
......
......@@ -24,6 +24,7 @@ import org.apache.commons.math3.exception.TooManyEvaluationsException;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.apache.commons.math3.util.FastMath;
import org.orekit.errors.OrekitExceptionWrapper;
import org.orekit.time.AbsoluteDate;
/** Class devoted to locate where ground point crosses a sensor line.
* <p>
......@@ -65,11 +66,12 @@ class SensorPixelCrossing {
}
/** Locate pixel along sensor line.
* @param date current date
* @return pixel location ({@code Double.NaN} if the first and last
* pixels of the line do not bracket a location)
* @exception RuggedException if the maximum number of evaluations is exceeded
*/
public double locatePixel() throws RuggedException {
public double locatePixel(final AbsoluteDate date) throws RuggedException {
try {
// set up function evaluating to 0.0 where target matches pixel
......@@ -77,7 +79,7 @@ class SensorPixelCrossing {
/** {@inheritDoc} */
@Override
public double value(final double x) throws OrekitExceptionWrapper {
return Vector3D.angle(cross, getLOS(x)) - 0.5 * FastMath.PI;
return Vector3D.angle(cross, getLOS(date, x)) - 0.5 * FastMath.PI;
}
};
......@@ -95,17 +97,19 @@ class SensorPixelCrossing {
}
/** Interpolate sensor pixels at some pixel index.
* @param date current date
* @param x pixel index
* @return interpolated direction for specified index
*/
private Vector3D getLOS(final double x) {
private Vector3D getLOS(final AbsoluteDate date, final double x) {
// find surrounding pixels
final int iInf = FastMath.max(0, FastMath.min(sensor.getNbPixels() - 2, (int) FastMath.floor(x)));
final int iSup = iInf + 1;
// interpolate
return new Vector3D(iSup - x, sensor.getLos(iInf), x - iInf, sensor.getLos(iSup)).normalize();
return new Vector3D(iSup - x, sensor.getLos(date, iInf),
x - iInf, sensor.getLos(date, iSup)).normalize();
}
......
/* Copyright 2013-2014 CS Systèmes d'Information
* Licensed to CS Systèmes d'Information (CS) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* CS licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.orekit.rugged.api;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.orekit.time.AbsoluteDate;
/** Interface representing a line-of-sight which depends on time.
* @see LineSensor
* @author Luc Maisonobe
*/
public interface TimeDependentLOS {
/** Get the line of sight for a given date.
* @param date date
* @return line of sight
*/
Vector3D getLOS(AbsoluteDate date);
}
This diff is collapsed.
......@@ -66,10 +66,10 @@ public class SensorMeanPlaneCrossingTest {
final Vector3D cross = Vector3D.crossProduct(normal, fovCenter);
// build lists of pixels regularly spread on a perfect plane
final List<Vector3D> los = new ArrayList<Vector3D>();
final List<TimeDependentLOS> los = new ArrayList<TimeDependentLOS>();
for (int i = -1000; i <= 1000; ++i) {
final double alpha = i * 0.17 / 1000;
los.add(new Vector3D(FastMath.cos(alpha), fovCenter, FastMath.sin(alpha), cross));
los.add(new FixedLOS(new Vector3D(FastMath.cos(alpha), fovCenter, FastMath.sin(alpha), cross)));
}
final LineSensor sensor = new LineSensor("perfect line",
......@@ -96,7 +96,7 @@ public class SensorMeanPlaneCrossingTest {
final Vector3D cross = Vector3D.crossProduct(normal, fovCenter);
// build lists of pixels regularly spread on a perfect plane
final List<Vector3D> los = new ArrayList<Vector3D>();
final List<TimeDependentLOS> los = new ArrayList<TimeDependentLOS>();
for (int i = -1000; i <= 1000; ++i) {
final double alpha = i * 0.17 / 10 + 1.0e-5 * random.nextDouble();
final double delta = 1.0e-5 * random.nextDouble();
......@@ -104,7 +104,7 @@ public class SensorMeanPlaneCrossingTest {
final double sA = FastMath.sin(alpha);
final double cD = FastMath.cos(delta);
final double sD = FastMath.sin(delta);
los.add(new Vector3D(cA * cD, fovCenter, sA * cD, cross, sD, normal));
los.add(new FixedLOS(new Vector3D(cA * cD, fovCenter, sA * cD, cross, sD, normal)));
}
final LineSensor sensor = new LineSensor("noisy line",
......
......@@ -61,7 +61,7 @@
class LineSensor
IntersectionAlgorithm "1" <--o Rugged : delegate DEM intersection
ExtendedEllipsoid <-- Rugged : convert geodetic points
Rugged --> LineSensor : getLOS(pixel)
Rugged --> LineSensor : getLOS(date, pixel)
Rugged --> LineSensor : getDate(line)
SpacecraftToObservedBody <-- Rugged : convert positions/directions
}
......
No preview for this file type
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment