Hi Luc,
Here is an example I made up, both the dump and the code that produced it. Changing the value of maxLine
passed to the inverse location method will make the test case pass or fail. I can work towards making the margin settable via the RuggedBuilder
.
Here is the test case, which ended up being rather long:
/** Illustrative test case where refraction can cause errors. */
@Test
public void testRefraction() {
// setup
System.setProperty(DataProvidersManager.OREKIT_DATA_PATH, "/home/ward/eop/");
DumpManager.activate(new File("refraction.dump"));
Frame ecf = FramesFactory.getITRF(IERSConventions.IERS_2010, true);
RuggedBuilder builder = new RuggedBuilder();
builder.setEllipsoid(ReferenceEllipsoid.getWgs84(ecf));
MultiLayerModel atmosphere = new MultiLayerModel(builder.getEllipsoid());
builder.setRefractionCorrection(atmosphere);
builder.setLightTimeCorrection(true);
builder.setAberrationOfLightCorrection(true);
builder.setAlgorithm(AlgorithmId.IGNORE_DEM_USE_ELLIPSOID);
AbsoluteDate start = AbsoluteDate.ARBITRARY_EPOCH;
AbsoluteDate end = start.shiftedBy(10);
AbsoluteDate middle = start.shiftedBy(end.durationFrom(start) / 2);
builder.setTimeSpan(start, end, 1e-3, 1e-3);
final double h = 500e3;
Vector3D p = new Vector3D(6378137 + h, 0, 0);
Vector3D v = Vector3D.ZERO;
List<TimeStampedPVCoordinates> pvs = Arrays.asList(
new TimeStampedPVCoordinates(start, p, v),
new TimeStampedPVCoordinates(end, p, v));
Rotation rotation = new Rotation(Vector3D.MINUS_I, Vector3D.MINUS_K, Vector3D.PLUS_K, Vector3D.PLUS_I);
TimeStampedAngularCoordinates attitude =
new TimeStampedAngularCoordinates(
middle, rotation,
Vector3D.PLUS_I.scalarMultiply(0.1), Vector3D.ZERO);
List<TimeStampedAngularCoordinates> attitudes = Arrays.asList(
attitude.shiftedBy(start.durationFrom(attitude.getDate())),
attitude,
attitude.shiftedBy(end.durationFrom(attitude.getDate())));
builder.setTrajectory(ecf,
pvs, 2, CartesianDerivativesFilter.USE_P,
attitudes, 2, AngularDerivativesFilter.USE_R);
final double iFov = 1e-6;
TimeDependentLOS los = new TimeDependentLOS() {
@Override
public int getNbPixels() {
return 1000;
}
@Override
public Vector3D getLOS(int index, AbsoluteDate date) {
// simplistic pinhole camera, assumes small angle
final double center = getNbPixels() / 2.0;
final double x = (index - center);
final double los = x * iFov;
return new Vector3D(los, 0, 1);
}
@Override
public <T extends Derivative<T>> FieldVector3D<T> getLOSDerivatives(
int index,
AbsoluteDate date,
DerivativeGenerator<T> generator) {
throw new UnsupportedOperationException("not implemented");
}
@Override
public Stream<ParameterDriver> getParametersDrivers() {
return Stream.empty();
}
};
LineSensor sensor = new LineSensor("sensor",
new LinearLineDatation(middle, 0, 1000),
Vector3D.ZERO,
los);
builder.addLineSensor(sensor);
Rugged rugged = builder.build();
Vector3D losVector = new Vector3D(-1, 0.1 * 5, 500e-6);
NormalizedGeodeticPoint guess = rugged.getEllipsoid().pointOnGround(p, losVector, 0);
NormalizedGeodeticPoint correctedGp = atmosphere.applyCorrection(p, losVector, guess, rugged.getAlgorithm());
Vector3D correctedP = rugged.getEllipsoid().transform(correctedGp);
double correction = Vector3D.angle(losVector, correctedP.subtract(p));
System.out.format("Max refraction correction: %s rad, %s px\n", correction, correction / iFov);
final int maxLine = 4999; // works with 4500, fails with 4999
GeodeticPoint point = rugged.directLocation(sensor.getName(), 0)[0];
System.out.println("(0, 0) is " + point);
point = rugged.directLocation(sensor.getName(), 0)[500];
System.out.println("(0, 500) is " + point);
point = rugged.directLocation(sensor.getName(), 0)[999];
System.out.println("(0, 1000) is " + point);
point = rugged.directLocation(sensor.getName(), 1000)[500];
System.out.println("(1000, 500) is " + point);
SensorPixel pixel = rugged.inverseLocation(sensor.getName(), point, 0, maxLine);
System.out.format("%s is (%s, %s)\n", point, pixel.getLineNumber(), pixel.getPixelNumber());
point = rugged.directLocation(sensor.getName(), 2000)[500];
System.out.println("(2000, 500) is " + point);
pixel = rugged.inverseLocation(sensor.getName(), point, 0, maxLine);
System.out.format("%s is (%s, %s)\n", point, pixel.getLineNumber(), pixel.getPixelNumber());
point = rugged.directLocation(sensor.getName(), 4000)[500];
System.out.println("(2000, 500) is " + point);
pixel = rugged.inverseLocation(sensor.getName(), point, 0, maxLine);
System.out.format("%s is (%s, %s)\n", point, pixel.getLineNumber(), pixel.getPixelNumber());
DumpManager.deactivate();
}
Here is the output from when I run it:
Max refraction correction: 3.036616178093026E-6 rad, 3.036616178093026 px
(0, 0) is {lat: 0.0022609104 deg, lon: 0 deg, alt: 0}
(0, 500) is {lat: 0 deg, lon: 0 deg, alt: 0}
(0, 1000) is {lat: -0.0022563886 deg, lon: 0 deg, alt: 0}
(1000, 500) is {lat: -0.0860411513 deg, lon: 0.5038531532 deg, alt: 0}
org.orekit.rugged.errors.RuggedException: range between min line 0 and max line 4,999 is invalid
at org.orekit.rugged.api.Rugged.computeInverseLocOnGridWithoutAtmosphere(Rugged.java:824)
at org.orekit.rugged.api.Rugged.findSensorPixelWithAtmosphere(Rugged.java:708)
at org.orekit.rugged.api.Rugged.inverseLocation(Rugged.java:539)
refraction.dump (1.9 MB)
Regards,
Evan