From c511030648b5a8ea00b6b32a2fe180b95e75836b Mon Sep 17 00:00:00 2001
From: Luc Maisonobe <luc@orekit.org>
Date: Tue, 16 Aug 2016 18:29:21 +0200
Subject: [PATCH] Replaced the ad-hoc parameters with Orekit ParameterDriver.

The ParameterDriver class has been introduced in Orekit for
the orbit determination feature.
---
 .../java/org/orekit/rugged/api/Rugged.java    |  14 +-
 .../orekit/rugged/errors/DumpReplayer.java    |  37 ++--
 .../orekit/rugged/linesensor/LineSensor.java  | 110 +++++++++++-
 .../linesensor/SensorMeanPlaneCrossing.java   |   8 +-
 .../linesensor/SensorPixelCrossing.java       |   4 +-
 .../org/orekit/rugged/los/FixedRotation.java  | 115 ++++++------
 .../org/orekit/rugged/los/LOSBuilder.java     | 167 +++++++-----------
 .../org/orekit/rugged/los/LOSTransform.java   |  12 +-
 .../orekit/rugged/los/PolynomialRotation.java | 138 ++++++++-------
 .../orekit/rugged/los/TimeDependentLOS.java   |  25 +--
 .../los/TimeIndependentLOSTransform.java      |  12 +-
 .../rugged/utils/ExtendedParameterDriver.java |  85 +++++++++
 .../orekit/rugged/utils/ParameterType.java    |  32 ----
 .../orekit/rugged/utils/ParametricModel.java  |  56 ------
 src/site/xdoc/changes.xml                     |   4 +
 .../org/orekit/rugged/api/RuggedTest.java     |   4 +-
 .../orekit/rugged/errors/DumpManagerTest.java |   2 +-
 17 files changed, 455 insertions(+), 370 deletions(-)
 create mode 100644 src/main/java/org/orekit/rugged/utils/ExtendedParameterDriver.java
 delete mode 100644 src/main/java/org/orekit/rugged/utils/ParameterType.java
 delete mode 100644 src/main/java/org/orekit/rugged/utils/ParametricModel.java

