diff --git a/src/main/java/org/orekit/rugged/adjustment/GroundOptimizationProblemBuilder.java b/src/main/java/org/orekit/rugged/adjustment/GroundOptimizationProblemBuilder.java
index 23a7d40378c7b4aeed9bbc83e6fd770d1e6f0adb..ec9c758d51204f1173054fd1cdff99c07365274d 100644
--- a/src/main/java/org/orekit/rugged/adjustment/GroundOptimizationProblemBuilder.java
+++ b/src/main/java/org/orekit/rugged/adjustment/GroundOptimizationProblemBuilder.java
@@ -21,7 +21,7 @@ import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.hipparchus.analysis.differentiation.DerivativeStructure;
+import org.hipparchus.analysis.differentiation.Gradient;
 import org.hipparchus.linear.Array2DRowRealMatrix;
 import org.hipparchus.linear.ArrayRealVector;
 import org.hipparchus.linear.RealMatrix;
@@ -162,7 +162,7 @@ public class GroundOptimizationProblemBuilder extends OptimizationProblemBuilder
             for (final SensorToGroundMapping reference : this.sensorToGroundMappings) {
                 for (final Map.Entry<SensorPixel, GeodeticPoint> mapping : reference.getMapping()) {
                     final GeodeticPoint gp = mapping.getValue();
-                    final DerivativeStructure[] ilResult = this.rugged.inverseLocationDerivatives(reference.getSensorName(), gp, minLine, maxLine, this.getGenerator());
+                    final Gradient[] ilResult = this.rugged.inverseLocationDerivatives(reference.getSensorName(), gp, minLine, maxLine, this.getGenerator());
 
                     if (ilResult == null) {
                         value.setEntry(l, minLine - 100.0); // arbitrary
diff --git a/src/main/java/org/orekit/rugged/adjustment/InterSensorsOptimizationProblemBuilder.java b/src/main/java/org/orekit/rugged/adjustment/InterSensorsOptimizationProblemBuilder.java
index 13d69958ce7429762be4a0d0c654ae93b1b44487..4f6b98308a3df3297a4ce9fbac54a38af11df927 100644
--- a/src/main/java/org/orekit/rugged/adjustment/InterSensorsOptimizationProblemBuilder.java
+++ b/src/main/java/org/orekit/rugged/adjustment/InterSensorsOptimizationProblemBuilder.java
@@ -24,7 +24,7 @@ import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
 
-import org.hipparchus.analysis.differentiation.DerivativeStructure;
+import org.hipparchus.analysis.differentiation.Gradient;
 import org.hipparchus.linear.Array2DRowRealMatrix;
 import org.hipparchus.linear.ArrayRealVector;
 import org.hipparchus.linear.RealMatrix;
@@ -207,7 +207,7 @@ public class InterSensorsOptimizationProblemBuilder extends OptimizationProblemB
 
                     final SpacecraftToObservedBody scToBodyA = ruggedA.getScToBody();
 
-                    final DerivativeStructure[] ilResult =
+                    final Gradient[] ilResult =
                             ruggedB.distanceBetweenLOSderivatives(lineSensorA, dateA, pixelA, scToBodyA,
                                     lineSensorB, dateB, pixelB, this.getGenerator());
 
diff --git a/src/main/java/org/orekit/rugged/adjustment/OptimizationProblemBuilder.java b/src/main/java/org/orekit/rugged/adjustment/OptimizationProblemBuilder.java
index 421e23e39c7dd6d1e338ea8a2bfe842291afd2fc..1dd9945076f6ff4c88170f67045aec3fe29ee375 100644
--- a/src/main/java/org/orekit/rugged/adjustment/OptimizationProblemBuilder.java
+++ b/src/main/java/org/orekit/rugged/adjustment/OptimizationProblemBuilder.java
@@ -24,8 +24,9 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
-import org.hipparchus.analysis.differentiation.DSFactory;
-import org.hipparchus.analysis.differentiation.DerivativeStructure;
+import org.hipparchus.Field;
+import org.hipparchus.analysis.differentiation.Gradient;
+import org.hipparchus.analysis.differentiation.GradientField;
 import org.hipparchus.optim.ConvergenceChecker;
 import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresProblem;
 import org.hipparchus.optim.nonlinear.vector.leastsquares.MultivariateJacobianFunction;
@@ -34,7 +35,7 @@ import org.orekit.rugged.adjustment.measurements.Observables;
 import org.orekit.rugged.errors.RuggedException;
 import org.orekit.rugged.errors.RuggedMessages;
 import org.orekit.rugged.linesensor.LineSensor;
-import org.orekit.rugged.utils.DSGenerator;
+import org.orekit.rugged.utils.DerivativeGenerator;
 import org.orekit.utils.ParameterDriver;
 
 /**
@@ -51,8 +52,8 @@ abstract class OptimizationProblemBuilder {
     /** Margin used in parameters estimation for the inverse location lines range. */
     protected static final int ESTIMATION_LINE_RANGE_MARGIN = 100;
 
-    /** Derivative structure generator.*/
-    private final DSGenerator generator;
+    /** Gradient generator.*/
+    private final DerivativeGenerator<Gradient> generator;
 
     /** Parameter drivers list. */
     private final List<ParameterDriver> drivers;
@@ -151,11 +152,11 @@ abstract class OptimizationProblemBuilder {
         return validator;
     }
 
-    /** Create the generator for {@link DerivativeStructure} instances.
+    /** Create the generator for {@link Gradient} instances.
      * @param selectedSensors list of sensors referencing the parameters drivers
      * @return a new generator
      */
-    private DSGenerator createGenerator(final List<LineSensor> selectedSensors) {
+    private DerivativeGenerator<Gradient> createGenerator(final List<LineSensor> selectedSensors) {
 
         // Initialize set of drivers name
         final Set<String> names = new HashSet<>();
@@ -188,10 +189,9 @@ abstract class OptimizationProblemBuilder {
             });
         }
 
-        final DSFactory factory = new DSFactory(map.size(), 1);
-
-        // Derivative Structure Generator
-        return new DSGenerator() {
+        // gradient Generator
+        final GradientField field = GradientField.getField(map.size());
+        return new DerivativeGenerator<Gradient>() {
 
             /** {@inheritDoc} */
             @Override
@@ -201,21 +201,27 @@ abstract class OptimizationProblemBuilder {
 
             /** {@inheritDoc} */
             @Override
-            public DerivativeStructure constant(final double value) {
-                return factory.constant(value);
+            public Gradient constant(final double value) {
+                return Gradient.constant(map.size(), value);
             }
 
             /** {@inheritDoc} */
             @Override
-            public DerivativeStructure variable(final ParameterDriver driver) {
-
+            public Gradient variable(final ParameterDriver driver) {
                 final Integer index = map.get(driver.getName());
                 if (index == null) {
                     return constant(driver.getValue());
                 } else {
-                    return factory.variable(index.intValue(), driver.getValue());
+                    return Gradient.variable(map.size(), index.intValue(), driver.getValue());
                 }
             }
+
+            /** {@inheritDoc} */
+            @Override
+            public Field<Gradient> getField() {
+                return field;
+            }
+
         };
     }
 
@@ -245,7 +251,7 @@ abstract class OptimizationProblemBuilder {
      * Get the derivative structure generator.
      * @return the derivative structure generator.
      */
-    protected final DSGenerator getGenerator() {
+    protected final DerivativeGenerator<Gradient> getGenerator() {
         return this.generator;
     }
 
diff --git a/src/main/java/org/orekit/rugged/api/Rugged.java b/src/main/java/org/orekit/rugged/api/Rugged.java
index 57fd79bbeb701b67f91e483b65ac63d4074fe2ef..a7f3890a9d6304ed50be475e160bb91f0e7b3fe6 100644
--- a/src/main/java/org/orekit/rugged/api/Rugged.java
+++ b/src/main/java/org/orekit/rugged/api/Rugged.java
@@ -20,10 +20,12 @@ import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.hipparchus.analysis.differentiation.Derivative;
 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.hipparchus.util.MathArrays;
 import org.orekit.bodies.GeodeticPoint;
 import org.orekit.frames.Transform;
 import org.orekit.rugged.errors.DumpManager;
@@ -36,7 +38,7 @@ import org.orekit.rugged.linesensor.SensorMeanPlaneCrossing;
 import org.orekit.rugged.linesensor.SensorPixel;
 import org.orekit.rugged.linesensor.SensorPixelCrossing;
 import org.orekit.rugged.refraction.AtmosphericRefraction;
-import org.orekit.rugged.utils.DSGenerator;
+import org.orekit.rugged.utils.DerivativeGenerator;
 import org.orekit.rugged.utils.ExtendedEllipsoid;
 import org.orekit.rugged.utils.NormalizedGeodeticPoint;
 import org.orekit.rugged.utils.SpacecraftToObservedBody;
@@ -944,6 +946,7 @@ public class Rugged {
     }
 
     /** Compute distances between two line sensors with derivatives.
+     * @param <T> derivative type
      * @param sensorA line sensor A
      * @param dateA current date for sensor A
      * @param pixelA pixel index for sensor A
@@ -955,11 +958,11 @@ public class Rugged {
      * @return distances computed, with derivatives, between LOS and to the ground
      * @see #distanceBetweenLOS(LineSensor, AbsoluteDate, double, SpacecraftToObservedBody, LineSensor, AbsoluteDate, double)
      */
-    public DerivativeStructure[] distanceBetweenLOSderivatives(
+    public <T extends Derivative<T>> T[] distanceBetweenLOSderivatives(
                                  final LineSensor sensorA, final AbsoluteDate dateA, final double pixelA,
                                  final SpacecraftToObservedBody scToBodyA,
                                  final LineSensor sensorB, final AbsoluteDate dateB, final double pixelB,
-                                 final DSGenerator generator) {
+                                 final DerivativeGenerator<T> generator) {
 
         // Compute the approximate transforms between spacecraft and observed body
         // from Rugged instance A
@@ -973,59 +976,63 @@ public class Rugged {
         final Transform transformScToBodyB = new Transform(dateB, scToInertB, inertToBodyB);
 
         // Get sensors LOS into local frame
-        final FieldVector3D<DerivativeStructure> vALocal = sensorA.getLOSDerivatives(dateA, pixelA, generator);
-        final FieldVector3D<DerivativeStructure> vBLocal = sensorB.getLOSDerivatives(dateB, pixelB, generator);
+        final FieldVector3D<T> vALocal = sensorA.getLOSDerivatives(dateA, pixelA, generator);
+        final FieldVector3D<T> vBLocal = sensorB.getLOSDerivatives(dateB, pixelB, generator);
 
         // Get sensors LOS into body frame
-        final FieldVector3D<DerivativeStructure> vA = transformScToBodyA.transformVector(vALocal); // V_a : line of sight's vectorA
-        final FieldVector3D<DerivativeStructure> vB = transformScToBodyB.transformVector(vBLocal); // V_b : line of sight's vectorB
+        final FieldVector3D<T> vA = transformScToBodyA.transformVector(vALocal); // V_a : line of sight's vectorA
+        final FieldVector3D<T> vB = transformScToBodyB.transformVector(vBLocal); // V_b : line of sight's vectorB
 
         // Position of sensors into local frame
         final Vector3D sAtmp = sensorA.getPosition();
         final Vector3D sBtmp = sensorB.getPosition();
 
-        final DerivativeStructure scaleFactor = FieldVector3D.dotProduct(vA.normalize(), vA.normalize()); // V_a.V_a=1
+        final T scaleFactor = FieldVector3D.dotProduct(vA.normalize(), vA.normalize()); // V_a.V_a=1
 
         // Build a vector from the position and a scale factor (equals to 1).
         // The vector built will be scaleFactor * sAtmp for example.
-        final FieldVector3D<DerivativeStructure> sALocal = new FieldVector3D<DerivativeStructure>(scaleFactor, sAtmp);
-        final FieldVector3D<DerivativeStructure> sBLocal = new FieldVector3D<DerivativeStructure>(scaleFactor, sBtmp);
+        final FieldVector3D<T> sALocal = new FieldVector3D<>(scaleFactor, sAtmp);
+        final FieldVector3D<T> sBLocal = new FieldVector3D<>(scaleFactor, sBtmp);
 
         // Get sensors position into body frame
-        final FieldVector3D<DerivativeStructure> sA = transformScToBodyA.transformPosition(sALocal); // S_a : sensorA 's position
-        final FieldVector3D<DerivativeStructure> sB = transformScToBodyB.transformPosition(sBLocal); // S_b : sensorB 's position
+        final FieldVector3D<T> sA = transformScToBodyA.transformPosition(sALocal); // S_a : sensorA 's position
+        final FieldVector3D<T> sB = transformScToBodyB.transformPosition(sBLocal); // S_b : sensorB 's position
 
         // Compute distance
-        final FieldVector3D<DerivativeStructure> vBase = sB.subtract(sA);    // S_b - S_a
-        final DerivativeStructure svA = FieldVector3D.dotProduct(vBase, vA); // SV_a = (S_b - S_a).V_a
-        final DerivativeStructure svB = FieldVector3D.dotProduct(vBase, vB); // SV_b = (S_b - S_a).V_b
+        final FieldVector3D<T> vBase = sB.subtract(sA);    // S_b - S_a
+        final T svA = FieldVector3D.dotProduct(vBase, vA); // SV_a = (S_b - S_a).V_a
+        final T svB = FieldVector3D.dotProduct(vBase, vB); // SV_b = (S_b - S_a).V_b
 
-        final DerivativeStructure vAvB = FieldVector3D.dotProduct(vA, vB); // V_a.V_b
+        final T vAvB = FieldVector3D.dotProduct(vA, vB); // V_a.V_b
 
         // Compute lambda_b = (SV_a * V_a.V_b - SV_b) / (1 - (V_a.V_b)²)
-        final DerivativeStructure lambdaB = (svA.multiply(vAvB).subtract(svB)).divide(vAvB.multiply(vAvB).subtract(1).negate());
+        final T lambdaB = (svA.multiply(vAvB).subtract(svB)).divide(vAvB.multiply(vAvB).subtract(1).negate());
 
         // Compute lambda_a = SV_a + lambdaB * V_a.V_b
-        final DerivativeStructure lambdaA = vAvB.multiply(lambdaB).add(svA);
+        final T lambdaA = vAvB.multiply(lambdaB).add(svA);
 
         // Compute vector M_a:
-        final FieldVector3D<DerivativeStructure> mA = sA.add(vA.scalarMultiply(lambdaA)); // M_a = S_a + lambda_a * V_a
+        final FieldVector3D<T> mA = sA.add(vA.scalarMultiply(lambdaA)); // M_a = S_a + lambda_a * V_a
         // Compute vector M_b
-        final FieldVector3D<DerivativeStructure> mB = sB.add(vB.scalarMultiply(lambdaB)); // M_b = S_b + lambda_b * V_b
+        final FieldVector3D<T> mB = sB.add(vB.scalarMultiply(lambdaB)); // M_b = S_b + lambda_b * V_b
 
         // Compute vector M_a -> M_B for which distance between LOS is minimum
-        final FieldVector3D<DerivativeStructure> vDistanceMin = mB.subtract(mA); // M_b - M_a
+        final FieldVector3D<T> vDistanceMin = mB.subtract(mA); // M_b - M_a
 
         // Compute vector from mid point of vector M_a -> M_B to the ground (corresponds to minimum elevation)
-        final FieldVector3D<DerivativeStructure> midPoint = (mB.add(mA)).scalarMultiply(0.5);
+        final FieldVector3D<T> midPoint = (mB.add(mA)).scalarMultiply(0.5);
 
         // Get the euclidean norms to compute the minimum distances:
         // between LOS
-        final DerivativeStructure dMin = vDistanceMin.getNorm();
+        final T dMin = vDistanceMin.getNorm();
         // to the ground
-        final DerivativeStructure dCentralBody = midPoint.getNorm();
+        final T dCentralBody = midPoint.getNorm();
+
+        final T[] ret = MathArrays.buildArray(dMin.getField(), 2);
+        ret[0] = dMin;
+        ret[1] = dCentralBody;
+        return ret;
 
-        return new DerivativeStructure[] {dMin, dCentralBody};
     }
 
 
@@ -1066,22 +1073,22 @@ public class Rugged {
     }
 
     /** Inverse location of a point with derivatives.
+     * @param <T> derivative type
      * @param sensorName name of the line sensor
      * @param point point to localize
      * @param minLine minimum line number
      * @param maxLine maximum line number
-     * @param generator generator to use for building {@link DerivativeStructure} instances
+     * @param generator generator to use for building {@link Derivative} instances
      * @return sensor pixel seeing point with derivatives, or null if point cannot be seen between the
      * prescribed line numbers
      * @see #inverseLocation(String, GeodeticPoint, int, int)
      * @since 2.0
      */
-
-    public DerivativeStructure[] inverseLocationDerivatives(final String sensorName,
-                                                            final GeodeticPoint point,
-                                                            final int minLine,
-                                                            final int maxLine,
-                                                            final DSGenerator generator) {
+    public <T extends Derivative<T>> T[] inverseLocationDerivatives(final String sensorName,
+                                                                    final GeodeticPoint point,
+                                                                    final int minLine,
+                                                                    final int maxLine,
+                                                                    final DerivativeGenerator<T> generator) {
 
         final LineSensor sensor = getLineSensor(sensorName);
 
@@ -1109,37 +1116,39 @@ 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 FieldVector3D<DerivativeStructure> lowLOS =
+        final FieldVector3D<T> lowLOS =
                         sensor.getLOSDerivatives(crossingResult.getDate(), lowIndex, generator);
-        final FieldVector3D<DerivativeStructure> highLOS = sensor.getLOSDerivatives(crossingResult.getDate(), lowIndex + 1, generator);
-        final FieldVector3D<DerivativeStructure> localZ = FieldVector3D.crossProduct(lowLOS, highLOS).normalize();
-        final DerivativeStructure beta         = FieldVector3D.dotProduct(crossingResult.getTargetDirection(), localZ).acos();
-        final DerivativeStructure s            = FieldVector3D.dotProduct(crossingResult.getTargetDirectionDerivative(), localZ);
-        final DerivativeStructure minusBetaDer = s.divide(s.multiply(s).subtract(1).negate().sqrt());
-        final DerivativeStructure deltaL       = beta.subtract(0.5 * FastMath.PI) .divide(minusBetaDer);
-        final DerivativeStructure fixedLine    = deltaL.add(crossingResult.getLine());
-        final FieldVector3D<DerivativeStructure> fixedDirection =
-                        new FieldVector3D<DerivativeStructure>(deltaL.getField().getOne(), crossingResult.getTargetDirection(),
-                                                               deltaL, crossingResult.getTargetDirectionDerivative()).normalize();
+        final FieldVector3D<T> highLOS = sensor.getLOSDerivatives(crossingResult.getDate(), lowIndex + 1, generator);
+        final FieldVector3D<T> localZ = FieldVector3D.crossProduct(lowLOS, highLOS).normalize();
+        final T beta         = FieldVector3D.dotProduct(crossingResult.getTargetDirection(), localZ).acos();
+        final T s            = FieldVector3D.dotProduct(crossingResult.getTargetDirectionDerivative(), localZ);
+        final T minusBetaDer = s.divide(s.multiply(s).subtract(1).negate().sqrt());
+        final T deltaL       = beta.subtract(0.5 * FastMath.PI) .divide(minusBetaDer);
+        final T fixedLine    = deltaL.add(crossingResult.getLine());
+        final FieldVector3D<T> fixedDirection =
+                        new FieldVector3D<>(deltaL.getField().getOne(), crossingResult.getTargetDirection(),
+                                            deltaL, crossingResult.getTargetDirectionDerivative()).normalize();
 
         // fix neighbouring pixels
         final AbsoluteDate fixedDate  = sensor.getDate(fixedLine.getValue());
-        final FieldVector3D<DerivativeStructure> fixedX = sensor.getLOSDerivatives(fixedDate, lowIndex, generator);
-        final FieldVector3D<DerivativeStructure> fixedZ = FieldVector3D.crossProduct(fixedX, sensor.getLOSDerivatives(fixedDate, lowIndex + 1, generator));
-        final FieldVector3D<DerivativeStructure> fixedY = FieldVector3D.crossProduct(fixedZ, fixedX);
+        final FieldVector3D<T> fixedX = sensor.getLOSDerivatives(fixedDate, lowIndex, generator);
+        final FieldVector3D<T> fixedZ = FieldVector3D.crossProduct(fixedX, sensor.getLOSDerivatives(fixedDate, lowIndex + 1, generator));
+        final FieldVector3D<T> fixedY = FieldVector3D.crossProduct(fixedZ, fixedX);
 
         // fix pixel
-        final DerivativeStructure hY         = FieldVector3D.dotProduct(highLOS, fixedY);
-        final DerivativeStructure hX         = FieldVector3D.dotProduct(highLOS, fixedX);
-        final DerivativeStructure pixelWidth = hY.atan2(hX);
-        final DerivativeStructure fY         = FieldVector3D.dotProduct(fixedDirection, fixedY);
-        final DerivativeStructure fX         = FieldVector3D.dotProduct(fixedDirection, fixedX);
-        final DerivativeStructure alpha      = fY.atan2(fX);
-        final DerivativeStructure fixedPixel = alpha.divide(pixelWidth).add(lowIndex);
-
-        return new DerivativeStructure[] {
-            fixedLine, fixedPixel
-        };
+        final T hY         = FieldVector3D.dotProduct(highLOS, fixedY);
+        final T hX         = FieldVector3D.dotProduct(highLOS, fixedX);
+        final T pixelWidth = hY.atan2(hX);
+        final T fY         = FieldVector3D.dotProduct(fixedDirection, fixedY);
+        final T fX         = FieldVector3D.dotProduct(fixedDirection, fixedX);
+        final T alpha      = fY.atan2(fX);
+        final T fixedPixel = alpha.divide(pixelWidth).add(lowIndex);
+
+        final T[] ret = MathArrays.buildArray(fixedPixel.getField(), 2);
+        ret[0] = fixedLine;
+        ret[1] = fixedPixel;
+        return ret;
+
     }
 
     /** Get transform from spacecraft to inertial frame.
diff --git a/src/main/java/org/orekit/rugged/errors/DumpReplayer.java b/src/main/java/org/orekit/rugged/errors/DumpReplayer.java
index 59adb6528ecfe202015df6911b3ef8cd479ab8ad..fb22fd5d58c4322e0f935a74126c9842b4298328 100644
--- a/src/main/java/org/orekit/rugged/errors/DumpReplayer.java
+++ b/src/main/java/org/orekit/rugged/errors/DumpReplayer.java
@@ -36,7 +36,7 @@ import java.util.TreeMap;
 import java.util.regex.Pattern;
 import java.util.stream.Stream;
 
-import org.hipparchus.analysis.differentiation.DerivativeStructure;
+import org.hipparchus.analysis.differentiation.Derivative;
 import org.hipparchus.exception.LocalizedCoreFormats;
 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
 import org.hipparchus.geometry.euclidean.threed.Rotation;
@@ -63,7 +63,7 @@ import org.orekit.rugged.raster.TileUpdater;
 import org.orekit.rugged.raster.UpdatableTile;
 import org.orekit.rugged.refraction.AtmosphericRefraction;
 import org.orekit.rugged.refraction.MultiLayerModel;
-import org.orekit.rugged.utils.DSGenerator;
+import org.orekit.rugged.utils.DerivativeGenerator;
 import org.orekit.rugged.utils.ExtendedEllipsoid;
 import org.orekit.rugged.utils.SpacecraftToObservedBody;
 import org.orekit.time.AbsoluteDate;
@@ -1215,12 +1215,12 @@ public class DumpReplayer {
 
         /** {@inheritDoc} */
         @Override
-        public FieldVector3D<DerivativeStructure> getLOSDerivatives(final int index, final AbsoluteDate date,
-                                                                    final DSGenerator generator) {
+        public <T extends Derivative<T>> FieldVector3D<T> getLOSDerivatives(final int index, final AbsoluteDate date,
+                                                                            final DerivativeGenerator<T> generator) {
             final Vector3D los = getLOS(index, date);
-            return new FieldVector3D<DerivativeStructure>(generator.constant(los.getX()),
-                                                          generator.constant(los.getY()),
-                                                          generator.constant(los.getZ()));
+            return new FieldVector3D<>(generator.constant(los.getX()),
+                                       generator.constant(los.getY()),
+                                       generator.constant(los.getZ()));
         }
 
         /** Set a datation pair.
diff --git a/src/main/java/org/orekit/rugged/linesensor/LineSensor.java b/src/main/java/org/orekit/rugged/linesensor/LineSensor.java
index c712c7344ad9447bdb406118a8583e435c5cd4fe..ca9fd053173413b20682e728b868f9fad85741c5 100644
--- a/src/main/java/org/orekit/rugged/linesensor/LineSensor.java
+++ b/src/main/java/org/orekit/rugged/linesensor/LineSensor.java
@@ -18,13 +18,13 @@ package org.orekit.rugged.linesensor;
 
 import java.util.stream.Stream;
 
-import org.hipparchus.analysis.differentiation.DerivativeStructure;
+import org.hipparchus.analysis.differentiation.Derivative;
 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
 import org.hipparchus.geometry.euclidean.threed.Vector3D;
 import org.hipparchus.util.FastMath;
 import org.orekit.rugged.errors.DumpManager;
 import org.orekit.rugged.los.TimeDependentLOS;
-import org.orekit.rugged.utils.DSGenerator;
+import org.orekit.rugged.utils.DerivativeGenerator;
 import org.orekit.time.AbsoluteDate;
 import org.orekit.utils.ParameterDriver;
 
@@ -113,37 +113,36 @@ public class LineSensor {
 
     /** Get the pixel normalized line-of-sight at some date,
      * and their derivatives with respect to estimated parameters.
+     * @param <T> derivative type
      * @param date current date
      * @param i pixel index (must be between 0 and {@link #getNbPixels()} - 1
-     * @param generator generator to use for building {@link DerivativeStructure} instances
+     * @param generator generator to use for building {@link Derivative} instances
      * @return pixel normalized line-of-sight
-     * @since 2.0
      */
-    public FieldVector3D<DerivativeStructure> getLOSDerivatives(final AbsoluteDate date, final int i,
-                                                                final DSGenerator generator) {
+    public <T extends Derivative<T>> FieldVector3D<T> getLOSDerivatives(final AbsoluteDate date, final int i,
+                                                                        final DerivativeGenerator<T> generator) {
         return los.getLOSDerivatives(i, date, generator);
     }
 
     /** Get the pixel normalized line-of-sight at some date,
      * and their derivatives with respect to estimated parameters.
+     * @param <T> derivative type
      * @param date current date
      * @param i pixel index (must be between 0 and {@link #getNbPixels()} - 1
-     * @param generator generator to use for building {@link DerivativeStructure} instances
+     * @param generator generator to use for building {@link Derivative} instances
      * @return pixel normalized line-of-sight
      * @since 2.0
      */
-    public FieldVector3D<DerivativeStructure> getLOSDerivatives(final AbsoluteDate date, final double i,
-                                                                final DSGenerator generator) {
+    public <T extends Derivative<T>> FieldVector3D<T> getLOSDerivatives(final AbsoluteDate date, final double i,
+                                                                        final DerivativeGenerator<T> generator) {
 
         // find surrounding pixels of pixelB (in order to interpolate LOS from pixelB (that is not an integer)
         final int iInf = FastMath.max(0, FastMath.min(getNbPixels() - 2, (int) FastMath.floor(i)));
         final int iSup = iInf + 1;
 
-        final FieldVector3D<DerivativeStructure> interpolatedLos = new FieldVector3D<DerivativeStructure> (
-                                                                    iSup - i,
-                                                                    los.getLOSDerivatives(iInf, date, generator),
-                                                                    i - iInf,
-                                                                    los.getLOSDerivatives(iSup, date, generator)).normalize();
+        final FieldVector3D<T> interpolatedLos =
+                        new FieldVector3D<> (iSup - i, los.getLOSDerivatives(iInf, date, generator),
+                                             i - iInf, los.getLOSDerivatives(iSup, date, generator)).normalize();
         return interpolatedLos;
     }
 
diff --git a/src/main/java/org/orekit/rugged/los/FixedRotation.java b/src/main/java/org/orekit/rugged/los/FixedRotation.java
index d2905bb9e13ee28cea2944ce6751f69e71475605..40187de276418cfd0b68d7ca9da3b86192640aa4 100644
--- a/src/main/java/org/orekit/rugged/los/FixedRotation.java
+++ b/src/main/java/org/orekit/rugged/los/FixedRotation.java
@@ -18,14 +18,14 @@ package org.orekit.rugged.los;
 
 import java.util.stream.Stream;
 
-import org.hipparchus.analysis.differentiation.DerivativeStructure;
+import org.hipparchus.analysis.differentiation.Derivative;
 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.rugged.utils.DSGenerator;
+import org.orekit.rugged.utils.DerivativeGenerator;
 import org.orekit.utils.ParameterDriver;
 import org.orekit.utils.ParameterObserver;
 
@@ -50,7 +50,7 @@ public class FixedRotation implements TimeIndependentLOSTransform {
     private Rotation rotation;
 
     /** Underlying rotation with derivatives. */
-    private FieldRotation<DerivativeStructure> rDS;
+    private FieldRotation<?> rDS;
 
     /** Driver for rotation angle. */
     private final ParameterDriver angleDriver;
@@ -96,19 +96,31 @@ public class FixedRotation implements TimeIndependentLOSTransform {
     }
 
     /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
     @Override
-    public FieldVector3D<DerivativeStructure> transformLOS(final int i, final FieldVector3D<DerivativeStructure> los,
-                                                           final DSGenerator generator) {
-        if (rDS == null) {
+    public <T extends Derivative<T>> FieldVector3D<T> transformLOS(final int i, final FieldVector3D<T> los,
+                                                                   final DerivativeGenerator<T> generator) {
+        final FieldRotation<T> rD;
+        if (rDS == null || !rDS.getQ0().getField().equals(generator.getField())) {
+
             // lazy evaluation of the rotation
-            final FieldVector3D<DerivativeStructure> axisDS =
-                            new FieldVector3D<DerivativeStructure>(generator.constant(axis.getX()),
-                                                                   generator.constant(axis.getY()),
-                                                                   generator.constant(axis.getZ()));
-            final DerivativeStructure angleDS = generator.variable(angleDriver);
-            rDS = new FieldRotation<DerivativeStructure>(axisDS, angleDS, RotationConvention.VECTOR_OPERATOR);
+            final FieldVector3D<T> axisDS =
+                            new FieldVector3D<>(generator.constant(axis.getX()),
+                                                generator.constant(axis.getY()),
+                                                generator.constant(axis.getZ()));
+            final T angleDS = generator.variable(angleDriver);
+            rD = new FieldRotation<>(axisDS, angleDS, RotationConvention.VECTOR_OPERATOR);
+
+            // cache evaluated rotation
+            rDS = rD;
+
+        } else {
+            // reuse cached value
+            rD  = (FieldRotation<T>) rDS;
         }
-        return rDS.applyTo(los);
+
+        return rD.applyTo(los);
+
     }
 
 }
diff --git a/src/main/java/org/orekit/rugged/los/FixedZHomothety.java b/src/main/java/org/orekit/rugged/los/FixedZHomothety.java
index 855fcd0a865565489887d408716e591eb47732d4..071b5672b8d04544d44e298a10499d112da102ce 100644
--- a/src/main/java/org/orekit/rugged/los/FixedZHomothety.java
+++ b/src/main/java/org/orekit/rugged/los/FixedZHomothety.java
@@ -18,11 +18,11 @@ package org.orekit.rugged.los;
 
 import java.util.stream.Stream;
 
-import org.hipparchus.analysis.differentiation.DerivativeStructure;
+import org.hipparchus.analysis.differentiation.Derivative;
 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
 import org.hipparchus.geometry.euclidean.threed.Vector3D;
 import org.hipparchus.util.FastMath;
-import org.orekit.rugged.utils.DSGenerator;
+import org.orekit.rugged.utils.DerivativeGenerator;
 import org.orekit.utils.ParameterDriver;
 import org.orekit.utils.ParameterObserver;
 
@@ -46,7 +46,7 @@ public class FixedZHomothety implements TimeIndependentLOSTransform {
     private double factor;
 
     /** Underlying homothety with derivatives. */
-    private DerivativeStructure factorDS;
+    private Derivative<?> factorDS;
 
     /** Driver for homothety factor. */
     private final ParameterDriver factorDriver;
@@ -91,14 +91,26 @@ public class FixedZHomothety implements TimeIndependentLOSTransform {
     }
 
     /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
     @Override
-    public FieldVector3D<DerivativeStructure> transformLOS(final int i, final FieldVector3D<DerivativeStructure> los,
-                                                           final DSGenerator generator) {
-        if (factorDS == null) {
+    public <T extends Derivative<T>> FieldVector3D<T> transformLOS(final int i, final FieldVector3D<T> los,
+                                                                   final DerivativeGenerator<T> generator) {
+        final T factorD;
+        if (factorDS == null || !factorDS.getField().equals(generator.getField())) {
+
             // lazy evaluation of the homothety
-            factorDS = generator.variable(factorDriver);
+            factorD = generator.variable(factorDriver);
+
+            // cache evaluated homothety
+            factorDS = factorD;
+
+        } else {
+            // reuse cached value
+            factorD  = (T) factorDS;
         }
-        return new FieldVector3D<DerivativeStructure>(los.getX(), los.getY(), factorDS.multiply(los.getZ()));
+
+        return new FieldVector3D<>(los.getX(), los.getY(), factorD.multiply(los.getZ()));
+
     }
 
 }
diff --git a/src/main/java/org/orekit/rugged/los/LOSBuilder.java b/src/main/java/org/orekit/rugged/los/LOSBuilder.java
index bfcce6b381763f46ce680d1387fd2fd7fdf18f29..c65796850490c5ffcbdeb59c3caa5c2a09e0e816 100644
--- a/src/main/java/org/orekit/rugged/los/LOSBuilder.java
+++ b/src/main/java/org/orekit/rugged/los/LOSBuilder.java
@@ -21,10 +21,10 @@ import java.util.Arrays;
 import java.util.List;
 import java.util.stream.Stream;
 
-import org.hipparchus.analysis.differentiation.DerivativeStructure;
+import org.hipparchus.analysis.differentiation.Derivative;
 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
 import org.hipparchus.geometry.euclidean.threed.Vector3D;
-import org.orekit.rugged.utils.DSGenerator;
+import org.orekit.rugged.utils.DerivativeGenerator;
 import org.orekit.time.AbsoluteDate;
 import org.orekit.utils.ParameterDriver;
 import org.orekit.utils.ParameterObserver;
@@ -122,8 +122,8 @@ public class LOSBuilder {
 
         /** {@inheritDoc} */
         @Override
-        public FieldVector3D<DerivativeStructure> transformLOS(final int i, final FieldVector3D<DerivativeStructure> los,
-                                                               final AbsoluteDate date, final DSGenerator generator) {
+        public <T extends Derivative<T>> FieldVector3D<T> transformLOS(final int i, final FieldVector3D<T> los,
+                                                                       final AbsoluteDate date, final DerivativeGenerator<T> generator) {
             return transform.transformLOS(i, los, generator);
         }
 
@@ -179,14 +179,13 @@ public class LOSBuilder {
 
         /** {@inheritDoc} */
         @Override
-        public FieldVector3D<DerivativeStructure> getLOSDerivatives(final int index, final AbsoluteDate date,
-                                                                    final DSGenerator generator) {
+        public <T extends Derivative<T>> FieldVector3D<T> getLOSDerivatives(final int index, final AbsoluteDate date,
+                                                                            final DerivativeGenerator<T> generator) {
 
             // the raw line of sights are considered to be constant
-            FieldVector3D<DerivativeStructure> los =
-                            new FieldVector3D<DerivativeStructure>(generator.constant(raw[index].getX()),
-                                                                   generator.constant(raw[index].getY()),
-                                                                   generator.constant(raw[index].getZ()));
+            FieldVector3D<T> los = new FieldVector3D<>(generator.constant(raw[index].getX()),
+                                                       generator.constant(raw[index].getY()),
+                                                       generator.constant(raw[index].getZ()));
 
             // apply the transforms, which depend on parameters and hence may introduce non-zero derivatives
             for (final LOSTransform transform : transforms) {
diff --git a/src/main/java/org/orekit/rugged/los/LOSTransform.java b/src/main/java/org/orekit/rugged/los/LOSTransform.java
index b32af12a654485c9e80d82abf5ae83e2a057b7c5..7fd71d574c401662e96f19351d1904b9e6eb8600 100644
--- a/src/main/java/org/orekit/rugged/los/LOSTransform.java
+++ b/src/main/java/org/orekit/rugged/los/LOSTransform.java
@@ -18,10 +18,11 @@ package org.orekit.rugged.los;
 
 import java.util.stream.Stream;
 
+import org.hipparchus.analysis.differentiation.Derivative;
 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.DSGenerator;
+import org.orekit.rugged.utils.DerivativeGenerator;
 import org.orekit.time.AbsoluteDate;
 import org.orekit.utils.ParameterDriver;
 
@@ -46,14 +47,15 @@ public interface LOSTransform {
      * are typically polynomials coefficients representing rotation angles.
      * These polynomials can be used for example to model thermo-elastic effects.
      * </p>
+     * @param <T> derivative type
      * @param index los pixel index
      * @param los line-of-sight to transform
      * @param date date
      * @param generator generator to use for building {@link DerivativeStructure} instances
      * @return line of sight, and its first partial derivatives with respect to the parameters
      */
-    FieldVector3D<DerivativeStructure> transformLOS(int index, FieldVector3D<DerivativeStructure> los,
-                                                    AbsoluteDate date, DSGenerator generator);
+    <T extends Derivative<T>> FieldVector3D<T> transformLOS(int index, FieldVector3D<T> los,
+                                                            AbsoluteDate date, DerivativeGenerator<T> generator);
 
     /** Get the drivers for LOS parameters.
      * @return drivers for LOS parameters
diff --git a/src/main/java/org/orekit/rugged/los/PolynomialRotation.java b/src/main/java/org/orekit/rugged/los/PolynomialRotation.java
index dec79d1ff21ae5e7b6e8aa98064963416ad2c020..e548781a69f8fa548625a1324075ddad916ab807 100644
--- a/src/main/java/org/orekit/rugged/los/PolynomialRotation.java
+++ b/src/main/java/org/orekit/rugged/los/PolynomialRotation.java
@@ -18,7 +18,8 @@ package org.orekit.rugged.los;
 
 import java.util.stream.Stream;
 
-import org.hipparchus.analysis.differentiation.DerivativeStructure;
+import org.hipparchus.Field;
+import org.hipparchus.analysis.differentiation.Derivative;
 import org.hipparchus.analysis.polynomials.PolynomialFunction;
 import org.hipparchus.geometry.euclidean.threed.FieldRotation;
 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
@@ -26,7 +27,8 @@ 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.rugged.utils.DSGenerator;
+import org.hipparchus.util.MathArrays;
+import org.orekit.rugged.utils.DerivativeGenerator;
 import org.orekit.time.AbsoluteDate;
 import org.orekit.utils.ParameterDriver;
 import org.orekit.utils.ParameterObserver;
@@ -52,10 +54,10 @@ public class PolynomialRotation implements LOSTransform {
     private PolynomialFunction angle;
 
     /** Rotation axis and derivatives. */
-    private FieldVector3D<DerivativeStructure> axisDS;
+    private FieldVector3D<?> axisDS;
 
     /** Rotation angle polynomial and derivatives. */
-    private DerivativeStructure[] angleDS;
+    private Derivative<?>[] angleDS;
 
     /** Reference date for polynomial evaluation. */
     private final AbsoluteDate referenceDate;
@@ -143,30 +145,44 @@ public class PolynomialRotation implements LOSTransform {
     }
 
     /** {@inheritDoc} */
+    @SuppressWarnings("unchecked")
     @Override
-    public FieldVector3D<DerivativeStructure> transformLOS(final int i, final FieldVector3D<DerivativeStructure> los,
-                                                           final AbsoluteDate date, final DSGenerator generator) {
+    public <T extends Derivative<T>> FieldVector3D<T> transformLOS(final int i, final FieldVector3D<T> los,
+                                                                   final AbsoluteDate date,
+                                                                   final DerivativeGenerator<T> generator) {
+
+        final Field<T> field = generator.getField();
+        final FieldVector3D<T> axisD;
+        final T[] angleD;
+        if (axisDS == null || !axisDS.getX().getField().equals(field)) {
 
-        if (angleDS == null) {
             // lazy evaluation of the rotation
-            axisDS = new FieldVector3D<DerivativeStructure>(generator.constant(axis.getX()),
-                                                            generator.constant(axis.getY()),
-                                                            generator.constant(axis.getZ()));
-            angleDS = new DerivativeStructure[coefficientsDrivers.length];
-            for (int k = 0; k < angleDS.length; ++k) {
-                angleDS[k] = generator.variable(coefficientsDrivers[k]);
+            axisD = new FieldVector3D<>(generator.constant(axis.getX()),
+                                        generator.constant(axis.getY()),
+                                        generator.constant(axis.getZ()));
+            angleD = MathArrays.buildArray(field, coefficientsDrivers.length);
+            for (int k = 0; k < angleD.length; ++k) {
+                angleD[k] = generator.variable(coefficientsDrivers[k]);
             }
+
+            // cache evaluated rotation parameters
+            axisDS  = axisD;
+            angleDS = angleD;
+
+        } else {
+            // reuse cached values
+            axisD  = (FieldVector3D<T>) axisDS;
+            angleD = (T[]) angleDS;
         }
+
         // evaluate polynomial, with all its partial derivatives
         final double t = date.durationFrom(referenceDate);
-        DerivativeStructure alpha = axisDS.getX().getField().getZero();
+        T alpha = field.getZero();
         for (int k = angleDS.length - 1; k >= 0; --k) {
-            alpha = alpha.multiply(t).add(angleDS[k]);
+            alpha = alpha.multiply(t).add(angleD[k]);
         }
 
-        return new FieldRotation<DerivativeStructure>(axisDS,
-                                                      alpha,
-                                                      RotationConvention.VECTOR_OPERATOR).applyTo(los);
+        return new FieldRotation<>(axisD, alpha, RotationConvention.VECTOR_OPERATOR).applyTo(los);
 
     }
 
diff --git a/src/main/java/org/orekit/rugged/los/TimeDependentLOS.java b/src/main/java/org/orekit/rugged/los/TimeDependentLOS.java
index 5da881287ab79ba7fc9e3530fe01cf908c6d44f6..d12d6aba476b96f143276acab8c6088030a217c6 100644
--- a/src/main/java/org/orekit/rugged/los/TimeDependentLOS.java
+++ b/src/main/java/org/orekit/rugged/los/TimeDependentLOS.java
@@ -18,10 +18,10 @@ package org.orekit.rugged.los;
 
 import java.util.stream.Stream;
 
-import org.hipparchus.analysis.differentiation.DerivativeStructure;
+import org.hipparchus.analysis.differentiation.Derivative;
 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
 import org.hipparchus.geometry.euclidean.threed.Vector3D;
-import org.orekit.rugged.utils.DSGenerator;
+import org.orekit.rugged.utils.DerivativeGenerator;
 import org.orekit.time.AbsoluteDate;
 import org.orekit.utils.ParameterDriver;
 
@@ -56,14 +56,15 @@ public interface TimeDependentLOS {
      * method must have been set to {@code true} for the various parameters returned
      * by {@link #getParametersDrivers()} that should be estimated.
      * </p>
+     * @param <T> derivative type
      * @param index los pixel index
      * @param date date
-     * @param generator generator to use for building {@link DerivativeStructure} instances
+     * @param generator generator to use for building {@link Derivative} instances
      * @return line of sight, and its first partial derivatives with respect to the parameters
      * @since 2.0
      */
-    FieldVector3D<DerivativeStructure> getLOSDerivatives(int index, AbsoluteDate date,
-                                                         DSGenerator generator);
+    <T extends Derivative<T>> FieldVector3D<T> getLOSDerivatives(int index, AbsoluteDate date,
+                                                                 DerivativeGenerator<T> generator);
 
     /** Get the drivers for LOS parameters.
      * @return drivers for LOS parameters
diff --git a/src/main/java/org/orekit/rugged/los/TimeIndependentLOSTransform.java b/src/main/java/org/orekit/rugged/los/TimeIndependentLOSTransform.java
index 34e9f753ecce410204e75c2cff7f90a57038f34d..6c433a6fb96f8d00776e4441694491a52b77c391 100644
--- a/src/main/java/org/orekit/rugged/los/TimeIndependentLOSTransform.java
+++ b/src/main/java/org/orekit/rugged/los/TimeIndependentLOSTransform.java
@@ -18,10 +18,10 @@ package org.orekit.rugged.los;
 
 import java.util.stream.Stream;
 
-import org.hipparchus.analysis.differentiation.DerivativeStructure;
+import org.hipparchus.analysis.differentiation.Derivative;
 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
 import org.hipparchus.geometry.euclidean.threed.Vector3D;
-import org.orekit.rugged.utils.DSGenerator;
+import org.orekit.rugged.utils.DerivativeGenerator;
 import org.orekit.utils.ParameterDriver;
 
 /** Interface for lines-of-sight tranforms that do not depend on time.
@@ -50,13 +50,14 @@ public interface TimeIndependentLOSTransform {
      * method must have been set to {@code true} for the various parameters returned
      * by {@link #getParametersDrivers()} that should be estimated.
      * </p>
+     * @param <T> derivative type
      * @param index los pixel index
      * @param los line-of-sight to transform
-     * @param generator generator to use for building {@link DerivativeStructure} instances
+     * @param generator generator to use for building {@link Derivative} instances
      * @return line of sight, and its first partial derivatives with respect to the parameters
      */
-    FieldVector3D<DerivativeStructure> transformLOS(int index, FieldVector3D<DerivativeStructure> los,
-                                                    DSGenerator generator);
+    <T extends Derivative<T>> FieldVector3D<T> transformLOS(int index, FieldVector3D<T> los,
+                                                            DerivativeGenerator<T> generator);
 
     /** Get the drivers for LOS parameters.
      * @return drivers for LOS parameters
diff --git a/src/main/java/org/orekit/rugged/utils/DSGenerator.java b/src/main/java/org/orekit/rugged/utils/DSGenerator.java
index 5260cd093c2c3aa2085d21cdb11f8e6ce249b54e..938a32bae1a9290496b322293167d083dc834552 100644
--- a/src/main/java/org/orekit/rugged/utils/DSGenerator.java
+++ b/src/main/java/org/orekit/rugged/utils/DSGenerator.java
@@ -16,8 +16,6 @@
  */
 package org.orekit.rugged.utils;
 
-import java.util.List;
-
 import org.hipparchus.analysis.differentiation.DerivativeStructure;
 import org.orekit.utils.ParameterDriver;
 
@@ -27,29 +25,8 @@ import org.orekit.utils.ParameterDriver;
  * </p>
  * @author Luc Maisonobe
  * @since 2.0
+ * @deprecated as of 2.2, replaced by {@link DerivativeGenerator}
  */
-public interface DSGenerator {
-
-    /** Get the parameters selected for estimation.
-     * @return parameters selected for estimation
-     */
-    List<ParameterDriver> getSelected();
-
-    /** Generate a constant {@link DerivativeStructure}.
-     * @param value value of the constant
-     * @return constant {@link DerivativeStructure}
-     */
-    DerivativeStructure constant(double value);
-
-    /** Generate a {@link DerivativeStructure} representing the
-     * parameter driver either as a canonical variable or a constant.
-     * <p>
-     * The instance created is a variable only if the parameter
-     * has been selected for estimation, otherwise it is a constant.
-     * </p>
-     * @param driver driver for the variable
-     * @return variable {@link DerivativeStructure}
-     */
-    DerivativeStructure variable(ParameterDriver driver);
-
+public interface DSGenerator extends DerivativeGenerator<DerivativeStructure> {
+    // nothing specialized here
 }
diff --git a/src/main/java/org/orekit/rugged/utils/DerivativeGenerator.java b/src/main/java/org/orekit/rugged/utils/DerivativeGenerator.java
new file mode 100644
index 0000000000000000000000000000000000000000..be87b7e7f953114597eb05121f56b8b37d2bf9a7
--- /dev/null
+++ b/src/main/java/org/orekit/rugged/utils/DerivativeGenerator.java
@@ -0,0 +1,64 @@
+/* Copyright 2013-2020 CS GROUP
+ * Licensed to CS GROUP (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 java.util.List;
+
+import org.hipparchus.Field;
+import org.hipparchus.analysis.differentiation.Derivative;
+import org.orekit.utils.ParameterDriver;
+
+/** Generator for {@link Derivative} instances from {@link ParameterDriver}.
+ * <p>
+ * Note that this interface is for Rugged library internal use only.
+ * </p>
+ * @author Luc Maisonobe
+ * @since 2.0
+ */
+public interface DerivativeGenerator<T extends Derivative<T>> {
+
+    /** Get the parameters selected for estimation.
+     * @return parameters selected for estimation
+     */
+    List<ParameterDriver> getSelected();
+
+    /** Generate a constant {@link Derivative}.
+     * @param value value of the constant
+     * @return constant {@link Derivative}
+     */
+    T constant(double value);
+
+    /** Generate a {@link Derivative} representing the
+     * parameter driver either as a canonical variable or a constant.
+     * <p>
+     * The instance created is a variable only if the parameter
+     * has been selected for estimation, otherwise it is a constant.
+     * </p>
+     * @param driver driver for the variable
+     * @return variable {@link Derivative}
+     */
+    T variable(ParameterDriver driver);
+
+    /** Get the {@link Field} to which the generated derivatives belongs.
+     * @return {@link Field} to which the generated derivatives belongs
+     * @since 2.2
+     */
+    default Field<T> getField() {
+        return constant(0).getField();
+    }
+
+}
diff --git a/src/test/java/org/orekit/rugged/adjustment/util/InitInterRefiningTest.java b/src/test/java/org/orekit/rugged/adjustment/util/InitInterRefiningTest.java
index 448c890414050dd49ac99e81fb9929f15eab55b5..e9991d95bfbd75b6eb53484dde11c3cd5297d415 100644
--- a/src/test/java/org/orekit/rugged/adjustment/util/InitInterRefiningTest.java
+++ b/src/test/java/org/orekit/rugged/adjustment/util/InitInterRefiningTest.java
@@ -8,6 +8,7 @@ import java.util.Arrays;
 import java.util.List;
 
 import org.hipparchus.analysis.differentiation.DerivativeStructure;
+import org.hipparchus.analysis.differentiation.Gradient;
 import org.hipparchus.geometry.euclidean.threed.Vector3D;
 import org.hipparchus.random.GaussianRandomGenerator;
 import org.hipparchus.random.UncorrelatedRandomVectorGenerator;
@@ -33,7 +34,7 @@ import org.orekit.rugged.api.Rugged;
 import org.orekit.rugged.api.RuggedBuilder;
 import org.orekit.rugged.linesensor.LineSensor;
 import org.orekit.rugged.linesensor.SensorPixel;
-import org.orekit.rugged.utils.DSGenerator;
+import org.orekit.rugged.utils.DerivativeGenerator;
 import org.orekit.rugged.utils.SpacecraftToObservedBody;
 import org.orekit.time.AbsoluteDate;
 import org.orekit.utils.AngularDerivativesFilter;
@@ -268,11 +269,29 @@ public class InitInterRefiningTest {
      * @param realPixelA real pixel from sensor A
      * @param realPixelB real pixel from sensor B
      * @return the distances of two real pixels computed between LOS and to the ground
+     * @deprecated as of 2.2, replaced by {@link #computeDistancesBetweenLOSGradient(SensorPixel, SensorPixel, double, double)}
      */
     public DerivativeStructure[] computeDistancesBetweenLOSDerivatives(final SensorPixel realPixelA, final SensorPixel realPixelB,
-                                                                       double losDistance, double earthDistance) 
+                                                                       final double losDistance, final double earthDistance) 
         throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
-        
+        final Gradient[] gradient = computeDistancesBetweenLOSGradient(realPixelA, realPixelB, losDistance, earthDistance);
+        final DerivativeStructure[] ds = new DerivativeStructure[gradient.length];
+        for (int i = 0; i < gradient.length; ++i) {
+            ds[i] = gradient[i].toDerivativeStructure();
+        }
+        return ds;
+    }
+
+    /** Compute the distances with derivatives between LOS of two real pixels (one from sensor A and one from sensor B)
+     * @param realPixelA real pixel from sensor A
+     * @param realPixelB real pixel from sensor B
+     * @return the distances of two real pixels computed between LOS and to the ground
+     * @since 2.2
+     */
+    public Gradient[] computeDistancesBetweenLOSGradient(final SensorPixel realPixelA, final SensorPixel realPixelB,
+                                                         final double losDistance, final double earthDistance) 
+        throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+            
         final SpacecraftToObservedBody scToBodyA = ruggedA.getScToBody();
 
         final AbsoluteDate realDateA = lineSensorA.getDate(realPixelA.getLineNumber());
@@ -301,15 +320,14 @@ public class InitInterRefiningTest {
         listLineSensor.addAll(ruggedA.getLineSensors());
         listLineSensor.addAll(ruggedB.getLineSensors());
 
-        DSGenerator generator = (DSGenerator) createGenerator.invoke(optimizationPbBuilder, listLineSensor);
+        @SuppressWarnings("unchecked")
+        DerivativeGenerator<Gradient> generator = (DerivativeGenerator<Gradient>) createGenerator.invoke(optimizationPbBuilder, listLineSensor);
 
-        final DerivativeStructure[] distanceLOSwithDS = ruggedB.distanceBetweenLOSderivatives(
-                                           lineSensorA, realDateA, realPixelA.getPixelNumber(), 
-                                           scToBodyA,
-                                           lineSensorB, realDateB, realPixelB.getPixelNumber(),
-                                           generator);
+        return ruggedB.distanceBetweenLOSderivatives(lineSensorA, realDateA, realPixelA.getPixelNumber(), 
+                                                     scToBodyA,
+                                                     lineSensorB, realDateB, realPixelB.getPixelNumber(),
+                                                     generator);
         
-        return distanceLOSwithDS;
     }
     
     /** Generate noisy measurements (sensor to sensor mapping)
diff --git a/src/test/java/org/orekit/rugged/api/RuggedTest.java b/src/test/java/org/orekit/rugged/api/RuggedTest.java
index dff1e06f328c013e7c7850006c3a9f6dc1ea27de..8d44d62404433a65130d9553ff6221a8670d3ccb 100644
--- a/src/test/java/org/orekit/rugged/api/RuggedTest.java
+++ b/src/test/java/org/orekit/rugged/api/RuggedTest.java
@@ -37,6 +37,7 @@ import java.util.Locale;
 import org.hipparchus.analysis.differentiation.DSFactory;
 import org.hipparchus.analysis.differentiation.DerivativeStructure;
 import org.hipparchus.analysis.differentiation.FiniteDifferencesDifferentiator;
+import org.hipparchus.analysis.differentiation.Gradient;
 import org.hipparchus.analysis.differentiation.UnivariateDifferentiableFunction;
 import org.hipparchus.geometry.euclidean.threed.Rotation;
 import org.hipparchus.geometry.euclidean.threed.RotationConvention;
@@ -77,7 +78,7 @@ import org.orekit.rugged.los.TimeDependentLOS;
 import org.orekit.rugged.raster.RandomLandscapeUpdater;
 import org.orekit.rugged.raster.TileUpdater;
 import org.orekit.rugged.raster.VolcanicConeElevationUpdater;
-import org.orekit.rugged.utils.DSGenerator;
+import org.orekit.rugged.utils.DerivativeGenerator;
 import org.orekit.time.AbsoluteDate;
 import org.orekit.time.TimeScale;
 import org.orekit.time.TimeScalesFactory;
@@ -1170,7 +1171,8 @@ public class RuggedTest {
             java.lang.reflect.Method getGenerator = GroundOptimizationProblemBuilder.class.getSuperclass().getDeclaredMethod("getGenerator");
             getGenerator.setAccessible(true);
 
-            DSGenerator generator = (DSGenerator) getGenerator.invoke(optimizationPbBuilder);
+            @SuppressWarnings("unchecked")
+            DerivativeGenerator<Gradient> generator = (DerivativeGenerator<Gradient>) getGenerator.invoke(optimizationPbBuilder);
 
             double referenceLine = 0.87654 * dimension;
             GeodeticPoint[] gp = rugged.directLocation("line", referenceLine);
@@ -1178,13 +1180,13 @@ public class RuggedTest {
             Method inverseLoc = Rugged.class.getDeclaredMethod("inverseLocationDerivatives",
                                                                String.class, GeodeticPoint.class,
                                                                Integer.TYPE, Integer.TYPE,
-                                                               DSGenerator.class);
+                                                               DerivativeGenerator.class);
             inverseLoc.setAccessible(true);
             int referencePixel = (3 * dimension) / 4;
-            DerivativeStructure[] result = 
-                            (DerivativeStructure[]) inverseLoc.invoke(rugged,
-                                                                      "line", gp[referencePixel], 0, dimension,
-                                                                      generator);
+            Gradient[] result = 
+                            (Gradient[]) inverseLoc.invoke(rugged,
+                                                           "line", gp[referencePixel], 0, dimension,
+                                                           generator);
             Assert.assertEquals(referenceLine,  result[0].getValue(), lineTolerance);
             Assert.assertEquals(referencePixel, result[1].getValue(), pixelTolerance);
             Assert.assertEquals(2, result[0].getFreeParameters());
diff --git a/src/test/java/org/orekit/rugged/errors/DumpReplayerTest.java b/src/test/java/org/orekit/rugged/errors/DumpReplayerTest.java
index 098e2bf697d24cf06d7ebcda40514f151b0bf6da..dd0330c9494c178a12df4fc12c0b9c8dbe809ada 100644
--- a/src/test/java/org/orekit/rugged/errors/DumpReplayerTest.java
+++ b/src/test/java/org/orekit/rugged/errors/DumpReplayerTest.java
@@ -53,7 +53,7 @@ import org.orekit.data.DirectoryCrawler;
 import org.orekit.rugged.api.Rugged;
 import org.orekit.rugged.linesensor.SensorPixel;
 import org.orekit.rugged.refraction.MultiLayerModel;
-import org.orekit.rugged.utils.DSGenerator;
+import org.orekit.rugged.utils.DerivativeGenerator;
 import org.orekit.time.AbsoluteDate;
 import org.orekit.time.TimeScalesFactory;
 import org.orekit.utils.ParameterDriver;
@@ -643,11 +643,11 @@ public class DumpReplayerTest {
  
         // ParsedSensor.getLOSDerivatives
         // Needs some LOS to be set
-        Method getLOSDerivatives = innerClass.getDeclaredMethod("getLOSDerivatives", int.class, AbsoluteDate.class, DSGenerator.class);
+        Method getLOSDerivatives = innerClass.getDeclaredMethod("getLOSDerivatives", int.class, AbsoluteDate.class, DerivativeGenerator.class);
         getLOSDerivatives.setAccessible(true);
 
         final DSFactory factory = new DSFactory(1, 1);
-        DSGenerator generator = new DSGenerator() {
+        DerivativeGenerator<DerivativeStructure> generator = new DerivativeGenerator<DerivativeStructure>() {
             @Override
             public List<ParameterDriver> getSelected() {
                 return null;
diff --git a/src/test/java/org/orekit/rugged/linesensor/FixedRotationTest.java b/src/test/java/org/orekit/rugged/linesensor/FixedRotationTest.java
index d49377ebd9bf15ac6b11a09e988d04c2f6f01715..cad43aeaac0cacb56540a6b8fa05bab3838ea67a 100644
--- a/src/test/java/org/orekit/rugged/linesensor/FixedRotationTest.java
+++ b/src/test/java/org/orekit/rugged/linesensor/FixedRotationTest.java
@@ -40,7 +40,7 @@ import org.junit.Test;
 import org.orekit.rugged.los.FixedRotation;
 import org.orekit.rugged.los.LOSBuilder;
 import org.orekit.rugged.los.TimeDependentLOS;
-import org.orekit.rugged.utils.DSGenerator;
+import org.orekit.rugged.utils.DerivativeGenerator;
 import org.orekit.time.AbsoluteDate;
 import org.orekit.utils.ParameterDriver;
 
@@ -158,7 +158,7 @@ public class FixedRotationTest {
                 driver.setSelected(true);
             }
             final DSFactory factoryS = new DSFactory(selected.size(), 1);
-            DSGenerator generator = new DSGenerator() {
+            DerivativeGenerator<DerivativeStructure> generator = new DerivativeGenerator<DerivativeStructure>() {
 
                 /** {@inheritDoc} */
                 @Override