diff --git a/src/main/java/org/orekit/rugged/api/Rugged.java b/src/main/java/org/orekit/rugged/api/Rugged.java
index 60218048..59950a68 100644
--- a/src/main/java/org/orekit/rugged/api/Rugged.java
+++ b/src/main/java/org/orekit/rugged/api/Rugged.java
@@ -212,10 +212,10 @@ public class Rugged {
         final GeodeticPoint[] gp = new GeodeticPoint[sensor.getNbPixels()];
         for (int i = 0; i < sensor.getNbPixels(); ++i) {
 
-            DumpManager.dumpDirectLocation(date, sensor.getPosition(), sensor.getLos(date, i),
+            DumpManager.dumpDirectLocation(date, sensor.getPosition(), sensor.getLOS(date, i),
                                            lightTimeCorrection, aberrationOfLightCorrection);
 
-            final Vector3D obsLInert = scToInert.transformVector(sensor.getLos(date, i));
+            final Vector3D obsLInert = scToInert.transformVector(sensor.getLOS(date, i));
             final Vector3D lInert;
             if (aberrationOfLightCorrection) {
                 // apply aberration of light correction
@@ -238,7 +238,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(date, 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);
@@ -528,8 +528,8 @@ 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(crossingResult.getDate(), lowIndex);
-        final Vector3D highLOS         = sensor.getLos(crossingResult.getDate(), 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 DerivativeStructure beta = FieldVector3D.angle(crossingResult.getTargetDirection(), localZ);
         final double   deltaL          = (0.5 * FastMath.PI - beta.getValue()) / beta.getPartialDerivative(1);
@@ -540,8 +540,8 @@ public class Rugged {
 
         // 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 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
diff --git a/src/main/java/org/orekit/rugged/errors/DumpReplayer.java b/src/main/java/org/orekit/rugged/errors/DumpReplayer.java
index 73819945..0e1506c1 100644
--- a/src/main/java/org/orekit/rugged/errors/DumpReplayer.java
+++ b/src/main/java/org/orekit/rugged/errors/DumpReplayer.java
@@ -40,7 +40,9 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.NavigableMap;
+import java.util.Optional;
 import java.util.TreeMap;
+import java.util.stream.Stream;
 
 import org.orekit.bodies.GeodeticPoint;
 import org.orekit.bodies.OneAxisEllipsoid;
@@ -60,6 +62,7 @@ import org.orekit.rugged.linesensor.SensorPixel;
 import org.orekit.rugged.los.TimeDependentLOS;
 import org.orekit.rugged.raster.TileUpdater;
 import org.orekit.rugged.raster.UpdatableTile;
+import org.orekit.rugged.utils.ExtendedParameterDriver;
 import org.orekit.rugged.utils.SpacecraftToObservedBody;
 import org.orekit.time.AbsoluteDate;
 import org.orekit.time.TimeScalesFactory;
@@ -1129,24 +1132,6 @@ public class DumpReplayer {
             this.rates    = new ArrayList<Pair<Double, Double>>();
         }
 
-        /** {@inheritDoc} */
-        @Override
-        public int getNbEstimatedParameters() {
-            return 0;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void getEstimatedParameters(final double[] parameters, final int start, final int length)
-            throws RuggedException {
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void setEstimatedParameters(final double[] parameters, final int start, final int length)
-            throws RuggedException {
-        }
-
         /** Set the mean place finder.
          * @param meanPlane mean plane finder
          */
@@ -1229,11 +1214,13 @@ public class DumpReplayer {
 
         /** {@inheritDoc} */
         @Override
-        public FieldVector3D<DerivativeStructure> getLOS(final int index, final AbsoluteDate date, final double[] parameters) {
+        public FieldVector3D<DerivativeStructure> getLOSDerivatives(final int index, final AbsoluteDate date) {
+            final Optional<ExtendedParameterDriver> first = getExtendedParametersDrivers().findFirst();
+            final int nbEstimated = first.isPresent() ? first.get().getNbEstimated() : 0;
             final Vector3D los = getLOS(index, date);
-            return new FieldVector3D<DerivativeStructure>(new DerivativeStructure(parameters.length, 1, los.getX()),
-                                                          new DerivativeStructure(parameters.length, 1, los.getY()),
-                                                          new DerivativeStructure(parameters.length, 1, los.getZ()));
+            return new FieldVector3D<DerivativeStructure>(new DerivativeStructure(nbEstimated, 1, los.getX()),
+                                                          new DerivativeStructure(nbEstimated, 1, los.getY()),
+                                                          new DerivativeStructure(nbEstimated, 1, los.getZ()));
         }
 
         /** Set a datation pair.
@@ -1349,6 +1336,12 @@ public class DumpReplayer {
 
         }
 
+        /** {@inheritDoc} */
+        @Override
+        public Stream<ExtendedParameterDriver> getExtendedParametersDrivers() {
+            return Stream.<ExtendedParameterDriver>empty();
+        }
+
     }
 
     /** Local class for handling already parsed mean plane data. */
diff --git a/src/main/java/org/orekit/rugged/linesensor/LineSensor.java b/src/main/java/org/orekit/rugged/linesensor/LineSensor.java
index d00389df..88aa9137 100644
--- a/src/main/java/org/orekit/rugged/linesensor/LineSensor.java
+++ b/src/main/java/org/orekit/rugged/linesensor/LineSensor.java
@@ -16,17 +16,34 @@
  */
 package org.orekit.rugged.linesensor;
 
+import java.util.stream.Stream;
+
+import org.hipparchus.analysis.differentiation.DerivativeStructure;
+import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
 import org.hipparchus.geometry.euclidean.threed.Vector3D;
+import org.hipparchus.util.FastMath;
+import org.orekit.errors.OrekitException;
 import org.orekit.rugged.errors.DumpManager;
 import org.orekit.rugged.errors.RuggedException;
 import org.orekit.rugged.los.TimeDependentLOS;
+import org.orekit.rugged.utils.ExtendedParameterDriver;
 import org.orekit.time.AbsoluteDate;
+import org.orekit.utils.ParameterDriver;
+import org.orekit.utils.ParameterObserver;
 
 /** Line sensor model.
  * @author Luc Maisonobe
  */
 public class LineSensor {
 
+    /** Parameters scaling factor.
+     * <p>
+     * We use a power of 2 to avoid numeric noise introduction
+     * in the multiplications/divisions sequences.
+     * </p>
+     */
+    private final double SCALE = FastMath.scalb(1.0, -3);
+
     /** Name of the sensor. */
     private final String name;
 
@@ -34,11 +51,23 @@ public class LineSensor {
     private final LineDatation datationModel;
 
     /** Sensor position. */
-    private final Vector3D position;
+    private Vector3D position;
+
+    /** Sensor position, with derivatives. */
+    private FieldVector3D<DerivativeStructure> positionDS;
 
     /** Pixels lines-of-sight. */
     private final TimeDependentLOS los;
 
+    /** Driver for the sensor position parameter along X. */
+    private final ExtendedParameterDriver xPos;
+
+    /** Driver for the sensor position parameter along Y. */
+    private final ExtendedParameterDriver yPos;
+
+    /** Driver for the sensor position parameter along Z. */
+    private final ExtendedParameterDriver zPos;
+
     /** Simple constructor.
      * @param name name of the sensor
      * @param datationModel datation model
@@ -51,9 +80,32 @@ public class LineSensor {
 
         this.name          = name;
         this.datationModel = datationModel;
-        this.position      = position;
         this.los           = los;
 
+        final ParameterObserver resettingObserver = new ParameterObserver() {
+            /** {@inheritDoc} */
+            @Override
+            public void valueChanged(final double previousValue, final ParameterDriver driver) {
+                LineSensor.this.position   = null;
+                LineSensor.this.positionDS = null;
+            }
+        };
+
+        try {
+            xPos = new ExtendedParameterDriver(name + "-X", position.getX(), SCALE,
+                                               Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
+            xPos.addObserver(resettingObserver);
+            yPos = new ExtendedParameterDriver(name + "-Y", position.getY(), SCALE,
+                                               Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
+            yPos.addObserver(resettingObserver);
+            zPos = new ExtendedParameterDriver(name + "-Z", position.getZ(), SCALE,
+                                               Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
+            zPos.addObserver(resettingObserver);
+        } catch (OrekitException oe) {
+            // this should never happen
+            throw RuggedException.createInternalError(oe);
+        }
+
     }
 
     /** Get the name of the sensor.
@@ -70,19 +122,38 @@ public class LineSensor {
         return los.getNbPixels();
     }
 
+    /** Get the drivers for LOS parameters.
+     * @return drivers for LOS parameters
+     * @since 2.0
+     */
+    public Stream<ExtendedParameterDriver> getExtendedParametersDrivers() {
+        return Stream.<ExtendedParameterDriver>concat(Stream.of(xPos, yPos, zPos),
+                                                      los.getExtendedParametersDrivers());
+    }
+
     /** 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()} - 1
      * @return pixel normalized line-of-sight
      * @exception RuggedException if date cannot be handled
      */
-    public Vector3D getLos(final AbsoluteDate date, final int i)
+    public Vector3D getLOS(final AbsoluteDate date, final int i)
         throws RuggedException {
         final Vector3D l = los.getLOS(i, date);
         DumpManager.dumpSensorLOS(this, date, i, l);
         return l;
     }
 
+    /** Get the pixel normalized line-of-sight at some date,
+     * and their derivatives with respect to estimated parameters.
+     * @param date current date
+     * @param i pixel index (must be between 0 and {@link #getNbPixels()} - 1
+     * @return pixel normalized line-of-sight
+     */
+    public FieldVector3D<DerivativeStructure> getLOSDerivatives(final AbsoluteDate date, final int i) {
+        return los.getLOSDerivatives(i, date);
+    }
+
     /** Get the date.
      * @param lineNumber line number
      * @return date corresponding to line number
@@ -121,7 +192,40 @@ public class LineSensor {
      * @return position
      */
     public Vector3D getPosition() {
+        if (position == null) {
+            // lazy evaluation of the position
+            position = new Vector3D(xPos.getValue(), yPos.getValue(), zPos.getValue());
+        }
         return position;
     }
 
+    /** Get the sensor position,
+     * and its derivatives with respect to estimated parameters.
+     * @return position
+     */
+    public FieldVector3D<DerivativeStructure> getPositionDerivatives() {
+        if (positionDS == null) {
+            // lazy evaluation of the position
+            positionDS = new FieldVector3D<DerivativeStructure>(getCoordinate(xPos),
+                                                                getCoordinate(yPos),
+                                                                getCoordinate(zPos));
+        }
+        return positionDS;
+    }
+
+    /** Get a coordinate and its derivatives.
+     * @param driver coordinate driver
+     * @return coordinate value and its derivatives
+     */
+    private DerivativeStructure getCoordinate(final ExtendedParameterDriver driver) {
+        final double value = driver.getValue();
+        if (driver.isSelected()) {
+            // the x coordinate of the sensor is estimated
+            return new DerivativeStructure(driver.getNbEstimated(), 1, driver.getIndex(), value);
+        } else {
+            // the x coordinate of the sensor is not estimated
+            return new DerivativeStructure(driver.getNbEstimated(), 1, value);
+        }
+    }
+
 }
diff --git a/src/main/java/org/orekit/rugged/linesensor/SensorMeanPlaneCrossing.java b/src/main/java/org/orekit/rugged/linesensor/SensorMeanPlaneCrossing.java
index 3726f442..e6f523f5 100644
--- a/src/main/java/org/orekit/rugged/linesensor/SensorMeanPlaneCrossing.java
+++ b/src/main/java/org/orekit/rugged/linesensor/SensorMeanPlaneCrossing.java
@@ -116,7 +116,7 @@ public class SensorMeanPlaneCrossing {
         throws RuggedException {
         this(sensor, scToBody, minLine, maxLine, lightTimeCorrection, aberrationOfLightCorrection,
              maxEval, accuracy, computeMeanPlaneNormal(sensor, minLine, maxLine),
-             Stream.<CrossingResult>builder().build());
+             Stream.<CrossingResult>empty());
     }
 
     /** Simple constructor.
@@ -188,7 +188,7 @@ public class SensorMeanPlaneCrossing {
         //  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(midDate, 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());
@@ -206,8 +206,8 @@ public class SensorMeanPlaneCrossing {
         final Vector3D singularVector = new Vector3D(svd.getU().getColumn(2)).normalize();
 
         // check rotation order
-        final Vector3D first = sensor.getLos(midDate, 0);
-        final Vector3D last  = sensor.getLos(midDate, 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 {
diff --git a/src/main/java/org/orekit/rugged/linesensor/SensorPixelCrossing.java b/src/main/java/org/orekit/rugged/linesensor/SensorPixelCrossing.java
index 35c80ac5..d6dfa516 100644
--- a/src/main/java/org/orekit/rugged/linesensor/SensorPixelCrossing.java
+++ b/src/main/java/org/orekit/rugged/linesensor/SensorPixelCrossing.java
@@ -117,8 +117,8 @@ public class SensorPixelCrossing {
         final int iSup = iInf + 1;
 
         // interpolate
-        return new Vector3D(iSup - x, sensor.getLos(date, iInf),
-                            x - iInf, sensor.getLos(date, iSup)).normalize();
+        return new Vector3D(iSup - x, sensor.getLOS(date, iInf),
+                            x - iInf, sensor.getLOS(date, iSup)).normalize();
 
     }
 
diff --git a/src/main/java/org/orekit/rugged/los/FixedRotation.java b/src/main/java/org/orekit/rugged/los/FixedRotation.java
index c8bdd104..18eaa927 100644
--- a/src/main/java/org/orekit/rugged/los/FixedRotation.java
+++ b/src/main/java/org/orekit/rugged/los/FixedRotation.java
@@ -16,15 +16,20 @@
  */
 package org.orekit.rugged.los;
 
+import java.util.stream.Stream;
+
 import org.hipparchus.analysis.differentiation.DerivativeStructure;
 import org.hipparchus.geometry.euclidean.threed.FieldRotation;
 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
 import org.hipparchus.geometry.euclidean.threed.Rotation;
 import org.hipparchus.geometry.euclidean.threed.RotationConvention;
 import org.hipparchus.geometry.euclidean.threed.Vector3D;
+import org.hipparchus.util.FastMath;
+import org.orekit.errors.OrekitException;
 import org.orekit.rugged.errors.RuggedException;
-import org.orekit.rugged.errors.RuggedMessages;
-import org.orekit.rugged.utils.ParameterType;
+import org.orekit.rugged.utils.ExtendedParameterDriver;
+import org.orekit.utils.ParameterDriver;
+import org.orekit.utils.ParameterObserver;
 
 /** {@link TimeIndependentLOSTransform LOS transform} based on a fixed rotation.
  * @author Luc Maisonobe
@@ -32,8 +37,16 @@ import org.orekit.rugged.utils.ParameterType;
  */
 public class FixedRotation implements TimeIndependentLOSTransform {
 
-    /** Parameters type. */
-    private final ParameterType type;
+    /** Parameters scaling factor.
+     * <p>
+     * We use a power of 2 to avoid numeric noise introduction
+     * in the multiplications/divisions sequences.
+     * </p>
+     */
+    private final double SCALE = FastMath.scalb(1.0, -20);
+
+    /** Rotation axis. */
+    private final Vector3D axis;
 
     /** Underlying rotation. */
     private Rotation rotation;
@@ -41,78 +54,74 @@ public class FixedRotation implements TimeIndependentLOSTransform {
     /** Underlying rotation with derivatives. */
     private FieldRotation<DerivativeStructure> rDS;
 
+    /** Driver for rotation angle. */
+    private final ExtendedParameterDriver angleDriver;
+
     /** Simple constructor.
      * <p>
      * The single parameter is the rotation angle.
      * </p>
-     * @param type parameter type
+     * @param name name of the rotation (used for estimated parameters identification)
      * @param axis rotation axis
      * @param angle rotation angle
      */
-    public FixedRotation(final ParameterType type, final Vector3D axis, final double angle) {
-        this.type     = type;
-        this.rotation = new Rotation(axis, angle, RotationConvention.VECTOR_OPERATOR);
+    public FixedRotation(final String name, final Vector3D axis, final double angle) {
+        this.axis     = axis;
+        this.rotation = null;
         this.rDS      = null;
+        try {
+            this.angleDriver = new ExtendedParameterDriver(name, angle, SCALE, 0, 2 * FastMath.PI);
+            angleDriver.addObserver(new ParameterObserver() {
+                @Override
+                public void valueChanged(final double previousValue, final ParameterDriver driver) {
+                    // reset rotations to null, they will evaluated lazily if needed
+                    rotation = null;
+                    rDS      = null;
+                }
+            });
+        } catch (OrekitException oe) {
+            // this should never happen
+            throw RuggedException.createInternalError(oe);
+        }
     }
 
     /** {@inheritDoc} */
     @Override
-    public int getNbEstimatedParameters() {
-        return type == ParameterType.FIXED ? 0 : 1;
-    }
-
-    /** {@inheritDoc}
-     * <p>
-     * The single parameter is the rotation angle.
-     * </p>
-     */
-    @Override
-    public void getEstimatedParameters(final double[] parameters, final int start, final int length)
-        throws RuggedException {
-        checkSlice(length);
-        parameters[start] = rotation.getAngle();
-    }
-
-    /** {@inheritDoc}
-     * <p>
-     * The single parameter is the rotation angle.
-     * </p>
-     */
-    @Override
-    public void setEstimatedParameters(final double[] parameters, final int start, final int length)
-        throws RuggedException {
-        checkSlice(length);
-        final Vector3D axis = rotation.getAxis(RotationConvention.VECTOR_OPERATOR);
-        rotation = new Rotation(axis, parameters[start], RotationConvention.VECTOR_OPERATOR);
-        final FieldVector3D<DerivativeStructure> axisDS =
-                new FieldVector3D<DerivativeStructure>(new DerivativeStructure(parameters.length, 1, axis.getX()),
-                                                       new DerivativeStructure(parameters.length, 1, axis.getY()),
-                                                       new DerivativeStructure(parameters.length, 1, axis.getZ()));
-        final DerivativeStructure angleDS = new DerivativeStructure(parameters.length, 1, start, parameters[start]);
-        rDS = new FieldRotation<DerivativeStructure>(axisDS, angleDS, RotationConvention.VECTOR_OPERATOR);
-    }
-
-    /** Check the number of parameters of an array slice.
-     * @param length number of elements in the array slice to consider
-     * @exception RuggedException if the size of the slice does not match
-     * the {@link #getNbEstimatedParameters() number of estimated parameters}
-     */
-    private void checkSlice(final int length) throws RuggedException {
-        if (getNbEstimatedParameters() != length) {
-            throw new RuggedException(RuggedMessages.ESTIMATED_PARAMETERS_NUMBER_MISMATCH,
-                                      getNbEstimatedParameters(), length);
-        }
+    public Stream<ExtendedParameterDriver> getExtendedParametersDrivers() {
+        return Stream.of(angleDriver);
     }
 
     /** {@inheritDoc} */
     @Override
     public Vector3D transformLOS(final int i, final Vector3D los) {
+        if (rotation == null) {
+            // lazy evaluation of the rotation
+            rotation = new Rotation(axis, angleDriver.getValue(), RotationConvention.VECTOR_OPERATOR);
+        }
         return rotation.applyTo(los);
     }
 
     /** {@inheritDoc} */
     @Override
     public FieldVector3D<DerivativeStructure> transformLOS(final int i, final FieldVector3D<DerivativeStructure> los) {
+        if (rDS == null) {
+            // lazy evaluation of the rotation
+            final int nbEstimated = angleDriver.getNbEstimated();
+            final FieldVector3D<DerivativeStructure> axisDS =
+                            new FieldVector3D<DerivativeStructure>(new DerivativeStructure(nbEstimated, 1, axis.getX()),
+                                                                   new DerivativeStructure(nbEstimated, 1, axis.getY()),
+                                                                   new DerivativeStructure(nbEstimated, 1, axis.getZ()));
+            final double value = angleDriver.getValue();
+            final DerivativeStructure angleDS;
+            if (angleDriver.isSelected()) {
+                // the angle is estimated
+                angleDS = new DerivativeStructure(nbEstimated, 1, angleDriver.getIndex(), value);
+            } else {
+                // the angle is not estimated
+                angleDS = new DerivativeStructure(nbEstimated, 1, value);
+            }
+            rDS = new FieldRotation<DerivativeStructure>(axisDS, angleDS, RotationConvention.VECTOR_OPERATOR);
+        }
         return rDS.applyTo(los);
     }
 
diff --git a/src/main/java/org/orekit/rugged/los/LOSBuilder.java b/src/main/java/org/orekit/rugged/los/LOSBuilder.java
index bb6b2d34..c61be99a 100644
--- a/src/main/java/org/orekit/rugged/los/LOSBuilder.java
+++ b/src/main/java/org/orekit/rugged/los/LOSBuilder.java
@@ -16,17 +16,21 @@
  */
 package org.orekit.rugged.los;
 
-import org.hipparchus.analysis.differentiation.DerivativeStructure;
-import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
-import org.hipparchus.geometry.euclidean.threed.Vector3D;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
+import java.util.Optional;
+import java.util.stream.Stream;
 
+import org.hipparchus.analysis.differentiation.DerivativeStructure;
+import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
+import org.hipparchus.geometry.euclidean.threed.Vector3D;
+import org.orekit.errors.OrekitException;
 import org.orekit.rugged.errors.RuggedException;
-import org.orekit.rugged.errors.RuggedMessages;
-import org.orekit.rugged.utils.ParametricModel;
+import org.orekit.rugged.utils.ExtendedParameterDriver;
 import org.orekit.time.AbsoluteDate;
+import org.orekit.utils.ParameterDriver;
+import org.orekit.utils.ParameterObserver;
 
 /** Builder for lines-of-sight list.
  * <p>
@@ -113,26 +117,6 @@ public class LOSBuilder {
             this.transform = transform;
         }
 
-        /** {@inheritDoc} */
-        @Override
-        public int getNbEstimatedParameters() {
-            return transform.getNbEstimatedParameters();
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void getEstimatedParameters(final double[] parameters, final int start, final int length)
-            throws RuggedException {
-            transform.getEstimatedParameters(parameters, start, length);
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void setEstimatedParameters(final double[] parameters, final int start, final int length)
-            throws RuggedException {
-            transform.setEstimatedParameters(parameters, start, length);
-        }
-
         /** {@inheritDoc} */
         @Override
         public Vector3D transformLOS(final int i, final Vector3D los, final AbsoluteDate date) {
@@ -146,19 +130,22 @@ public class LOSBuilder {
             return transform.transformLOS(i, los);
         }
 
+        /** {@inheritDoc} */
+        @Override
+        public Stream<ExtendedParameterDriver> getExtendedParametersDrivers() {
+            return transform.getExtendedParametersDrivers();
+        }
+
     }
 
     /** Implement time-independent LOS by recomputing directions by applying all transforms each time. */
-    private static class TransformsSequenceLOS implements ParametricModel, TimeDependentLOS {
+    private static class TransformsSequenceLOS implements TimeDependentLOS {
 
         /** Raw direction. */
         private final Vector3D[] raw;
 
         /** Transforms to be applied. */
-        private final LOSTransform[] transforms;
-
-        /** Total number of estimated parameters. */
-        private final int total;
+        private final List<LOSTransform> transforms;
 
         /** Simple constructor.
          * @param raw raw directions
@@ -174,95 +161,53 @@ public class LOSBuilder {
                 this.raw[i] = raw.get(i);
             }
 
-            this.transforms = new LOSTransform[transforms.size()];
-            int n = 0;
-            for (int i = 0; i < transforms.size(); ++i) {
-                final LOSTransform transform = transforms.get(i);
-                this.transforms[i] = transform;
-                n += transform.getNbEstimatedParameters();
-            }
-            this.total = n;
+            this.transforms = new ArrayList<LOSTransform>(transforms);
 
         }
 
         /** {@inheritDoc} */
-        @Override
-        public int getNbEstimatedParameters() {
-            return total;
+        public int getNbPixels() {
+            return raw.length;
         }
 
         /** {@inheritDoc} */
         @Override
-        public void getEstimatedParameters(final double[] parameters, final int start, final int length)
-            throws RuggedException {
-
-            // global check
-            checkSlice(length);
-
-            // retrieve parameters for all transforms
-            int offset = 0;
-            for (final ParametricModel model : transforms) {
-                final int n = model.getNbEstimatedParameters();
-                model.getEstimatedParameters(parameters, offset, n);
-                offset += n;
+        public Vector3D getLOS(final int index, final AbsoluteDate date) {
+            Vector3D los = raw[index];
+            for (final LOSTransform transform : transforms) {
+                los = transform.transformLOS(index, los, date);
             }
-
+            return los.normalize();
         }
 
         /** {@inheritDoc} */
         @Override
-        public void setEstimatedParameters(final double[] parameters, final int start, final int length)
-            throws RuggedException {
-
-            // global check
-            checkSlice(length);
-
-            // set parameters for all transforms
-            int offset = 0;
-            for (final ParametricModel model : transforms) {
-                final int n = model.getNbEstimatedParameters();
-                model.setEstimatedParameters(parameters, offset, n);
-                offset += n;
-            }
+        public FieldVector3D<DerivativeStructure> getLOSDerivatives(final int index, final AbsoluteDate date) {
 
-        }
+            // the raw line of sights are considered to be constant
+            final Optional<ExtendedParameterDriver> first = getExtendedParametersDrivers().findFirst();
+            final int nbEstimated = first.isPresent() ? first.get().getNbEstimated() : 0;
+            FieldVector3D<DerivativeStructure> los =
+                            new FieldVector3D<DerivativeStructure>(new DerivativeStructure(nbEstimated, 1, raw[index].getX()),
+                                                                   new DerivativeStructure(nbEstimated, 1, raw[index].getY()),
+                                                                   new DerivativeStructure(nbEstimated, 1, raw[index].getZ()));
 
-        /** Check the number of parameters of an array slice.
-         * @param length number of elements in the array slice to consider
-         * @exception RuggedException if the size of the slice does not match
-         * the {@link #getNbEstimatedParameters() number of estimated parameters}
-         */
-        private void checkSlice(final int length) throws RuggedException {
-            if (getNbEstimatedParameters() != length) {
-                throw new RuggedException(RuggedMessages.ESTIMATED_PARAMETERS_NUMBER_MISMATCH,
-                                          getNbEstimatedParameters(), length);
-            }
-        }
-
-        /** {@inheritDoc} */
-        public int getNbPixels() {
-            return raw.length;
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public Vector3D getLOS(final int index, final AbsoluteDate date) {
-            Vector3D los = raw[index];
+            // apply the transforms, which depend on parameters and hence may introduce non-zero derivatives
             for (final LOSTransform transform : transforms) {
                 los = transform.transformLOS(index, los, date);
             }
+
             return los.normalize();
+
         }
 
-        /** {@inheritDoc} */
         @Override
-        public FieldVector3D<DerivativeStructure> getLOS(final int index, final AbsoluteDate date,
-                                                         final double[] parameters) {
-            // non-adjustable LOS do not depend on any parameters
-            final Vector3D los = getLOS(index, date);
-            return new FieldVector3D<DerivativeStructure>(new DerivativeStructure(parameters.length, 1, los.getX()),
-                                                          new DerivativeStructure(parameters.length, 1, los.getY()),
-                                                          new DerivativeStructure(parameters.length, 1, los.getZ()));
+        public Stream<ExtendedParameterDriver> getExtendedParametersDrivers() {
+            Stream<ExtendedParameterDriver> drivers = Stream.<ExtendedParameterDriver>empty();
+            for (final LOSTransform transform : transforms) {
+                drivers = Stream.concat(drivers, transform.getExtendedParametersDrivers());
+            }
+            return drivers;
         }
 
     }
@@ -278,20 +223,26 @@ public class LOSBuilder {
          * @param transforms transforms to apply (must be time-independent!)
          */
         FixedLOS(final List<Vector3D> raw, final List<LOSTransform> transforms) {
+
             super(raw, transforms);
             transformed = new Vector3D[raw.size()];
-        }
-
-        /** {@inheritDoc} */
-        @Override
-        public void setEstimatedParameters(final double[] parameters, final int start, final int length)
-            throws RuggedException {
-
-            // update the transforms
-            super.setEstimatedParameters(parameters, start, length);
 
-            // unset the directions, to ensure they get recomputed if needed
-            Arrays.fill(transformed, null);
+            // we will reset the transforms to null when parameters are changed
+            final ParameterObserver resettingObserver = new ParameterObserver() {
+                /** {@inheritDoc} */
+                @Override
+                public void valueChanged(final double previousValue, final ParameterDriver driver) {
+                    Arrays.fill(transformed, null);
+                }
+            };
+            getExtendedParametersDrivers().forEach(driver -> {
+                try {
+                    driver.addObserver(resettingObserver);
+                } catch (OrekitException oe) {
+                    // this should never happen
+                    throw RuggedException.createInternalError(oe);
+                }
+            });
 
         }
 
diff --git a/src/main/java/org/orekit/rugged/los/LOSTransform.java b/src/main/java/org/orekit/rugged/los/LOSTransform.java
index 067f18b4..b54f6289 100644
--- a/src/main/java/org/orekit/rugged/los/LOSTransform.java
+++ b/src/main/java/org/orekit/rugged/los/LOSTransform.java
@@ -16,17 +16,19 @@
  */
 package org.orekit.rugged.los;
 
+import java.util.stream.Stream;
+
 import org.hipparchus.analysis.differentiation.DerivativeStructure;
 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
 import org.hipparchus.geometry.euclidean.threed.Vector3D;
-import org.orekit.rugged.utils.ParametricModel;
+import org.orekit.rugged.utils.ExtendedParameterDriver;
 import org.orekit.time.AbsoluteDate;
 
 /** Interface for lines-of-sight tranforms.
  * @author Luc Maisonobe
  * @see LOSBuilder
  */
-public interface LOSTransform extends ParametricModel {
+public interface LOSTransform {
 
     /** Transform a line-of-sight.
      * @param i los pixel index
@@ -50,4 +52,10 @@ public interface LOSTransform extends ParametricModel {
      */
     FieldVector3D<DerivativeStructure> transformLOS(int index, FieldVector3D<DerivativeStructure> los, AbsoluteDate date);
 
+    /** Get the drivers for LOS parameters.
+     * @return drivers for LOS parameters
+     * @since 2.0
+     */
+    Stream<ExtendedParameterDriver> getExtendedParametersDrivers();
+
 }
diff --git a/src/main/java/org/orekit/rugged/los/PolynomialRotation.java b/src/main/java/org/orekit/rugged/los/PolynomialRotation.java
index 73d40b24..49df76a8 100644
--- a/src/main/java/org/orekit/rugged/los/PolynomialRotation.java
+++ b/src/main/java/org/orekit/rugged/los/PolynomialRotation.java
@@ -16,6 +16,8 @@
  */
 package org.orekit.rugged.los;
 
+import java.util.stream.Stream;
+
 import org.hipparchus.analysis.differentiation.DerivativeStructure;
 import org.hipparchus.analysis.polynomials.PolynomialFunction;
 import org.hipparchus.geometry.euclidean.threed.FieldRotation;
@@ -23,10 +25,13 @@ import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
 import org.hipparchus.geometry.euclidean.threed.Rotation;
 import org.hipparchus.geometry.euclidean.threed.RotationConvention;
 import org.hipparchus.geometry.euclidean.threed.Vector3D;
+import org.hipparchus.util.FastMath;
+import org.orekit.errors.OrekitException;
 import org.orekit.rugged.errors.RuggedException;
-import org.orekit.rugged.errors.RuggedMessages;
-import org.orekit.rugged.utils.ParameterType;
+import org.orekit.rugged.utils.ExtendedParameterDriver;
 import org.orekit.time.AbsoluteDate;
+import org.orekit.utils.ParameterDriver;
+import org.orekit.utils.ParameterObserver;
 
 /** {@link LOSTransform LOS transform} based on a rotation with polynomial angle.
  * @author Luc Maisonobe
@@ -34,8 +39,13 @@ import org.orekit.time.AbsoluteDate;
  */
 public class PolynomialRotation implements LOSTransform {
 
-    /** Parameters type. */
-    private final ParameterType type;
+    /** Parameters scaling factor.
+     * <p>
+     * We use a power of 2 to avoid numeric noise introduction
+     * in the multiplications/divisions sequences.
+     * </p>
+     */
+    private final double SCALE = FastMath.scalb(1.0, -20);
 
     /** Rotation axis. */
     private final Vector3D axis;
@@ -52,6 +62,9 @@ public class PolynomialRotation implements LOSTransform {
     /** Reference date for polynomial evaluation. */
     private final AbsoluteDate referenceDate;
 
+    /** Drivers for rotation angle polynomial coefficients. */
+    private final ExtendedParameterDriver[] coefficientsDrivers;
+
     /** Simple constructor.
      * <p>
      * The angle of the rotation is evaluated as a polynomial in t,
@@ -59,17 +72,38 @@ public class PolynomialRotation implements LOSTransform {
      * reference date. The parameters are the polynomial coefficients,
      * with the constant term at index 0.
      * </p>
-     * @param type parameters type
+     * @param name name of the rotation (used for estimated parameters identification)
      * @param axis rotation axis
      * @param referenceDate reference date for the polynomial angle
      * @param angleCoeffs polynomial coefficients of the polynomial angle,
      * with the constant term at index 0
      */
-    public PolynomialRotation(final ParameterType type,
+    public PolynomialRotation(final String name,
                               final Vector3D axis,
                               final AbsoluteDate referenceDate,
                               final double ... angleCoeffs) {
-        this(type, axis, referenceDate, new PolynomialFunction(angleCoeffs));
+        this.axis                = axis;
+        this.referenceDate       = referenceDate;
+        this.coefficientsDrivers = new ExtendedParameterDriver[angleCoeffs.length];
+        final ParameterObserver resettingObserver = new ParameterObserver() {
+            @Override
+            public void valueChanged(final double previousValue, final ParameterDriver driver) {
+                // reset rotations to null, they will evaluated lazily if needed
+                angle   = null;
+                axisDS  = null;
+                angleDS = null;
+            }
+        };
+        try {
+            for (int i = 0; i < angleCoeffs.length; ++i) {
+                coefficientsDrivers[i] = new ExtendedParameterDriver(name + "[" + i + "]", angleCoeffs[i], SCALE,
+                                                                     Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
+                coefficientsDrivers[i].addObserver(resettingObserver);
+            }
+        } catch (OrekitException oe) {
+            // this should never happen
+            throw RuggedException.createInternalError(oe);
+        }
     }
 
     /** Simple constructor.
@@ -79,81 +113,35 @@ public class PolynomialRotation implements LOSTransform {
      * reference date. The parameters are the polynomial coefficients,
      * with the constant term at index 0.
      * </p>
-     * @param type parameters type
+     * @param name name of the rotation (used for estimated parameters identification)
      * @param axis rotation axis
      * @param referenceDate reference date for the polynomial angle
      * @param angle polynomial angle
      */
-    public PolynomialRotation(final ParameterType type,
+    public PolynomialRotation(final String name,
                               final Vector3D axis,
                               final AbsoluteDate referenceDate,
                               final PolynomialFunction angle) {
-        this.type          = type;
-        this.axis          = axis;
-        this.angle         = angle;
-        this.referenceDate = referenceDate;
+        this(name, axis, referenceDate, angle.getCoefficients());
     }
 
     /** {@inheritDoc} */
     @Override
-    public int getNbEstimatedParameters() {
-        return type == ParameterType.FIXED ? 0 : (angle.degree() + 1);
-    }
-
-    /** {@inheritDoc}
-     * <p>
-     * The parameters are the polynomial coefficients,
-     * with the constant term at index 0.
-     * </p>
-     */
-    @Override
-    public void getEstimatedParameters(final double[] parameters, final int start, final int length)
-        throws RuggedException {
-        checkSlice(length);
-        System.arraycopy(angle.getCoefficients(), 0, parameters, start, length);
-    }
-
-    /** {@inheritDoc}
-     * <p>
-     * The parameters are the polynomial coefficients,
-     * with the constant term at index 0.
-     * </p>
-     */
-    @Override
-    public void setEstimatedParameters(final double[] parameters, final int start, final int length)
-        throws RuggedException {
-
-        checkSlice(length);
-
-        // regular rotation
-        angle = new PolynomialFunction(parameters);
-
-        // prepare components to compute rotation with derivatives
-        axisDS = new FieldVector3D<DerivativeStructure>(new DerivativeStructure(parameters.length, 1, axis.getX()),
-                                                        new DerivativeStructure(parameters.length, 1, axis.getY()),
-                                                        new DerivativeStructure(parameters.length, 1, axis.getZ()));
-        angleDS = new DerivativeStructure[length];
-        for (int i = 0; i < length; ++i) {
-            angleDS[i] = new DerivativeStructure(parameters.length, 1, start + i, parameters[start + i]);
-        }
-
-    }
-
-    /** Check the number of parameters of an array slice.
-     * @param length number of elements in the array slice to consider
-     * @exception RuggedException if the size of the slice does not match
-     * the {@link #getNbEstimatedParameters() number of estimated parameters}
-     */
-    private void checkSlice(final int length) throws RuggedException {
-        if (getNbEstimatedParameters() != length) {
-            throw new RuggedException(RuggedMessages.ESTIMATED_PARAMETERS_NUMBER_MISMATCH,
-                                      getNbEstimatedParameters(), length);
-        }
+    public Stream<ExtendedParameterDriver> getExtendedParametersDrivers() {
+        return Stream.of(coefficientsDrivers);
     }
 
     /** {@inheritDoc} */
     @Override
     public Vector3D transformLOS(final int i, final Vector3D los, final AbsoluteDate date) {
+        if (angle == null) {
+            // lazy evaluation of the rotation
+            final double[] coefficients = new double[coefficientsDrivers.length];
+            for (int k = 0; k < coefficients.length; ++k) {
+                coefficients[k] = coefficientsDrivers[k].getValue();
+            }
+            angle = new PolynomialFunction(coefficients);
+        }
         return new Rotation(axis,
                             angle.value(date.durationFrom(referenceDate)),
                             RotationConvention.VECTOR_OPERATOR).applyTo(los);
@@ -164,6 +152,24 @@ public class PolynomialRotation implements LOSTransform {
     public FieldVector3D<DerivativeStructure> transformLOS(final int i, final FieldVector3D<DerivativeStructure> los,
                                                            final AbsoluteDate date) {
 
+        if (angleDS == null) {
+            // lazy evaluation of the rotation
+            final int nbEstimated = coefficientsDrivers[0].getNbEstimated();
+            axisDS = new FieldVector3D<DerivativeStructure>(new DerivativeStructure(nbEstimated, 1, axis.getX()),
+                                                            new DerivativeStructure(nbEstimated, 1, axis.getY()),
+                                                            new DerivativeStructure(nbEstimated, 1, axis.getZ()));
+            angleDS = new DerivativeStructure[coefficientsDrivers.length];
+            for (int k = 0; k < angleDS.length; ++k) {
+                final double value = coefficientsDrivers[k].getValue();
+                if (coefficientsDrivers[k].isSelected()) {
+                    // the coefficient is estimated
+                    angleDS[k] = new DerivativeStructure(nbEstimated, 1, coefficientsDrivers[k].getIndex(), value);
+                } else {
+                    // the coefficient is not estimated
+                    angleDS[k] = new DerivativeStructure(nbEstimated, 1, value);
+                }
+            }
+        }
         // evaluate polynomial, with all its partial derivatives
         final double t = date.durationFrom(referenceDate);
         DerivativeStructure alpha = axisDS.getX().getField().getZero();
diff --git a/src/main/java/org/orekit/rugged/los/TimeDependentLOS.java b/src/main/java/org/orekit/rugged/los/TimeDependentLOS.java
index 7626be25..9cf3ac73 100644
--- a/src/main/java/org/orekit/rugged/los/TimeDependentLOS.java
+++ b/src/main/java/org/orekit/rugged/los/TimeDependentLOS.java
@@ -16,17 +16,19 @@
  */
 package org.orekit.rugged.los;
 
+import java.util.stream.Stream;
+
 import org.hipparchus.analysis.differentiation.DerivativeStructure;
 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
 import org.hipparchus.geometry.euclidean.threed.Vector3D;
-import org.orekit.rugged.utils.ParametricModel;
+import org.orekit.rugged.utils.ExtendedParameterDriver;
 import org.orekit.time.AbsoluteDate;
 
 /** Interface representing a line-of-sight which depends on time.
  * @see org.orekit.rugged.linesensor.LineSensor
  * @author Luc Maisonobe
  */
-public interface TimeDependentLOS extends ParametricModel {
+public interface TimeDependentLOS {
 
     /** Get the number of pixels.
      * @return number of pixels
@@ -43,23 +45,26 @@ public interface TimeDependentLOS extends ParametricModel {
     /** Get the line of sight and its partial derivatives for a given date.
      * <p>
      * This method is used for LOS calibration purposes. It allows to compute
-     * the Jacobian matrix of the LOS with respect to the parameters, which
+     * the Jacobian matrix of the LOS with respect to the estimated parameters, which
      * are typically polynomials coefficients representing rotation angles.
      * These polynomials can be used for example to model thermo-elastic effects.
      * </p>
      * <p>
      * Note that in order for the partial derivatives to be properly set up, the
-     * {@link #setEstimatedParameters(double[], int, int) setEstimatedParameters}
-     * <em>must</em> have been called at least once before this method and its
-     * {@code start} parameter will be used to ensure the partial derivatives are
-     * ordered in the same way in the returned vector as they were in the set
-     * parameters.
+     * {@link org.orekit.utils.ParameterDriver#setSelected(boolean) setSelected}
+     * method must have been set to {@code true} for the various parameters returned
+     * by {@link #getExtendedParametersDrivers()} that should be estimated.
      * </p>
      * @param index los pixel index
      * @param date date
-     * @param parameters current estimate of the adjusted parameters
      * @return line of sight, and its first partial derivatives with respect to the parameters
      */
-    FieldVector3D<DerivativeStructure> getLOS(int index, AbsoluteDate date, double[] parameters);
+    FieldVector3D<DerivativeStructure> getLOSDerivatives(int index, AbsoluteDate date);
+
+    /** Get the drivers for LOS parameters.
+     * @return drivers for LOS parameters
+     * @since 2.0
+     */
+    Stream<ExtendedParameterDriver> getExtendedParametersDrivers();
 
 }
diff --git a/src/main/java/org/orekit/rugged/los/TimeIndependentLOSTransform.java b/src/main/java/org/orekit/rugged/los/TimeIndependentLOSTransform.java
index 5fbb8e15..59ecbddf 100644
--- a/src/main/java/org/orekit/rugged/los/TimeIndependentLOSTransform.java
+++ b/src/main/java/org/orekit/rugged/los/TimeIndependentLOSTransform.java
@@ -16,16 +16,18 @@
  */
 package org.orekit.rugged.los;
 
+import java.util.stream.Stream;
+
 import org.hipparchus.analysis.differentiation.DerivativeStructure;
 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
 import org.hipparchus.geometry.euclidean.threed.Vector3D;
-import org.orekit.rugged.utils.ParametricModel;
+import org.orekit.rugged.utils.ExtendedParameterDriver;
 
 /** Interface for lines-of-sight tranforms that do not depend on time.
  * @author Luc Maisonobe
  * @see LOSBuilder
  */
-public interface TimeIndependentLOSTransform extends ParametricModel {
+public interface TimeIndependentLOSTransform {
 
     /** Transform a line-of-sight.
      * @param i los pixel index
@@ -55,4 +57,10 @@ public interface TimeIndependentLOSTransform extends ParametricModel {
      */
     FieldVector3D<DerivativeStructure> transformLOS(int index, FieldVector3D<DerivativeStructure> los);
 
+    /** Get the drivers for LOS parameters.
+     * @return drivers for LOS parameters
+     * @since 2.0
+     */
+    Stream<ExtendedParameterDriver> getExtendedParametersDrivers();
+
 }
diff --git a/src/main/java/org/orekit/rugged/utils/ExtendedParameterDriver.java b/src/main/java/org/orekit/rugged/utils/ExtendedParameterDriver.java
new file mode 100644
index 00000000..0fafb4a8
--- /dev/null
+++ b/src/main/java/org/orekit/rugged/utils/ExtendedParameterDriver.java
@@ -0,0 +1,85 @@
+/* Copyright 2013-2016 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.utils;
+
+import org.orekit.errors.OrekitException;
+import org.orekit.utils.ParameterDriver;
+
+/** {@link ParameterDriver} belonging to a list.
+ * @since 2.0
+ * @author Luc Maisonobe
+ */
+public class ExtendedParameterDriver extends ParameterDriver {
+
+    /** Total number of estimated parameters. */
+    private int nbEstimated;
+
+    /** Index of this parameter in the estimated parameters list. */
+    private int index;
+
+    /** Simple constructor.
+     * <p>
+     * At construction, the parameter is configured as <em>not</em> selected,
+     * and the value is set to the {@code referenceValue}.
+     * </p>
+     * @param name name of the parameter
+     * @param referenceValue reference value of the parameter
+     * @param scale scaling factor to convert the parameters value to
+     * non-dimensional (typically set to the expected standard deviation of the
+     * parameter), it must be non-zero
+     * @param minValue minimum value
+     * @param maxValue maximum value
+     * @exception OrekitException if scale is too close to zero
+     */
+    public ExtendedParameterDriver(final String name, final double referenceValue,
+                                   final double scale, final double minValue,
+                                   final double maxValue)
+        throws OrekitException {
+        super(name, referenceValue, scale, minValue, maxValue);
+        nbEstimated =  0;
+        index       = -1;
+    }
+
+    /** Set the total number of estimated parameters.
+     * @param nbEstimated total number of estimated parameters
+     */
+    public void setNbEstimated(final int nbEstimated) {
+        this.nbEstimated = nbEstimated;
+    }
+
+    /** Get the total number of estimated parameters.
+     * @return total number of estimated parameters
+     */
+    public int getNbEstimated() {
+        return nbEstimated;
+    }
+
+    /** Set the index of this parameter in the estimated parameters list.
+     * @param index index of this parameter in the estimated parameters list
+     */
+    public void setIndex(final int index) {
+        this.index = index;
+    }
+
+    /** Get the index of this parameter in the estimated parameters list.
+     * @return index of this parameter in the estimated parameters list
+     */
+    public int getIndex() {
+        return index;
+    }
+
+}
diff --git a/src/main/java/org/orekit/rugged/utils/ParameterType.java b/src/main/java/org/orekit/rugged/utils/ParameterType.java
deleted file mode 100644
index 65e232a9..00000000
--- a/src/main/java/org/orekit/rugged/utils/ParameterType.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/* Copyright 2013-2016 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.utils;
-
-
-/** Type of parameter.
- * @author Luc Maisonobe
- * @see ParametricModel
- */
-public enum ParameterType {
-
-    /** Type of parameter which cannot be changed at all. */
-    FIXED,
-
-    /** Type of parameter which can be estimated, i.e. its value can change. */
-    ESTIMATED;
-
-}
diff --git a/src/main/java/org/orekit/rugged/utils/ParametricModel.java b/src/main/java/org/orekit/rugged/utils/ParametricModel.java
deleted file mode 100644
index 0e3f852e..00000000
--- a/src/main/java/org/orekit/rugged/utils/ParametricModel.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/* Copyright 2013-2016 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.utils;
-
-import org.orekit.rugged.errors.RuggedException;
-
-
-/** Interface for models that have parameters.
- * <p>
- * The parameters are typically polynomial coefficients, for example
- * to model thermo-elastic deformations of the sensor or spacecraft.
- * </p>
- * @author Luc Maisonobe
- */
-public interface ParametricModel {
-
-    /** Get the number of estimated parameters.
-     * @return number of estimated parameters
-     */
-    int getNbEstimatedParameters();
-
-    /** Get the current values of the estimated parameters.
-     * @param parameters global array where to put the parameters
-     * @param start start index of the array slice to consider
-     * @param length number of elements in the array slice to consider
-     * @exception RuggedException if the size of the slice does not match
-     * the {@link #getNbEstimatedParameters() number of estimated parameters}
-     */
-    void getEstimatedParameters(double[] parameters, int start, int length)
-        throws RuggedException;
-
-    /** Set new values for the estimated parameters.
-     * @param parameters global array containing the parameters to set (among others)
-     * @param start start index of the array slice to consider
-     * @param length number of elements in the array slice to consider
-     * @exception RuggedException if the size of the slice does not match
-     * the {@link #getNbEstimatedParameters() number of estimated parameters}
-     */
-    void setEstimatedParameters(double[] parameters, int start, int length)
-        throws RuggedException;
-
-}
diff --git a/src/site/xdoc/changes.xml b/src/site/xdoc/changes.xml
index 5c40148f..6793d017 100644
--- a/src/site/xdoc/changes.xml
+++ b/src/site/xdoc/changes.xml
@@ -21,6 +21,10 @@
   </properties>
   <body>
     <release version="2.0" date="TBD" description="TTBD">
+      <action dev="luc" type="update">
+        Replaced the ad-hoc parameters with Orekit ParameterDriver that are
+        used in Orekit orbit determination feature.
+      </action>
       <action dev="luc" type="update">
         Updated dependencies to Orekit 8.0 and Hipparchus 1.0.
       </action>
diff --git a/src/test/java/org/orekit/rugged/api/RuggedTest.java b/src/test/java/org/orekit/rugged/api/RuggedTest.java
index 98ec4885..2b8928e6 100644
--- a/src/test/java/org/orekit/rugged/api/RuggedTest.java
+++ b/src/test/java/org/orekit/rugged/api/RuggedTest.java
@@ -416,7 +416,7 @@ public class RuggedTest {
         for (int i = 0; i < gpLine.length; ++i) {
             GeodeticPoint gpPixel =
                     rugged.directLocation(lineSensor.getDate(100), lineSensor.getPosition(),
-                                              lineSensor.getLos(lineSensor.getDate(100), i));
+                                              lineSensor.getLOS(lineSensor.getDate(100), i));
             Assert.assertEquals(gpLine[i].getLatitude(),  gpPixel.getLatitude(),  1.0e-10);
             Assert.assertEquals(gpLine[i].getLongitude(), gpPixel.getLongitude(), 1.0e-10);
             Assert.assertEquals(gpLine[i].getAltitude(),  gpPixel.getAltitude(),  1.0e-10);
@@ -477,7 +477,7 @@ public class RuggedTest {
         for (int i = 0; i < gpLine.length; ++i) {
             GeodeticPoint gpPixel =
                     rugged.directLocation(lineSensor.getDate(100), lineSensor.getPosition(),
-                                              lineSensor.getLos(lineSensor.getDate(100), i));
+                                              lineSensor.getLOS(lineSensor.getDate(100), i));
             Assert.assertEquals(gpLine[i].getLatitude(),  gpPixel.getLatitude(),  1.0e-10);
             Assert.assertEquals(gpLine[i].getLongitude(), gpPixel.getLongitude(), 1.0e-10);
             Assert.assertEquals(gpLine[i].getAltitude(),  gpPixel.getAltitude(),  1.0e-10);
diff --git a/src/test/java/org/orekit/rugged/errors/DumpManagerTest.java b/src/test/java/org/orekit/rugged/errors/DumpManagerTest.java
index 6e183d35..e9de4c43 100644
--- a/src/test/java/org/orekit/rugged/errors/DumpManagerTest.java
+++ b/src/test/java/org/orekit/rugged/errors/DumpManagerTest.java
@@ -179,7 +179,7 @@ public class DumpManagerTest {
        for (int i = 0; i < gpLine.length; ++i) {
            GeodeticPoint gpPixel =
                    rugged.directLocation(lineSensor.getDate(100), lineSensor.getPosition(),
-                                             lineSensor.getLos(lineSensor.getDate(100), i));
+                                             lineSensor.getLOS(lineSensor.getDate(100), i));
            Assert.assertEquals(gpLine[i].getLatitude(),  gpPixel.getLatitude(),  1.0e-10);
            Assert.assertEquals(gpLine[i].getLongitude(), gpPixel.getLongitude(), 1.0e-10);
            Assert.assertEquals(gpLine[i].getAltitude(),  gpPixel.getAltitude(),  1.0e-10);
-- 
GitLab