Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • orekit/rugged
  • sdinot/rugged
  • yzokras/rugged
  • youngcle/rugged-mod
4 results
Show changes
Showing
with 3085 additions and 0 deletions
src/site/resources/images/rugged-architecture.png

35.5 KiB

File added
src/site/resources/images/rugged-git-flow.png

43.3 KiB

src/site/resources/images/rugged-logo-small.jpg

13.4 KiB

src/site/resources/images/rugged-logo.jpg

48.6 KiB

src/site/resources/images/tile-description.png

14.9 KiB

function DirectLocation()
clear all
%Put 'orekit-data.zip' in the current directory, if not I get an error in line 55 %org.orekit.errors.OrekitException: aucune donne d'historique UTC-TAI n'a t charge
% These seems to work if pasted to prompt.
% javaaddpath 'C:\ ... enter your path here ...\MATLAB'
% javaaddpath 'C:\.. enter your path here ...\MATLAB\orekit-7.1.jar'
% javaaddpath 'C:\.. enter your path here ...\\MATLAB\rugged-1.0.jar'
% javaaddpath 'C:\.. enter your path here... \\MATLAB\commons-math3-3.6.1.jar'
%%
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.math3.geometry.euclidean.threed.Rotation;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.orekit.rugged.los.*;
import org.orekit.rugged.utils.*;
%% Configure Orekit. The file orekit-data.zip must be in current dir
import org.orekit.data.ZipJarCrawler
import org.orekit.time.AbsoluteDate
import org.orekit.time.TimeScalesFactory
DM=org.orekit.data.DataProvidersManager.getInstance();
crawler=org.orekit.data.ZipJarCrawler('orekit-data.zip');
DM.clearProviders();
DM.addProvider(crawler);
%%
%The raw viewing direction of pixel i with respect to the instrument is defined by the vector:
rawDirs = ArrayList();
for i =1:2000
%20 field of view, 2000 pixels
rawDirs.add (Vector3D(0,i*deg2rad(20)/2000,1));
end
%The instrument is oriented 10 off nadir around the X-axis, we need to rotate the viewing
%direction to obtain the line of sight in the satellite frame
losBuilder = LOSBuilder(rawDirs);
losBuilder.addTransform(FixedRotation(ParameterType.FIXED, Vector3D.PLUS_I, deg2rad(10)));
lineOfSight = losBuilder.build();
%%
import org.orekit.time.AbsoluteDate;
import org.orekit.time.TimeScalesFactory;
import org.orekit.rugged.linesensor.LinearLineDatation;
%We use Orekit for handling time and dates, and Rugged for defining the datation model:
utc = TimeScalesFactory.getUTC();
absDate = AbsoluteDate('2009-12-11T16:59:30.0', utc);
lineDatation = LinearLineDatation(absDate, 1, 20);
%%
import org.orekit.rugged.linesensor.LineSensor;
%With the LOS and the datation now defined , we can initialize a line sensor object in Rugged:
lineSensor = LineSensor('mySensor', lineDatation, Vector3D.ZERO, lineOfSight);
%%
import org.orekit.frames.*;
import org.orekit.utils.*;
%In our application, we simply need to know the name of the frames we are working with. Positions and
%velocities are given in the ITRF terrestrial frame, while the quaternions are given in EME2000
%inertial frame.
eme2000 = FramesFactory.getEME2000();
simpleEOP = true; % we don't want to compute tiny tidal effects at millimeter level
itrf = FramesFactory.getITRF(IERSConventions.IERS_2010, simpleEOP);
%%
satelliteQList = ArrayList();
gps=TimeScalesFactory.getGPS();
addSatelliteQ(gps, satelliteQList, '2009-12-11T16:58:42.592937', -0.340236, 0.333952, -0.844012, -0.245684);
addSatelliteQ(gps, satelliteQList, '2009-12-11T16:59:06.592937', -0.354773, 0.329336, -0.837871, -0.252281);
addSatelliteQ(gps, satelliteQList, '2009-12-11T16:59:30.592937', -0.369237, 0.324612, -0.831445, -0.258824);
addSatelliteQ(gps, satelliteQList, '2009-12-11T16:59:54.592937', -0.3836, 0.319792, -0.824743, -0.265299);
addSatelliteQ(gps, satelliteQList, '2009-12-11T17:00:18.592937', -0.397834, 0.314883, -0.817777, -0.271695);
addSatelliteQ(gps, satelliteQList, '2009-12-11T17:00:42.592937', -0.411912, 0.309895, -0.810561, -0.278001);
addSatelliteQ(gps, satelliteQList, '2009-12-11T17:01:06.592937', -0.42581, 0.304838, -0.803111, -0.284206);
addSatelliteQ(gps, satelliteQList, '2009-12-11T17:01:30.592937', -0.439505, 0.299722, -0.795442, -0.290301);
addSatelliteQ(gps, satelliteQList, '2009-12-11T17:01:54.592937', -0.452976, 0.294556, -0.787571, -0.296279);
addSatelliteQ(gps, satelliteQList, '2009-12-11T17:02:18.592937', -0.466207, 0.28935, -0.779516, -0.302131);
%%
satellitePVList = ArrayList();
addSatellitePV(gps, eme2000, itrf, satellitePVList, '2009-12-11T16:58:42.592937', -726361.466, -5411878.485, 4637549.599, -2463.635, -4447.634, -5576.736);
addSatellitePV(gps, eme2000, itrf, satellitePVList, '2009-12-11T16:59:04.192937', -779538.267, -5506500.533, 4515934.894, -2459.848, -4312.676, -5683.906);
addSatellitePV(gps, eme2000, itrf, satellitePVList, '2009-12-11T16:59:25.792937', -832615.368, -5598184.195, 4392036.13, -2454.395, -4175.564, -5788.201);
addSatellitePV(gps, eme2000, itrf, satellitePVList, '2009-12-11T16:59:47.392937', -885556.748, -5686883.696, 4265915.971, -2447.273, -4036.368, -5889.568);
addSatellitePV(gps, eme2000, itrf, satellitePVList, '2009-12-11T17:00:08.992937', -938326.32, -5772554.875, 4137638.207, -2438.478, -3895.166, -5987.957);
addSatellitePV(gps, eme2000, itrf, satellitePVList, '2009-12-11T17:00:30.592937', -990887.942, -5855155.21, 4007267.717, -2428.011, -3752.034, -6083.317);
addSatellitePV(gps, eme2000, itrf, satellitePVList, '2009-12-11T17:00:52.192937', -1043205.448, -5934643.836, 3874870.441, -2415.868, -3607.05, -6175.6);
addSatellitePV(gps, eme2000, itrf, satellitePVList, '2009-12-11T17:01:13.792937', -1095242.669, -6010981.571, 3740513.34, -2402.051, -3460.291, -6264.76);
addSatellitePV(gps, eme2000, itrf, satellitePVList, '2009-12-11T17:01:35.392937', -1146963.457, -6084130.93, 3604264.372, -2386.561, -3311.835, -6350.751);
addSatellitePV(gps, eme2000, itrf, satellitePVList, '2009-12-11T17:01:56.992937', -1198331.706, -6154056.146, 3466192.446, -2369.401, -3161.764, -6433.531);
addSatellitePV(gps, eme2000, itrf, satellitePVList, '2009-12-11T17:02:18.592937', -1249311.381, -6220723.191, 3326367.397, -2350.574, -3010.159, -6513.056);
%%
% import org.orekit.rugged.api.AlgorithmId;
% import org.orekit.rugged.api.BodyRotatingFrameId;
% import org.orekit.rugged.api.EllipsoidId;
% import org.orekit.rugged.api.InertialFrameId;
% import org.orekit.rugged.api.Rugged;
import org.orekit.rugged.api.*;
import org.orekit.rugged.errors.RuggedException;
import org.orekit.utils.*;
% import org.orekit.utils.CartesianDerivativesFilter;
rugged=RuggedBuilder();
rugged.setAlgorithm(AlgorithmId.IGNORE_DEM_USE_ELLIPSOID);
rugged.setEllipsoid(EllipsoidId.WGS84, BodyRotatingFrameId.ITRF);
rugged.setTimeSpan(absDate, absDate.shiftedBy(60.0), 0.01, 5 / lineSensor.getRate(0));
rugged.setTrajectory(InertialFrameId.EME2000,...
satellitePVList, 4, CartesianDerivativesFilter.USE_P,...
satelliteQList, 4, AngularDerivativesFilter.USE_R);
rugged.addLineSensor(lineSensor);
Rugged=rugged.build();
%%
import org.orekit.bodies.GeodeticPoint;
position = lineSensor.getPosition(); % This returns a zero vector since we set the relative position of the sensor w.r.T the satellite to 0.
firstLineDate = lineSensor.getDate(0);
los = lineSensor.getLos(firstLineDate, 0);
upLeftPoint = Rugged.directLocation(firstLineDate, position, los);
fprintf('upper left point: Lat = %8.3f , Lon = %8.3f , h = %8.3f m\n',rad2deg(upLeftPoint.getLatitude()), rad2deg(upLeftPoint.getLongitude()),upLeftPoint.getAltitude() )
end
function satelliteQList=addSatelliteQ( gps, satelliteQList ,absDate,q0, q1, q2, q3)
import org.orekit.utils.TimeStampedAngularCoordinates;
import org.orekit.time.AbsoluteDate;
import org.apache.commons.math3.geometry.euclidean.threed.Rotation;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
attitudeDate = AbsoluteDate(absDate, gps);
rotation = Rotation(q0, q1, q2, q3, true);
rotationRate = Vector3D.ZERO;
rotationAcceleration = Vector3D.ZERO;
pair = TimeStampedAngularCoordinates(attitudeDate, rotation, rotationRate, rotationAcceleration);
satelliteQList.add(pair);
end
function satellitePVList= addSatellitePV( gps, eme2000, itrf, satellitePVList, absDate, px, py, pz, vx, vy, vz)
import org.orekit.time.AbsoluteDate;
import org.apache.commons.math3.geometry.euclidean.threed.Rotation;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.orekit.utils.TimeStampedPVCoordinates;
import org.orekit.utils.PVCoordinates;
import org.orekit.frames.Transform;
ephemerisDate = AbsoluteDate(absDate, gps);
position = Vector3D(px, py, pz);
velocity = Vector3D(vx, vy, vz);
pvITRF = PVCoordinates(position, velocity);
transform = itrf.getTransformTo(eme2000, ephemerisDate);
pvEME2000 = transform.transformPVCoordinates(pvITRF);
satellitePVList.add( TimeStampedPVCoordinates(ephemerisDate, pvEME2000.getPosition(), pvEME2000.getVelocity(), Vector3D.ZERO));
end
function InverseLocation()
clear all
%Put 'orekit-data.zip' in the current directory, if not I get an error in line 55 %org.orekit.errors.OrekitException: aucune donne d'historique UTC-TAI n'a t charge
% These seems to work if pasted to prompt.
% javaaddpath 'C:\ ... enter your path here ...\MATLAB'
% javaaddpath 'C:\.. enter your path here ...\MATLAB\orekit-7.1.jar'
% javaaddpath 'C:\.. enter your path here ...\\MATLAB\rugged-1.0.jar'
% javaaddpath 'C:\.. enter your path here... \\MATLAB\commons-math3-3.6.1.jar'
%%
import org.orekit.rugged.errors.RuggedException;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.math3.geometry.euclidean.threed.Rotation;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.orekit.rugged.los.*;
import org.orekit.rugged.utils.*;
%% Configure Orekit. The file orekit-data.zip must be in current dir
% Initialize Orekit, assuming an orekit-data folder is in user home directory
import org.orekit.data.ZipJarCrawler
import org.orekit.time.AbsoluteDate
import org.orekit.time.TimeScalesFactory
DM=org.orekit.data.DataProvidersManager.getInstance();
crawler=org.orekit.data.ZipJarCrawler('orekit-data.zip');
DM.clearProviders();
DM.addProvider(crawler);
%% Building of the LOS
%The raw viewing direction of pixel i with respect to the instrument is defined by the vector:
rawDirs = ArrayList();
for i =1:2000
%20 field of view, 2000 pixels
rawDirs.add (Vector3D(0,i*deg2rad(20)/2000,1));
end
%The instrument is oriented 10 off nadir around the X-axis, we need to rotate the viewing
%direction to obtain the line of sight in the satellite frame
losBuilder = LOSBuilder(rawDirs);
losBuilder.addTransform(FixedRotation(ParameterType.FIXED, Vector3D.PLUS_I, deg2rad(10)));
lineOfSight = losBuilder.build();
%% Configure the Datation
import org.orekit.time.AbsoluteDate;
import org.orekit.time.TimeScalesFactory;
import org.orekit.rugged.linesensor.LinearLineDatation;
%We use Orekit for handling time and dates, and Rugged for defining the datation model:
utc = TimeScalesFactory.getUTC();
absDate = AbsoluteDate('2009-12-11T16:59:30.0', utc);
lineDatation = LinearLineDatation(absDate, 1, 20);
%% Initialize the Line Sensor using LOS and Datation
import org.orekit.rugged.linesensor.LineSensor;
%With the LOS and the datation now defined , we can initialize a line sensor object in Rugged:
sensorName = 'mySensor';
lineSensor = LineSensor(sensorName, lineDatation, Vector3D.ZERO, lineOfSight);
%% Configure Frames (EME2000 and ITRF)
import org.orekit.frames.*;
import org.orekit.utils.*;
%In our application, we simply need to know the name of the frames we are working with. Positions and
%velocities are given in the ITRF terrestrial frame, while the quaternions are given in EME2000
%inertial frame.
eme2000 = FramesFactory.getEME2000();
simpleEOP = true; % we don't want to compute tiny tidal effects at millimeter level
itrf = FramesFactory.getITRF(IERSConventions.IERS_2010, simpleEOP);
%% Reading Quaternions
satelliteQList = ArrayList();
gps=TimeScalesFactory.getGPS();
addSatelliteQ(gps, satelliteQList, '2009-12-11T16:58:42.592937', -0.340236, 0.333952, -0.844012, -0.245684);
addSatelliteQ(gps, satelliteQList, '2009-12-11T16:59:06.592937', -0.354773, 0.329336, -0.837871, -0.252281);
addSatelliteQ(gps, satelliteQList, '2009-12-11T16:59:30.592937', -0.369237, 0.324612, -0.831445, -0.258824);
addSatelliteQ(gps, satelliteQList, '2009-12-11T16:59:54.592937', -0.3836, 0.319792, -0.824743, -0.265299);
addSatelliteQ(gps, satelliteQList, '2009-12-11T17:00:18.592937', -0.397834, 0.314883, -0.817777, -0.271695);
addSatelliteQ(gps, satelliteQList, '2009-12-11T17:00:42.592937', -0.411912, 0.309895, -0.810561, -0.278001);
addSatelliteQ(gps, satelliteQList, '2009-12-11T17:01:06.592937', -0.42581, 0.304838, -0.803111, -0.284206);
addSatelliteQ(gps, satelliteQList, '2009-12-11T17:01:30.592937', -0.439505, 0.299722, -0.795442, -0.290301);
addSatelliteQ(gps, satelliteQList, '2009-12-11T17:01:54.592937', -0.452976, 0.294556, -0.787571, -0.296279);
addSatelliteQ(gps, satelliteQList, '2009-12-11T17:02:18.592937', -0.466207, 0.28935, -0.779516, -0.302131);
%% Reading Potitions/Velocities
satellitePVList = ArrayList();
addSatellitePV(gps, eme2000, itrf, satellitePVList, '2009-12-11T16:58:42.592937', -726361.466, -5411878.485, 4637549.599, -2463.635, -4447.634, -5576.736);
addSatellitePV(gps, eme2000, itrf, satellitePVList, '2009-12-11T16:59:04.192937', -779538.267, -5506500.533, 4515934.894, -2459.848, -4312.676, -5683.906);
addSatellitePV(gps, eme2000, itrf, satellitePVList, '2009-12-11T16:59:25.792937', -832615.368, -5598184.195, 4392036.13, -2454.395, -4175.564, -5788.201);
addSatellitePV(gps, eme2000, itrf, satellitePVList, '2009-12-11T16:59:47.392937', -885556.748, -5686883.696, 4265915.971, -2447.273, -4036.368, -5889.568);
addSatellitePV(gps, eme2000, itrf, satellitePVList, '2009-12-11T17:00:08.992937', -938326.32, -5772554.875, 4137638.207, -2438.478, -3895.166, -5987.957);
addSatellitePV(gps, eme2000, itrf, satellitePVList, '2009-12-11T17:00:30.592937', -990887.942, -5855155.21, 4007267.717, -2428.011, -3752.034, -6083.317);
addSatellitePV(gps, eme2000, itrf, satellitePVList, '2009-12-11T17:00:52.192937', -1043205.448, -5934643.836, 3874870.441, -2415.868, -3607.05, -6175.6);
addSatellitePV(gps, eme2000, itrf, satellitePVList, '2009-12-11T17:01:13.792937', -1095242.669, -6010981.571, 3740513.34, -2402.051, -3460.291, -6264.76);
addSatellitePV(gps, eme2000, itrf, satellitePVList, '2009-12-11T17:01:35.392937', -1146963.457, -6084130.93, 3604264.372, -2386.561, -3311.835, -6350.751);
addSatellitePV(gps, eme2000, itrf, satellitePVList, '2009-12-11T17:01:56.992937', -1198331.706, -6154056.146, 3466192.446, -2369.401, -3161.764, -6433.531);
addSatellitePV(gps, eme2000, itrf, satellitePVList, '2009-12-11T17:02:18.592937', -1249311.381, -6220723.191, 3326367.397, -2350.574, -3010.159, -6513.056);
%% Configure and Build Rugged
import org.orekit.rugged.api.*;
import org.orekit.rugged.errors.RuggedException;
import org.orekit.utils.*;
rugged=RuggedBuilder();
rugged.setAlgorithm(AlgorithmId.IGNORE_DEM_USE_ELLIPSOID);
rugged.setEllipsoid(EllipsoidId.WGS84, BodyRotatingFrameId.ITRF);
rugged.setTimeSpan(absDate, absDate.shiftedBy(60.0), 0.01, 5 / lineSensor.getRate(0));
rugged.setTrajectory(InertialFrameId.EME2000,...
satellitePVList, 4, CartesianDerivativesFilter.USE_P,...
satelliteQList, 4, AngularDerivativesFilter.USE_R);
rugged.addLineSensor(lineSensor);
Rugged=rugged.build();
%% Geodetic Point creation and Inverse Location
%Point defined by its latitude, longitude and altitude
import org.orekit.bodies.GeodeticPoint;
latitude = deg2rad(34.27452);
longitude = deg2rad(-99.56804);
altitude = 0.0;
gp=GeodeticPoint(latitude, longitude, altitude);
% Search the sensor pixel seeing point
% the obteined result must be (1000,1000).
% the above geodetic point coordinates are obteined using DirecLocation.m to
% project the image point (1000,1000) on the ground.
minLine = 950;
maxLine = 1050;
sensorPixel = Rugged.inverseLocation(sensorName, gp, minLine, maxLine);
%% Test of the result and Print outputs
%we need to test if the sensor pixel is found in the prescribed lines
%otherwise the sensor pixel is empty
if (isempty(sensorPixel))
fprintf('Sensor Pixel is Empty: point cannot be seen between the prescribed line numbers\n')
else
fprintf('Sensor Pixel found : line = %5.3f, pixel = %5.3f \n', sensorPixel.getLineNumber(), sensorPixel.getPixelNumber())
%Find the date at which the sensor sees the ground point
dateLine = Rugged.dateLocation(sensorName, gp, minLine, maxLine);
fprintf(['Date at which the sensor sees the ground point :', char(dateLine.toString()),'\n'])
end
end
%% read Quaternions Function
function satelliteQList=addSatelliteQ( gps, satelliteQList ,absDate,q0, q1, q2, q3)
import org.orekit.utils.TimeStampedAngularCoordinates;
import org.orekit.time.AbsoluteDate;
import org.apache.commons.math3.geometry.euclidean.threed.Rotation;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
attitudeDate = AbsoluteDate(absDate, gps);
rotation = Rotation(q0, q1, q2, q3, true);
rotationRate = Vector3D.ZERO;
rotationAcceleration = Vector3D.ZERO;
pair = TimeStampedAngularCoordinates(attitudeDate, rotation, rotationRate, rotationAcceleration);
satelliteQList.add(pair);
end
%% read Position/Velocity Function
function satellitePVList= addSatellitePV( gps, eme2000, itrf, satellitePVList, absDate, px, py, pz, vx, vy, vz)
import org.orekit.time.AbsoluteDate;
import org.apache.commons.math3.geometry.euclidean.threed.Rotation;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.orekit.utils.TimeStampedPVCoordinates;
import org.orekit.utils.PVCoordinates;
import org.orekit.frames.Transform;
ephemerisDate = AbsoluteDate(absDate, gps);
position = Vector3D(px, py, pz);
velocity = Vector3D(vx, vy, vz);
pvITRF = PVCoordinates(position, velocity);
transform = itrf.getTransformTo(eme2000, ephemerisDate);
pvEME2000 = transform.transformPVCoordinates(pvITRF);
satellitePVList.add( TimeStampedPVCoordinates(ephemerisDate, pvEME2000.getPosition(), pvEME2000.getVelocity(), Vector3D.ZERO));
end
%In this example we aim to create the rugged object based on the DIM file (in xml format).
%Dimap is a format file used to provide interior and exterior orientation
%elements, this format is used by several satellites such: SPOT5,
%Formosat, THEOS, ALSAT-2A, KOMPSAT-2 and other.
%Except SPOT5 and Formosat, the interior orientation parameters are
%given in the form of polynomial coefficients that allow the estimation of the
%look direction of a considered pixel in a frame called RLOS and also the
%Bias angles to transform the look directions from RLOS to RSAT.
%(see: DOI 10.1007/s12524-014-0380-x and doi:10.5194/isprsarchives-XL-1-W1-35-2013)
%as an example for THEOS Dimap file see:
%http://ortho-qgis.googlecode.com/svn/trunk/Chiangmai1Dimap.xml
%This example has been tested and works also using ALSAT-2A DIM file.
function dim2rugged()
clear all
%Put 'orekit-data.zip' in the current directory, if not I get an error in line 55 %org.orekit.errors.OrekitException: aucune donnée d'historique UTC-TAI n'a été chargée
% These seems to work if pasted to prompt.
% javaaddpath 'C:\ ... enter your path here ...\MATLAB'
% javaaddpath 'C:\.. enter your path here ...\MATLAB\orekit-7.1.jar'
% javaaddpath 'C:\.. enter your path here ...\\MATLAB\rugged-1.0.jar'
% javaaddpath 'C:\.. enter your path here... \\MATLAB\commons-math3-3.6.1.jar'
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
dimFile='Chiangmai1Dimap.xml';
%terrainaltitude is the altitude of the ground intersection point
terrainAltitude=800;
%this function returns a RuggedBuilder based on DIM file and a nominal terrainAltitude
ruggedBuilder= Dim2RuggedBuilderObj(dimFile,terrainAltitude);
%the terrainAltitude can be changed using ruggedBuilder.setConstantElevation(terrainAltitude);
%then dimRugged=ruggedBuilder.build(); must be called to create a new Rugged that
%allow the direct location at a different terrain altitude without parsing
%the DIM file again.
dimRugged=ruggedBuilder.build();
%This exemple consider the PAN image only where the sensor line is called
%PAN Sensor
lineSensor=dimRugged.getLineSensor('PAN Sensor');
%Get the LOS and the datation of the first pixel of the image
position = lineSensor.getPosition();
lineDate = lineSensor.getDate(0);
los = lineSensor.getLos(lineDate, 0);
%Get the corresponding ground coordinates of the considered pixel at terrainAltitude
upLeftPoint = dimRugged.directLocation(lineDate, position, los);
%Print the results
fprintf('upper left point: Lat = %8.6f °, Lon = %8.6f °, h = %8.2f m\n',rad2deg(upLeftPoint.getLatitude()), rad2deg(upLeftPoint.getLongitude()),upLeftPoint.getAltitude() )
end
function ruggedBuilder= Dim2RuggedBuilderObj(dimFile,terrainAltitude)
% This function creates a RuggedBuilder object based on DIM file
% The intersection are done at terrainAltitude, when this object is used for DirectLocation
%% Configure Orekit. The file orekit-data.zip must be in current dir
import org.orekit.data.ZipJarCrawler
import org.orekit.time.AbsoluteDate
import org.orekit.time.TimeScalesFactory
DM=org.orekit.data.DataProvidersManager.getInstance();
crawler=org.orekit.data.ZipJarCrawler('orekit-data.zip');
DM.clearProviders();
DM.addProvider(crawler);
%%
%Read XML document and get Document Object Model node
xDoc = xmlread(dimFile);
%REFERENCE_TIME is the time of imaging of the REFERENCE_LINE
Element='REFERENCE_TIME';
referenceTime=GetElementValue(Element,xDoc);
%FormatTime to get the read time in the standard format
referenceTime=FormatTime(referenceTime);
%LINE_PERIOD is the time required to record an image line
Element='LINE_PERIOD';
%LineRate is the inverse of the line period
lineRate=1/(str2double(GetElementValue(Element,xDoc)));
%REFERENCE_LINE the line used for datation reference
Element='REFERENCE_LINE';
referenceLine=str2double(GetElementValue(Element,xDoc));
%NROWS the number of Rows
Element='NROWS';
nRows=str2double(GetElementValue(Element,xDoc));
%NCOLS the number of columns
Element='NCOLS';
nCols=str2double(GetElementValue(Element,xDoc));
%YAW, PITCH, ROLL are the angles between RLOS and RSAT, where RLOS is the
%frame where the los are measured and RSAT is the frame tied to the
%spacecraft where the quatenions represent the rotaion between RSAT and
%EME2000
Element='YAW';
yaw=str2double(GetElementValue(Element,xDoc));
Element='PITCH';
pitch=str2double(GetElementValue(Element,xDoc));
Element='ROLL';
roll=str2double(GetElementValue(Element,xDoc));
%XLOS_i and YLOS_i are the polynomial coefficiens that allow the
%calculation of LOS direction of each pixel in RLOS
%(see: DOI 10.1007/s12524-014-0380-x)
Element='XLOS_3';
xLosPoly=str2double(GetElementValue(Element,xDoc));
Element='XLOS_2';
xLosPoly=[xLosPoly, str2double(GetElementValue(Element,xDoc))];
Element='XLOS_1';
xLosPoly=[xLosPoly, str2double(GetElementValue(Element,xDoc))];
Element='XLOS_0';
xLosPoly=[xLosPoly, str2double(GetElementValue(Element,xDoc))];
Element='YLOS_3';
yLosPoly=str2double(GetElementValue(Element,xDoc));
Element='YLOS_2';
yLosPoly=[yLosPoly, str2double(GetElementValue(Element,xDoc))];
Element='YLOS_1';
yLosPoly=[yLosPoly, str2double(GetElementValue(Element,xDoc))];
Element='YLOS_0';
yLosPoly=[yLosPoly, str2double(GetElementValue(Element,xDoc))];
%%
quaternions = xDoc.getElementsByTagName('Quaternion');
%read the Quaternions into the arraylist
satelliteQList=ParseQuaternions(quaternions);
%%
pv = xDoc.getElementsByTagName('Point');
%read the Positions/Velocities into the arraylist
satellitePVList=ParsePV(pv);
%%
%Build the LOS based on whole pushbroom size (ncols), the polynomial
%describing the LOS and bias angles (yaw,pitch,roll)
lineOfSight=LosBuilding(nCols,xLosPoly,yLosPoly,yaw,pitch,roll);
%%
import org.orekit.time.AbsoluteDate;
import org.orekit.time.TimeScalesFactory;
import org.orekit.rugged.linesensor.LinearLineDatation;
%setup of the datation
gps = TimeScalesFactory.getGPS();
absDate = AbsoluteDate(referenceTime, gps);
lineDatation = LinearLineDatation(absDate, referenceLine, lineRate);
%%
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.orekit.rugged.linesensor.LineSensor;
%With the LOS and the datation now defined , we can initialize a line sensor object in Rugged:
lineSensor = LineSensor('PAN Sensor', lineDatation, Vector3D.ZERO, lineOfSight);
%%
import org.orekit.rugged.api.*;
import org.orekit.rugged.errors.RuggedException;
import org.orekit.utils.*;
ruggedBuilder=RuggedBuilder();
%the intersection during the direct location will be at "terrainAltitude"
ruggedBuilder.setConstantElevation(terrainAltitude);
ruggedBuilder.setAlgorithm(AlgorithmId.CONSTANT_ELEVATION_OVER_ELLIPSOID);
ruggedBuilder.setEllipsoid(EllipsoidId.WGS84, BodyRotatingFrameId.ITRF);
captureDuration=(nRows+100)/ lineSensor.getRate(0);
ruggedBuilder.setTimeSpan(absDate, absDate.shiftedBy(captureDuration), 0.001, 5 / lineSensor.getRate(0));
ruggedBuilder.setTrajectory(InertialFrameId.EME2000,...
satellitePVList, 4, CartesianDerivativesFilter.USE_P,...
satelliteQList, 4, AngularDerivativesFilter.USE_R);
ruggedBuilder.addLineSensor(lineSensor);
end
function lineOfSight=LosBuilding(nCols,xLosPoly,yLosPoly,yaw,pitch,roll)
import java.util.ArrayList;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.orekit.rugged.los.*;
import org.orekit.rugged.utils.*;
rawDirs = ArrayList();
for i =1:nCols
psiY = -polyval(xLosPoly,i)/1000;
psiX = polyval(yLosPoly,i)/1000;
rawDirs.add (Vector3D(psiX,psiY,1));
end
losBuilder = LOSBuilder(rawDirs);
losBuilder.addTransform(FixedRotation(ParameterType.FIXED, Vector3D.PLUS_K,yaw));
losBuilder.addTransform(FixedRotation(ParameterType.FIXED, Vector3D.PLUS_J,pitch));
losBuilder.addTransform(FixedRotation(ParameterType.FIXED, Vector3D.PLUS_I,roll));
lineOfSight = losBuilder.build();
end
function valElement=GetElementValue(element,xDoc)
% valElement=GetElementValue(element,xDoc) returne a string contained in
% the corresponding "element" in the XML "xDoc" file
valElement=char(xDoc.getElementsByTagName(element).item(0).getTextContent);
end
function time=FormatTime(time)
%FormatTime replace the space contained the time string by "T"
position=strfind(time,' ');
time(position)='T';
end
function satellitePVList=ParsePV(pv)
%ParsePV parse the "Point" element in the dimap file to get an ArrayList
import java.util.ArrayList;
import java.util.List;
import org.orekit.time.TimeScalesFactory;
import org.orekit.frames.*;
import org.orekit.utils.*;
satellitePVList = ArrayList();
gps=TimeScalesFactory.getGPS();
eme2000 = FramesFactory.getEME2000();
simpleEOP = true; % we don't want to compute tiny tidal effects at millimeter level
itrf = FramesFactory.getITRF(IERSConventions.IERS_2010, simpleEOP);
nPV = pv.getLength;
position=[];
velocity=[];
for i=0:nPV - 1
entries = pv.item(i).getChildNodes;
node = entries.getFirstChild;
while ~isempty(node)
if strcmpi(node.getNodeName, 'TIME')
T= FormatTime(char(node.getTextContent));
end
if strcmpi(node.getNodeName, 'Location')
position= str2num(char(node.getTextContent));
end
if strcmpi(node.getNodeName, 'Velocity')
velocity= str2num(char(node.getTextContent));
end
node = node.getNextSibling;
end
addSatellitePV(gps, eme2000, itrf, satellitePVList, T, position(1), position(2), position(3), velocity(1), velocity(2), velocity(3));
end
end
function satelliteQList=ParseQuaternions(quaternions)
%ParseQuaternions parse the "Quaternion" element in the dimap file to get an ArrayList
import java.util.ArrayList;
import java.util.List;
import org.orekit.time.TimeScalesFactory;
satelliteQList = ArrayList();
gps=TimeScalesFactory.getGPS();
nQuaternions=quaternions.getLength;
for i=0:nQuaternions - 1
entries = quaternions.item(i).getChildNodes;
node = entries.getFirstChild;
while ~isempty(node)
if strcmpi(node.getNodeName, 'TIME')
T= FormatTime(char(node.getTextContent));
end
if strcmpi(node.getNodeName, 'Q0')
Q0= str2double(char(node.getTextContent));
end
if strcmpi(node.getNodeName, 'Q1')
Q1= str2double(char(node.getTextContent));
end
if strcmpi(node.getNodeName, 'Q2')
Q2= str2double(char(node.getTextContent));
end
if strcmpi(node.getNodeName, 'Q3')
Q3= str2double(char(node.getTextContent));
end
node = node.getNextSibling;
end
addSatelliteQ(gps, satelliteQList, T, Q0, Q1, Q2, Q3);
end
end
function satelliteQList=addSatelliteQ( gps, satelliteQList ,absDate,q0, q1, q2, q3)
import org.orekit.utils.TimeStampedAngularCoordinates;
import org.orekit.time.AbsoluteDate;
import org.apache.commons.math3.geometry.euclidean.threed.Rotation;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
attitudeDate = AbsoluteDate(absDate, gps);
rotation = Rotation(q0, q1, q2, q3, true);
rotationRate = Vector3D.ZERO;
rotationAcceleration = Vector3D.ZERO;
pair = TimeStampedAngularCoordinates(attitudeDate, rotation, rotationRate, rotationAcceleration);
satelliteQList.add(pair);
end
function satellitePVList= addSatellitePV( gps, eme2000, itrf, satellitePVList, absDate, px, py, pz, vx, vy, vz)
import org.orekit.time.AbsoluteDate;
import org.apache.commons.math3.geometry.euclidean.threed.Rotation;
import org.apache.commons.math3.geometry.euclidean.threed.Vector3D;
import org.orekit.utils.TimeStampedPVCoordinates;
import org.orekit.utils.PVCoordinates;
import org.orekit.frames.Transform;
ephemerisDate = AbsoluteDate(absDate, gps);
position = Vector3D(px, py, pz);
velocity = Vector3D(vx, vy, vz);
pvITRF = PVCoordinates(position, velocity);
transform = itrf.getTransformTo(eme2000, ephemerisDate);
pvEME2000 = transform.transformPVCoordinates(pvITRF);
satellitePVList.add( TimeStampedPVCoordinates(ephemerisDate, pvEME2000.getPosition(), pvEME2000.getVelocity(), Vector3D.ZERO));
end
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 2013-2022 CS GROUP
Licensed 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.
-->
<project name="Rugged">
<bannerLeft>
<name>CS GROUP</name>
<src>/images/logo_cs_group.png</src>
<href>https://www.csgroup.eu/</href>
</bannerLeft>
<bannerRight>
<name>Rugged</name>
<src>/images/rugged-logo-small.jpg</src>
<href>/index.html</href>
</bannerRight>
<body>
<menu name="Rugged">
<item name="Overview" href="/index.html" />
<item name="Getting the sources" href="/sources.html" />
<item name="Building" href="/building.html" />
<item name="Configuration" href="/configuration.html" />
<item name="FAQ" href="/faq.html" />
<item name="License" href="/licenses.html" />
<item name="Downloads" href="/downloads.html" />
<item name="Changes" href="/changes-report.html" />
<item name="Contact" href="/contact.html" />
</menu>
<menu name="Design">
<item name="Overview" href="/design/overview.html" />
<item name="Technical choices" href="/design/technical-choices.html" />
<item name="Digital Elevation Model" href="/design/digital-elevation-model.html" />
<item name="Design of the major functions" href="/design/design-major-functions.html" />
</menu>
<menu name="Tutorials">
<item name="Direct location" href="/tutorials/direct-location.html" />
<item name="Direct location with DEM" href="/tutorials/direct-location-with-DEM.html" />
<item name="Inverse location" href="/tutorials/inverse-location.html" />
<item name="Matlab examples" href="/tutorials/matlab-example.html" />
</menu>
<menu name="Development">
<item name="Contributing" href="/contributing.html" />
<item name="Guidelines" href="/guidelines.html" />
<item name="Javadoc" href="/apidocs/index.html" />
<item name="Release guide" href="/release-guide.html" />
</menu>
<menu ref="reports"/>
</body>
<poweredBy>
<logo name="orekit"
href="https://www.orekit.org/"
img="/images/orekit-logo.png"
alt="orekit"
width="100" />
</poweredBy>
</project>
/* Copyright 2013-2022 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;
import static org.junit.Assert.assertEquals;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.hipparchus.geometry.euclidean.threed.Rotation;
import org.hipparchus.geometry.euclidean.threed.RotationConvention;
import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.hipparchus.ode.nonstiff.DormandPrince853Integrator;
import org.hipparchus.util.FastMath;
import org.junit.Assert;
import org.orekit.attitudes.AttitudeProvider;
import org.orekit.attitudes.NadirPointing;
import org.orekit.attitudes.YawCompensation;
import org.orekit.bodies.BodyShape;
import org.orekit.bodies.CelestialBodyFactory;
import org.orekit.bodies.GeodeticPoint;
import org.orekit.bodies.OneAxisEllipsoid;
import org.orekit.data.DataContext;
import org.orekit.forces.gravity.HolmesFeatherstoneAttractionModel;
import org.orekit.forces.gravity.ThirdBodyAttraction;
import org.orekit.forces.gravity.potential.GravityFieldFactory;
import org.orekit.forces.gravity.potential.NormalizedSphericalHarmonicsProvider;
import org.orekit.frames.Frame;
import org.orekit.frames.FramesFactory;
import org.orekit.frames.Transform;
import org.orekit.orbits.CircularOrbit;
import org.orekit.orbits.FieldCartesianOrbit;
import org.orekit.orbits.FieldCircularOrbit;
import org.orekit.orbits.FieldEquinoctialOrbit;
import org.orekit.orbits.FieldKeplerianOrbit;
import org.orekit.orbits.Orbit;
import org.orekit.orbits.OrbitType;
import org.orekit.orbits.PositionAngle;
import org.orekit.propagation.Propagator;
import org.orekit.propagation.SpacecraftState;
import org.orekit.propagation.analytical.KeplerianPropagator;
import org.orekit.propagation.numerical.NumericalPropagator;
import org.orekit.propagation.semianalytical.dsst.utilities.JacobiPolynomials;
import org.orekit.propagation.semianalytical.dsst.utilities.NewcombOperators;
import org.orekit.rugged.linesensor.SensorPixel;
import org.orekit.rugged.los.LOSBuilder;
import org.orekit.rugged.los.TimeDependentLOS;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.TimeScale;
import org.orekit.time.TimeScalesFactory;
import org.orekit.utils.Constants;
import org.orekit.utils.IERSConventions;
import org.orekit.utils.PVCoordinates;
import org.orekit.utils.TimeStampedAngularCoordinates;
import org.orekit.utils.TimeStampedPVCoordinates;
/**
* @author Luc Maisonobe
* @author Guylaine Prat
*/
public class TestUtils {
/**
* Clean up of factories for JUnit
* TBN: copied from Utils of Test suite of Orekit 9.0
* @since 2.0
*/
public static void clearFactories() {
clearFactoryMaps(CelestialBodyFactory.class);
CelestialBodyFactory.clearCelestialBodyLoaders();
clearFactoryMaps(FramesFactory.class);
clearFactoryMaps(TimeScalesFactory.class);
clearFactory(TimeScalesFactory.class, TimeScale.class);
clearFactoryMaps(FieldCartesianOrbit.class);
clearFactoryMaps(FieldKeplerianOrbit.class);
clearFactoryMaps(FieldCircularOrbit.class);
clearFactoryMaps(FieldEquinoctialOrbit.class);
clearFactoryMaps(JacobiPolynomials.class);
clearFactoryMaps(NewcombOperators.class);
for (final Class<?> c : NewcombOperators.class.getDeclaredClasses()) {
if (c.getName().endsWith("PolynomialsGenerator")) {
clearFactoryMaps(c);
}
}
FramesFactory.clearEOPHistoryLoaders();
FramesFactory.setEOPContinuityThreshold(5 * Constants.JULIAN_DAY);
TimeScalesFactory.clearUTCTAIOffsetsLoaders();
GravityFieldFactory.clearPotentialCoefficientsReaders();
GravityFieldFactory.clearOceanTidesReaders();
DataContext.getDefault().getDataProvidersManager().clearProviders();
DataContext.getDefault().getDataProvidersManager().clearLoadedDataNames();
}
/** Clean up of factory map
* @param factoryClass
* @since 2.0
*/
private static void clearFactoryMaps(Class<?> factoryClass) {
try {
for (Field field : factoryClass.getDeclaredFields()) {
if (Modifier.isStatic(field.getModifiers()) &&
Map.class.isAssignableFrom(field.getType())) {
field.setAccessible(true);
((Map<?, ?>) field.get(null)).clear();
}
}
} catch (IllegalAccessException iae) {
Assert.fail(iae.getMessage());
}
}
/** Clean up of a factory
* @param factoryClass
* @param cachedFieldsClass
* @since 2.0
*/
private static void clearFactory(Class<?> factoryClass, Class<?> cachedFieldsClass) {
try {
for (Field field : factoryClass.getDeclaredFields()) {
if (Modifier.isStatic(field.getModifiers()) &&
cachedFieldsClass.isAssignableFrom(field.getType())) {
field.setAccessible(true);
field.set(null, null);
}
}
} catch (IllegalAccessException iae) {
Assert.fail(iae.getMessage());
}
}
/**
* Generate satellite ephemeris.
*/
public static void addSatellitePV(TimeScale gps, Frame eme2000, Frame itrf,
ArrayList<TimeStampedPVCoordinates> satellitePVList,
String absDate,
double px, double py, double pz, double vx, double vy, double vz) {
AbsoluteDate ephemerisDate = new AbsoluteDate(absDate, gps);
Vector3D position = new Vector3D(px, py, pz);
Vector3D velocity = new Vector3D(vx, vy, vz);
PVCoordinates pvITRF = new PVCoordinates(position, velocity);
Transform transform = itrf.getTransformTo(eme2000, ephemerisDate);
Vector3D pEME2000 = transform.transformPosition(pvITRF.getPosition());
Vector3D vEME2000 = transform.transformVector(pvITRF.getVelocity());
satellitePVList.add(new TimeStampedPVCoordinates(ephemerisDate, pEME2000, vEME2000, Vector3D.ZERO));
}
/**
* Generate satellite attitudes.
*/
public static void addSatelliteQ(TimeScale gps, ArrayList<TimeStampedAngularCoordinates> satelliteQList,
String absDate, double q0, double q1, double q2, double q3) {
AbsoluteDate attitudeDate = new AbsoluteDate(absDate, gps);
Rotation rotation = new Rotation(q0, q1, q2, q3, true);
TimeStampedAngularCoordinates pair =
new TimeStampedAngularCoordinates(attitudeDate, rotation, Vector3D.ZERO, Vector3D.ZERO);
satelliteQList.add(pair);
}
/** Create an Earth for Junit tests.
*/
public static BodyShape createEarth() {
return new OneAxisEllipsoid(Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
Constants.WGS84_EARTH_FLATTENING,
FramesFactory.getITRF(IERSConventions.IERS_2010, true));
}
/** Created a gravity field.
* @return normalized spherical harmonics coefficients
*/
public static NormalizedSphericalHarmonicsProvider createGravityField() {
return GravityFieldFactory.getNormalizedProvider(12, 12);
}
/** Create an orbit.
* @param mu Earth gravitational constant
* @return the orbit
*/
public static Orbit createOrbit(double mu) {
// the following orbital parameters have been computed using
// Orekit tutorial about phasing, using the following configuration:
//
// orbit.date = 2012-01-01T00:00:00.000
// phasing.orbits.number = 143
// phasing.days.number = 10
// sun.synchronous.reference.latitude = 0
// sun.synchronous.reference.ascending = false
// sun.synchronous.mean.solar.time = 10:30:00
// gravity.field.degree = 12
// gravity.field.order = 12
AbsoluteDate date = new AbsoluteDate("2012-01-01T00:00:00.000", TimeScalesFactory.getUTC());
Frame eme2000 = FramesFactory.getEME2000();
return new CircularOrbit(7173352.811913891,
-4.029194321683225E-4, 0.0013530362644647786,
FastMath.toRadians(98.63218182243709),
FastMath.toRadians(77.55565567747836),
FastMath.PI, PositionAngle.TRUE,
eme2000, date, mu);
}
/** Create the propagator of an orbit.
* @return propagator of the orbit
*/
public static Propagator createPropagator(BodyShape earth,
NormalizedSphericalHarmonicsProvider gravityField,
Orbit orbit) {
AttitudeProvider yawCompensation = new YawCompensation(orbit.getFrame(), new NadirPointing(orbit.getFrame(), earth));
SpacecraftState state = new SpacecraftState(orbit,
yawCompensation.getAttitude(orbit,
orbit.getDate(),
orbit.getFrame()),
1180.0);
// numerical model for improving orbit
OrbitType type = OrbitType.CIRCULAR;
double[][] tolerances = NumericalPropagator.tolerances(0.1, orbit, type);
DormandPrince853Integrator integrator =
new DormandPrince853Integrator(1.0e-4 * orbit.getKeplerianPeriod(),
1.0e-1 * orbit.getKeplerianPeriod(),
tolerances[0], tolerances[1]);
integrator.setInitialStepSize(1.0e-2 * orbit.getKeplerianPeriod());
NumericalPropagator numericalPropagator = new NumericalPropagator(integrator);
numericalPropagator.addForceModel(new HolmesFeatherstoneAttractionModel(earth.getBodyFrame(), gravityField));
numericalPropagator.addForceModel(new ThirdBodyAttraction(CelestialBodyFactory.getSun()));
numericalPropagator.addForceModel(new ThirdBodyAttraction(CelestialBodyFactory.getMoon()));
numericalPropagator.setOrbitType(type);
numericalPropagator.setInitialState(state);
numericalPropagator.setAttitudeProvider(yawCompensation);
return numericalPropagator;
}
/** Create a perfect Line Of Sight list
* @return the perfect LOS list
*/
public static LOSBuilder createLOSPerfectLine(Vector3D center, Vector3D normal, double halfAperture, int n) {
List<Vector3D> list = new ArrayList<Vector3D>(n);
for (int i = 0; i < n; ++i) {
double alpha = (halfAperture * (2 * i + 1 - n)) / (n - 1);
list.add(new Rotation(normal, alpha, RotationConvention.VECTOR_OPERATOR).applyTo(center));
}
return new LOSBuilder(list);
}
/** Create a Line Of Sight which depends on time.
* @return the dependent of time LOS
*/
public static TimeDependentLOS createLOSCurvedLine(Vector3D center, Vector3D normal,
double halfAperture, double sagitta, int n) {
Vector3D u = Vector3D.crossProduct(center, normal);
List<Vector3D> list = new ArrayList<Vector3D>(n);
for (int i = 0; i < n; ++i) {
double x = (2.0 * i + 1.0 - n) / (n - 1);
double alpha = x * halfAperture;
double beta = x * x * sagitta;
list.add(new Rotation(normal, alpha, RotationConvention.VECTOR_OPERATOR).
applyTo(new Rotation(u, beta, RotationConvention.VECTOR_OPERATOR).
applyTo(center)));
}
return new LOSBuilder(list).build();
}
/** Propagate an orbit between 2 given dates
* @return a list of TimeStampedPVCoordinates
*/
public static List<TimeStampedPVCoordinates> orbitToPV(Orbit orbit, BodyShape earth,
AbsoluteDate minDate, AbsoluteDate maxDate,
double step) {
Propagator propagator = new KeplerianPropagator(orbit);
propagator.setAttitudeProvider(new YawCompensation(orbit.getFrame(), new NadirPointing(orbit.getFrame(), earth)));
propagator.propagate(minDate);
final List<TimeStampedPVCoordinates> list = new ArrayList<TimeStampedPVCoordinates>();
propagator.getMultiplexer().add(step, currentState -> list.add(new TimeStampedPVCoordinates(currentState.getDate(),
currentState.getPVCoordinates().getPosition(),
currentState.getPVCoordinates().getVelocity(),
Vector3D.ZERO)));
propagator.propagate(maxDate);
return list;
}
/** Propagate an attitude between 2 given dates
* @return a list of TimeStampedAngularCoordinates
*/
public static List<TimeStampedAngularCoordinates> orbitToQ(Orbit orbit, BodyShape earth,
AbsoluteDate minDate, AbsoluteDate maxDate,
double step) {
Propagator propagator = new KeplerianPropagator(orbit);
propagator.setAttitudeProvider(new YawCompensation(orbit.getFrame(), new NadirPointing(orbit.getFrame(), earth)));
propagator.propagate(minDate);
final List<TimeStampedAngularCoordinates> list = new ArrayList<TimeStampedAngularCoordinates>();
propagator.getMultiplexer().add(step, currentState -> list.add(new TimeStampedAngularCoordinates(currentState.getDate(),
currentState.getAttitude().getRotation(),
Vector3D.ZERO, Vector3D.ZERO)));
propagator.propagate(maxDate);
return list;
}
/**
* Asserts that two SensorPixel are equal to within a positive delta for each component.
* For more details see:
* org.junit.assert.assertEquals(String message, double expected, double actual, double delta)
*/
static public void sensorPixelAssertEquals(SensorPixel expected, SensorPixel result, double delta) {
assertEquals(null,expected.getLineNumber(), result.getLineNumber(), delta);
assertEquals(null,expected.getPixelNumber(), result.getPixelNumber(), delta);
}
/**
* Tell if two SensorPixel are the same, where each components are equal to within a positive delta.
* For more details see:
* org.junit.assert.assertEquals(String message, double expected, double actual, double delta)
* @param expected expected sensor pixel
* @param result actual sensor pixel
* @param delta delta within two values are consider equal
* @return true if the two SensorPixel are the same, false otherwise
*/
static public Boolean sameSensorPixels(SensorPixel expected, SensorPixel result, double delta) {
Boolean sameSensorPixel = false;
// To have same pixel (true)
sameSensorPixel = !(isDifferent(expected.getLineNumber(), result.getLineNumber(), delta) ||
isDifferent(expected.getPixelNumber(), result.getPixelNumber(), delta));
return sameSensorPixel;
}
/**
* Tell if two SensorPixel are the same, where each components are equal to within a positive delta.
* For more details see:
* org.junit.assert.assertEquals(String message, double expected, double actual, double delta)
* @param expected expected sensor pixel
* @param result actual sensor pixel
* @param delta delta within two values are consider equal
* @return true if the two SensorPixel are the same, false otherwise
*/
static public Boolean sameGeodeticPoints(GeodeticPoint expected, GeodeticPoint result, double delta) {
Boolean sameGeodeticPoint = false;
// To have same GeodeticPoint (true)
sameGeodeticPoint = !(isDifferent(expected.getLatitude(), result.getLatitude(), delta) ||
isDifferent(expected.getLongitude(), result.getLongitude(), delta) ||
isDifferent(expected.getAltitude(), result.getAltitude(), delta));
return sameGeodeticPoint;
}
/** Return true if two double values are different within a positive delta.
* @param val1 first value to compare
* @param val2 second value to compare
* @param delta delta within the two values are consider equal
* @return true is different, false if equal within the positive delta
*/
static private boolean isDifferent(double val1, double val2, double delta) {
if (Double.compare(val1, val2) == 0) {
return false;
}
if ((FastMath.abs(val1 - val2) <= delta)) {
return false;
}
return true;
}
}
/* Copyright 2013-2022 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.adjustment;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresOptimizer.Optimum;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.orekit.rugged.adjustment.measurements.Observables;
import org.orekit.rugged.adjustment.measurements.SensorMapping;
import org.orekit.rugged.adjustment.util.InitInterRefiningTest;
import org.orekit.rugged.api.Rugged;
import org.orekit.rugged.errors.RuggedException;
import org.orekit.rugged.errors.RuggedMessages;
import org.orekit.rugged.linesensor.SensorPixel;
public class AdjustmentContextTest {
@Before
public void setUp() {
try {
// One must set a context for the adjustment ... Here we choose an inter sensors optimization problem
InitInterRefiningTest refiningTest = new InitInterRefiningTest();
refiningTest.initRefiningTest();
ruggedList = refiningTest.getRuggedList();
int lineSampling = 1000;
int pixelSampling = 1000;
double earthConstraintWeight = 0.1;
measurements = refiningTest.generateNoisyPoints(lineSampling, pixelSampling, earthConstraintWeight, false);
} catch (RuggedException re) {
Assert.fail(re.getLocalizedMessage());
}
}
@Test
public void testAdjustmentContext() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
AdjustmentContext adjustmentContext = new AdjustmentContext(ruggedList, measurements);
// Check if the default OptimizerId is the expected one (use reflectivity)
Field optimizerId = adjustmentContext.getClass().getDeclaredField("optimizerID");
optimizerId.setAccessible(true);
OptimizerId defaultOptimizerId = (OptimizerId) optimizerId.get(adjustmentContext);
Assert.assertTrue((defaultOptimizerId == OptimizerId.GAUSS_NEWTON_QR));
// Check if the change of the default OptimizerId is correct
adjustmentContext.setOptimizer(OptimizerId.GAUSS_NEWTON_LU);
OptimizerId modifiedOptimizerId = (OptimizerId) optimizerId.get(adjustmentContext);
Assert.assertTrue((modifiedOptimizerId == OptimizerId.GAUSS_NEWTON_LU));
// Check if the change of the default OptimizerId is correct
adjustmentContext.setOptimizer(OptimizerId.LEVENBERG_MARQUADT);
modifiedOptimizerId = (OptimizerId) optimizerId.get(adjustmentContext);
Assert.assertTrue((modifiedOptimizerId == OptimizerId.LEVENBERG_MARQUADT));
}
@Test
public void testEstimateFreeParameters() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
AdjustmentContext adjustmentContext = new AdjustmentContext(ruggedList, measurements);
for (OptimizerId optimizer : OptimizerId.values()) {
// Set the optimizer
adjustmentContext.setOptimizer(optimizer);
List<String> ruggedNameList = new ArrayList<String>();
for(Rugged rugged : ruggedList) {
ruggedNameList.add(rugged.getName());
}
final int maxIterations = 120;
final double convergenceThreshold = 1.e-7;
Optimum optimum = adjustmentContext.estimateFreeParameters(ruggedNameList, maxIterations, convergenceThreshold);
Field optimizerId = adjustmentContext.getClass().getDeclaredField("optimizerID");
optimizerId.setAccessible(true);
OptimizerId usedOptimizerId = (OptimizerId) optimizerId.get(adjustmentContext);
if (usedOptimizerId == OptimizerId.GAUSS_NEWTON_QR || usedOptimizerId == OptimizerId.GAUSS_NEWTON_LU) {
// For Gauss Newton, the number of evaluations is equal to the number of iterations
Assert.assertTrue(optimum.getEvaluations() == optimum.getIterations());
} else if (usedOptimizerId == OptimizerId.LEVENBERG_MARQUADT) {
// For Levenberg Marquadt, the number of evaluations is slightly greater than the number of iterations
Assert.assertTrue(optimum.getEvaluations() >= optimum.getIterations());
}
} // loop on OptimizerId
}
@Test
public void testInvalidRuggedName() {
try {
AdjustmentContext adjustmentContext = new AdjustmentContext(ruggedList, measurements);
List<String> ruggedNameList = new ArrayList<String>();
// the list must not have a null value
Iterator<Rugged> it = ruggedList.iterator();
while (it.hasNext()) {
ruggedNameList.add(null);
it.next();
}
final int maxIterations = 1;
final double convergenceThreshold = 1.e-7;
adjustmentContext.estimateFreeParameters(ruggedNameList, maxIterations, convergenceThreshold);
Assert.fail("An exception should have been thrown");
} catch (RuggedException re) {
Assert.assertEquals(RuggedMessages.INVALID_RUGGED_NAME,re.getSpecifier());
}
}
@Test
public void testUnsupportedRefiningContext() {
try {
AdjustmentContext adjustmentContext = new AdjustmentContext(ruggedList, measurements);
List<String> ruggedNameList = new ArrayList<String>();
// Add too many rugged name: the list must have 1 or 2 items
for(Rugged rugged : ruggedList) {
ruggedNameList.add(rugged.getName());
ruggedNameList.add(rugged.getName());
ruggedNameList.add(rugged.getName());
}
final int maxIterations = 1;
final double convergenceThreshold = 1.e-7;
adjustmentContext.estimateFreeParameters(ruggedNameList, maxIterations, convergenceThreshold);
Assert.fail("An exception should have been thrown");
} catch (RuggedException re) {
Assert.assertEquals(RuggedMessages.UNSUPPORTED_REFINING_CONTEXT,re.getSpecifier());
}
}
@Test
public void testSensorMapping() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
String sensorGiven = "lineSensor";
String ruggedGiven = "Rugged";
SensorMapping<SensorPixel> simpleMapping = new SensorMapping<SensorPixel>(sensorGiven) ;
Field ruggedField = simpleMapping.getClass().getDeclaredField("ruggedName");
ruggedField.setAccessible(true);
String ruggedRead = (String) ruggedField.get(simpleMapping);
Field sensorField = simpleMapping.getClass().getDeclaredField("sensorName");
sensorField.setAccessible(true);
String sensorRead = (String) sensorField.get(simpleMapping);
Assert.assertTrue(ruggedGiven.equals(ruggedRead));
Assert.assertTrue(sensorGiven.equals(sensorRead));
}
@After
public void tearDown() {
measurements = null;
ruggedList = null;
}
private Observables measurements;
private List<Rugged> ruggedList;
}
package org.orekit.rugged.adjustment;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;
import java.util.Set;
import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresOptimizer.Optimum;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.orekit.bodies.GeodeticPoint;
import org.orekit.rugged.TestUtils;
import org.orekit.rugged.adjustment.measurements.Observables;
import org.orekit.rugged.adjustment.measurements.SensorToGroundMapping;
import org.orekit.rugged.adjustment.util.InitGroundRefiningTest;
import org.orekit.rugged.adjustment.util.RefiningParametersDriver;
import org.orekit.rugged.api.Rugged;
import org.orekit.rugged.errors.RuggedException;
import org.orekit.rugged.errors.RuggedMessages;
import org.orekit.rugged.linesensor.LineSensor;
import org.orekit.rugged.linesensor.SensorPixel;
public class GroundOptimizationProblemBuilderTest {
@Before
public void setUp() {
try {
refiningTest = new InitGroundRefiningTest();
refiningTest.initGroundRefiningTest();
rugged = refiningTest.getRugged();
// get the only line sensor
LineSensor sensor = rugged.getLineSensors().iterator().next();
sensorName = sensor.getName();
measurements = refiningTest.generateNoisyPoints(lineSampling, pixelSampling, false);
numberOfParameters = refiningTest.getParameterToAdjust();
} catch (RuggedException re) {
Assert.fail(re.getLocalizedMessage());
}
}
@Test
public void testEstimateFreeParameters() {
AdjustmentContext adjustmentContext = new AdjustmentContext(Collections.singletonList(rugged), measurements);
final int maxIterations = 50;
final double convergenceThreshold = 1.e-11;
Optimum optimum = adjustmentContext.estimateFreeParameters(Collections.singletonList(rugged.getName()), maxIterations, convergenceThreshold);
Assert.assertTrue(optimum.getIterations() < maxIterations);
// The default optimizer is a Gauss Newton.
// For Gauss Newton, the number of evaluations is equal to the number of iterations
Assert.assertTrue(optimum.getEvaluations() == optimum.getIterations());
final double expectedMaxValue = 39200.0;
Assert.assertEquals(expectedMaxValue, optimum.getResiduals().getMaxValue(), 1.0e-6);
final double expectedRMS = 5067.112098;
Assert.assertEquals(expectedRMS, optimum.getRMS(), 1.0e-6);
final double expectedCost = 286639.1460351976;
Assert.assertEquals(expectedCost, optimum.getCost(), 1.0e-6);
Assert.assertTrue(numberOfParameters == optimum.getPoint().getDimension());
final int sensorToGroundMappingSize = 1600;
Collection<SensorToGroundMapping> ssm = measurements.getGroundMappings();
Iterator<SensorToGroundMapping> it = ssm.iterator();
while (it.hasNext()) {
SensorToGroundMapping ssmit = it.next();
Assert.assertTrue(sensorToGroundMappingSize == ssmit.getMapping().size());
}
Assert.assertTrue(sensorToGroundMappingSize*2 == optimum.getResiduals().getDimension());
}
@Test
public void testNoParametersSelected() {
try {
RefiningParametersDriver.unselectRoll(rugged, sensorName);
RefiningParametersDriver.unselectPitch(rugged, sensorName);
AdjustmentContext adjustmentContext = new AdjustmentContext(Collections.singletonList(rugged), measurements);
final int maxIterations = 50;
final double convergenceThreshold = 1.e-11;
adjustmentContext.estimateFreeParameters(Collections.singletonList(rugged.getName()), maxIterations, convergenceThreshold);
Assert.fail("An exception should have been thrown");
} catch (RuggedException re) {
Assert.assertEquals(RuggedMessages.NO_PARAMETERS_SELECTED,re.getSpecifier());
}
}
@Test
public void testNoReferenceMapping() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
try {
final int maxIterations = 50;
final double convergenceThreshold = 1.e-11;
final List<LineSensor> selectedSensors = new ArrayList<LineSensor>();
selectedSensors.addAll(rugged.getLineSensors());
final GroundOptimizationProblemBuilder groundOptimizationProblem =
new GroundOptimizationProblemBuilder(selectedSensors, measurements, rugged);
Field sensorToGroundMapping = groundOptimizationProblem.getClass().getDeclaredField("sensorToGroundMappings");
sensorToGroundMapping.setAccessible(true);
sensorToGroundMapping.set(groundOptimizationProblem,new ArrayList<SensorToGroundMapping>());
groundOptimizationProblem.build(maxIterations, convergenceThreshold);
Assert.fail("An exception should have been thrown");
} catch (RuggedException re) {
Assert.assertEquals(RuggedMessages.NO_REFERENCE_MAPPINGS,re.getSpecifier());
}
}
@Test
public void testDefaultRuggedName(){
// Get the measurements as computed in other tests
Collection<SensorToGroundMapping> sensorToGroundMapping = measurements.getGroundMappings();
int nbModels = measurements.getNbModels();
// Recompute the measurements in another way ... but that must be the same after all
Observables measurementsNoName = refiningTest.generateNoisyPoints(lineSampling, pixelSampling, true);
Collection<SensorToGroundMapping> sensorToGroundMappingNoName = measurementsNoName.getGroundMappings();
int nbModelsWithWeight = measurementsNoName.getNbModels();
// Compare the two collections of measurements
Assert.assertEquals(nbModels, nbModelsWithWeight);
Assert.assertEquals(sensorToGroundMapping.size(), sensorToGroundMappingNoName.size());
// There is only one item
SensorToGroundMapping arraySensorToGroundMapping = (SensorToGroundMapping) sensorToGroundMapping.toArray()[0];
SensorToGroundMapping arraySensorToGroundMappingNoName = (SensorToGroundMapping) sensorToGroundMappingNoName.toArray()[0];
// Check if the two set are the same
Set<Entry<SensorPixel, GeodeticPoint>> mapping = arraySensorToGroundMapping.getMapping();
Set<Entry<SensorPixel, GeodeticPoint>> mappingNoName = arraySensorToGroundMappingNoName.getMapping();
Iterator<Entry<SensorPixel, GeodeticPoint>> itMapping = mapping.iterator();
while(itMapping.hasNext()) {
Entry<SensorPixel, GeodeticPoint> current = itMapping.next();
SensorPixel key = current.getKey();
GeodeticPoint value = current.getValue();
// Will search in mappingNoName if we can find the (key,value) found in mapping
Boolean found = false;
Iterator<Entry<SensorPixel, GeodeticPoint>> itMappingNoName = mappingNoName.iterator();
while(itMappingNoName.hasNext()) {
Entry<SensorPixel, GeodeticPoint> currentNoName = itMappingNoName.next();
SensorPixel keyNoName = currentNoName.getKey();
GeodeticPoint valueNoName = currentNoName.getValue();
// Comparison of each SensorPixel (for the key part and the value part)
if (TestUtils.sameSensorPixels(key, keyNoName, 1.e-3) &&
TestUtils.sameGeodeticPoints(value, valueNoName, 1.e-3)) {
// we found a match ...
found = true;
}
} // end iteration on mappingNoName
if (!found) { // the current (key,value) of the mapping was not found in the mappingNoName
Assert.assertTrue(found);
}
} // end on iteration on mapping
Assert.assertEquals(arraySensorToGroundMapping.getRuggedName(),arraySensorToGroundMappingNoName.getRuggedName());
Assert.assertEquals(arraySensorToGroundMapping.getSensorName(),arraySensorToGroundMappingNoName.getSensorName());;
}
@After
public void tearDown() {
measurements = null;
}
private InitGroundRefiningTest refiningTest;
private Observables measurements;
private Rugged rugged;
private String sensorName;
private int numberOfParameters;
private final int lineSampling = 1000;
private final int pixelSampling = 1000;
}
/* Copyright 2013-2022 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.adjustment;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresOptimizer.Optimum;
import org.hipparchus.optim.nonlinear.vector.leastsquares.LeastSquaresProblem;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.orekit.rugged.TestUtils;
import org.orekit.rugged.adjustment.measurements.Observables;
import org.orekit.rugged.adjustment.measurements.SensorToSensorMapping;
import org.orekit.rugged.adjustment.util.InitInterRefiningTest;
import org.orekit.rugged.api.Rugged;
import org.orekit.rugged.errors.RuggedException;
import org.orekit.rugged.errors.RuggedMessages;
import org.orekit.rugged.linesensor.LineSensor;
import org.orekit.rugged.linesensor.SensorPixel;
public class InterSensorOptimizationProblemBuilderTest {
@Before
public void setUp() {
try {
refiningTest = new InitInterRefiningTest();
refiningTest.initRefiningTest();
ruggedList = refiningTest.getRuggedList();
earthConstraintWeight = 0.1;
measurements = refiningTest.generateNoisyPoints(lineSampling, pixelSampling, earthConstraintWeight, false);
numberOfParameters = refiningTest.getParameterToAdjust();
} catch (RuggedException re) {
Assert.fail(re.getLocalizedMessage());
}
}
@Test
public void testEstimateFreeParameters() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
AdjustmentContext adjustmentContext = new AdjustmentContext(ruggedList, measurements);
List<String> ruggedNameList = new ArrayList<String>();
for(Rugged rugged : ruggedList) {
ruggedNameList.add(rugged.getName());
}
final int maxIterations = 100;
final double convergenceThreshold = 1.e-7;
Optimum optimum = adjustmentContext.estimateFreeParameters(ruggedNameList, maxIterations, convergenceThreshold);
Assert.assertTrue(optimum.getIterations() < maxIterations);
// The default optimizer is a Gauss Newton.
// For Gauss Newton, the number of evaluations is equal to the number of iterations
Assert.assertTrue(optimum.getEvaluations() == optimum.getIterations());
final double expectedMaxValue = 1.924769e-03;
Assert.assertEquals(expectedMaxValue, optimum.getResiduals().getMaxValue(), 1.0e-6);
final double expectedRMS = 0.069302;
Assert.assertEquals(expectedRMS, optimum.getRMS(), 1.0e-6);
final double expectedCost = 3.597082e+00;
Assert.assertEquals(expectedCost, optimum.getCost(), 1.0e-6);
Assert.assertTrue(numberOfParameters == optimum.getPoint().getDimension());
final int sensorToSensorMappingSize = 1347;
Collection<SensorToSensorMapping> ssm = measurements.getInterMappings();
Iterator<SensorToSensorMapping> it = ssm.iterator();
while (it.hasNext()) {
SensorToSensorMapping ssmit = it.next();
Assert.assertTrue(sensorToSensorMappingSize == ssmit.getMapping().size());
}
Assert.assertTrue(sensorToSensorMappingSize*2 == optimum.getResiduals().getDimension());
}
@Test
public void testEarthConstraintPostponed() {
// Get the measurements as computed in other tests
Collection<SensorToSensorMapping> sensorToSensorMapping = measurements.getInterMappings();
int nbModels = measurements.getNbModels();
// Recompute the measurements in another way ... but that must be the same after all
Observables measurementsPostponed = refiningTest.generateNoisyPoints(lineSampling, pixelSampling, earthConstraintWeight, true);
Collection<SensorToSensorMapping> sensorToSensorMappingPostponed = measurementsPostponed.getInterMappings();
int nbModelsPostponed = measurementsPostponed.getNbModels();
// Compare the two collections of measurements
Assert.assertEquals(nbModels, nbModelsPostponed);
Assert.assertEquals(sensorToSensorMapping.size(), sensorToSensorMappingPostponed.size());
// There is only one item
SensorToSensorMapping arraySensorToSensorMapping = (SensorToSensorMapping) sensorToSensorMapping.toArray()[0];
SensorToSensorMapping arraySensorToSensorMappingPostponed = (SensorToSensorMapping) sensorToSensorMappingPostponed.toArray()[0];
List<Double> listBody = arraySensorToSensorMapping.getBodyDistances();
// Convert List<Double> to double[]
double[] arrayBody = listBody.stream().mapToDouble(Double::doubleValue).toArray(); //via method reference
// Explanations:
// get the Stream<Double> from the list
// map each double instance to its primitive value, resulting in a DoubleStream
// call toArray() to get the array.
// Other method: double[] arrayBody = listBody.stream().mapToDouble(d -> d).toArray(); //identity function, Java unboxes automatically to get the double value
List<Double> listBodyPostponed = arraySensorToSensorMappingPostponed.getBodyDistances();
double[] arrayBodyPostponed = listBodyPostponed.stream().mapToDouble(Double::doubleValue).toArray();
Assert.assertEquals(listBody.size(), listBodyPostponed.size());
Assert.assertArrayEquals(arrayBody, arrayBodyPostponed, 1.e-3);
List<Double> listLos = arraySensorToSensorMapping.getLosDistances();
double[] arrayLos = listLos.stream().mapToDouble(Double::doubleValue).toArray();
List<Double> listLosPostponed = arraySensorToSensorMappingPostponed.getLosDistances();
double[] arrayLosPostponed = listLosPostponed.stream().mapToDouble(Double::doubleValue).toArray();
Assert.assertEquals(listLos.size(), listLosPostponed.size());
Assert.assertArrayEquals(arrayLos, arrayLosPostponed, 1.e-6);
// Check if the two set are the same
Set<Entry<SensorPixel, SensorPixel>> mapping = arraySensorToSensorMapping.getMapping();
Set<Entry<SensorPixel, SensorPixel>> mappingPostponed = arraySensorToSensorMappingPostponed.getMapping();
Iterator<Entry<SensorPixel, SensorPixel>> itMapping = mapping.iterator();
while(itMapping.hasNext()) {
Entry<SensorPixel, SensorPixel> current = itMapping.next();
SensorPixel key = current.getKey();
SensorPixel value = current.getValue();
// Will search in mappingPostponed if we can find the (key,value) found in mapping
Boolean found = false;
Iterator<Entry<SensorPixel, SensorPixel>> itMappingPost = mappingPostponed.iterator();
while(itMappingPost.hasNext()) {
Entry<SensorPixel, SensorPixel> currentPost = itMappingPost.next();
SensorPixel keyPost = currentPost.getKey();
SensorPixel valuePost = currentPost.getValue();
// Comparison of each SensorPixel (for the key part and the value part)
if (TestUtils.sameSensorPixels(key, keyPost, 1.e-3) &&
TestUtils.sameSensorPixels(value, valuePost, 1.e-3)) {
// we found a match ...
found = true;
}
} // end iteration on mappingPostponed
if (!found) { // the current (key,value) of the mapping was not found in the mappingPostponed
Assert.assertTrue(found);
}
} // end on iteration on mapping
Assert.assertEquals(arraySensorToSensorMapping.getRuggedNameA(),arraySensorToSensorMappingPostponed.getRuggedNameA());
Assert.assertEquals(arraySensorToSensorMapping.getRuggedNameB(),arraySensorToSensorMappingPostponed.getRuggedNameB());;
Assert.assertEquals(arraySensorToSensorMapping.getSensorNameA(),arraySensorToSensorMappingPostponed.getSensorNameA());;
Assert.assertEquals(arraySensorToSensorMapping.getSensorNameB(),arraySensorToSensorMappingPostponed.getSensorNameB());
}
@Test
public void testDefaultRuggedNames() {
// In that case there are no body distance set at construction
// Generate intermapping with simple constructor of SensorToSensorMapping with Earth Constraint Weight given at construction
Observables measurementsWithWeight = refiningTest.generateSimpleInterMapping(lineSampling, pixelSampling, earthConstraintWeight, false);
Collection<SensorToSensorMapping> sensorToSensorMappingWithWeight = measurementsWithWeight.getInterMappings();
int nbModelsWithWeight = measurementsWithWeight.getNbModels();
// Generate intermapping with simple constructor of SensorToSensorMapping with Earth Constraint Weight given after construction
Observables measurementsWithoutWeight = refiningTest.generateSimpleInterMapping(lineSampling, pixelSampling, earthConstraintWeight, true);
Collection<SensorToSensorMapping> sensorToSensorMappingPostponed = measurementsWithoutWeight.getInterMappings();
int nbModelsPostponed = measurementsWithoutWeight.getNbModels();
// Compare the two collections of measurements
Assert.assertEquals(nbModelsWithWeight, nbModelsPostponed);
Assert.assertEquals(sensorToSensorMappingWithWeight.size(), sensorToSensorMappingPostponed.size());
// There is only one item
SensorToSensorMapping arraySensorToSensorMappingWithWeight = (SensorToSensorMapping) sensorToSensorMappingWithWeight.toArray()[0];
SensorToSensorMapping arraySensorToSensorMappingPostponed = (SensorToSensorMapping) sensorToSensorMappingPostponed.toArray()[0];
List<Double> listLosWithWeight = arraySensorToSensorMappingWithWeight.getLosDistances();
double[] arrayLosWithWeight = listLosWithWeight.stream().mapToDouble(Double::doubleValue).toArray();
List<Double> listLosPostponed = arraySensorToSensorMappingPostponed.getLosDistances();
double[] arrayLosPostponed = listLosPostponed.stream().mapToDouble(Double::doubleValue).toArray();
Assert.assertEquals(listLosWithWeight.size(), listLosPostponed.size());
Assert.assertArrayEquals(arrayLosWithWeight, arrayLosPostponed, 1.e-6);
// Check if the two set are the same
Set<Entry<SensorPixel, SensorPixel>> mappingWithWeight = arraySensorToSensorMappingWithWeight.getMapping();
Set<Entry<SensorPixel, SensorPixel>> mappingPostponed = arraySensorToSensorMappingPostponed.getMapping();
Iterator<Entry<SensorPixel, SensorPixel>> itMapping = mappingWithWeight.iterator();
while(itMapping.hasNext()) {
Entry<SensorPixel, SensorPixel> current = itMapping.next();
SensorPixel key = current.getKey();
SensorPixel value = current.getValue();
// Will search in mappingPostponed if we can find the (key,value) found in mapping
Boolean found = false;
Iterator<Entry<SensorPixel, SensorPixel>> itMappingPost = mappingPostponed.iterator();
while(itMappingPost.hasNext()) {
Entry<SensorPixel, SensorPixel> currentPost = itMappingPost.next();
SensorPixel keyPost = currentPost.getKey();
SensorPixel valuePost = currentPost.getValue();
// Comparison of each SensorPixel (for the key part and the value part)
if (TestUtils.sameSensorPixels(key, keyPost, 1.e-3) &&
TestUtils.sameSensorPixels(value, valuePost, 1.e-3)) {
// we found a match ...
found = true;
}
} // end iteration on mappingPostponed
if (!found) { // the current (key,value) of the mapping was not found in the mappingPostponed
Assert.assertTrue(found);
}
} // end on iteration on mapping
Assert.assertEquals(arraySensorToSensorMappingWithWeight.getRuggedNameA(),arraySensorToSensorMappingPostponed.getRuggedNameA());
Assert.assertEquals(arraySensorToSensorMappingWithWeight.getRuggedNameB(),arraySensorToSensorMappingPostponed.getRuggedNameB());;
Assert.assertEquals(arraySensorToSensorMappingWithWeight.getSensorNameA(),arraySensorToSensorMappingPostponed.getSensorNameA());;
Assert.assertEquals(arraySensorToSensorMappingWithWeight.getSensorNameB(),arraySensorToSensorMappingPostponed.getSensorNameB());
}
@Test
public void testNoReferenceMapping() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
try {
final int maxIterations = 120;
final double convergenceThreshold = 1.e-7;
final List<LineSensor> selectedSensors = new ArrayList<LineSensor>();
for (Rugged rugged : ruggedList) {
selectedSensors.addAll(rugged.getLineSensors());
}
final InterSensorsOptimizationProblemBuilder interSensorsOptimizationProblem =
new InterSensorsOptimizationProblemBuilder(selectedSensors, measurements, ruggedList);
Field sensorToSensorMapping = interSensorsOptimizationProblem.getClass().getDeclaredField("sensorToSensorMappings");
sensorToSensorMapping.setAccessible(true);
sensorToSensorMapping.set(interSensorsOptimizationProblem,new ArrayList<SensorToSensorMapping>());
interSensorsOptimizationProblem.build(maxIterations, convergenceThreshold);
Assert.fail("An exception should have been thrown");
} catch (RuggedException re) {
Assert.assertEquals(RuggedMessages.NO_REFERENCE_MAPPINGS,re.getSpecifier());
}
}
@Test
public void testInvalidRuggedNames() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
final int maxIterations = 120;
final double convergenceThreshold = 1.e-7;
final List<LineSensor> selectedSensors = new ArrayList<LineSensor>();
for (Rugged rugged : ruggedList) {
selectedSensors.addAll(rugged.getLineSensors());
}
final InterSensorsOptimizationProblemBuilder interSensorsOptimizationProblem =
new InterSensorsOptimizationProblemBuilder(selectedSensors, measurements, ruggedList);
Field ruggedMapField = interSensorsOptimizationProblem.getClass().getDeclaredField("ruggedMap");
ruggedMapField.setAccessible(true);
@SuppressWarnings("unchecked")
Map<String,Rugged> ruggedMap = (Map<String,Rugged>) ruggedMapField.get(interSensorsOptimizationProblem);
// Set first RuggedB to null to get the right exception ...
try {
ruggedMap.put("RuggedB",null);
ruggedMapField.set(interSensorsOptimizationProblem,ruggedMap);
final LeastSquareAdjuster adjuster = new LeastSquareAdjuster(OptimizerId.GAUSS_NEWTON_QR);
LeastSquaresProblem theProblem = interSensorsOptimizationProblem.build(maxIterations, convergenceThreshold);
adjuster.optimize(theProblem);
Assert.fail("An exception should have been thrown");
} catch (RuggedException re) {
Assert.assertEquals(RuggedMessages.INVALID_RUGGED_NAME,re.getSpecifier());
}
// Then set RuggedA to null to get the right exception ...
try {
ruggedMap.put("RuggedA",null);
ruggedMapField.set(interSensorsOptimizationProblem,ruggedMap);
final LeastSquareAdjuster adjuster = new LeastSquareAdjuster(OptimizerId.GAUSS_NEWTON_QR);
LeastSquaresProblem theProblem = interSensorsOptimizationProblem.build(maxIterations, convergenceThreshold);
adjuster.optimize(theProblem);
Assert.fail("An exception should have been thrown");
} catch (RuggedException re) {
Assert.assertEquals(RuggedMessages.INVALID_RUGGED_NAME,re.getSpecifier());
}
}
@After
public void tearDown() {
measurements = null;
ruggedList = null;
}
private InitInterRefiningTest refiningTest;
private Observables measurements;
private List<Rugged> ruggedList;
private int numberOfParameters;
private double earthConstraintWeight;
private final int lineSampling = 1000;
private final int pixelSampling = 1000;
}
package org.orekit.rugged.adjustment;
import org.junit.Assert;
import java.lang.reflect.Field;
import org.junit.Test;
public class LeastSquareAdjusterTest {
@Test
public void testLeastSquareAdjuster() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
final LeastSquareAdjuster adjusterWithOptimizer = new LeastSquareAdjuster(OptimizerId.GAUSS_NEWTON_QR);
final LeastSquareAdjuster adjusterWithDefaultOptimizer = new LeastSquareAdjuster();
Field optimizerIdWithOptimizer = adjusterWithOptimizer.getClass().getDeclaredField("optimizerID");
optimizerIdWithOptimizer.setAccessible(true);
OptimizerId getOptimizerIdWithOptimizer = (OptimizerId) optimizerIdWithOptimizer.get(adjusterWithOptimizer);
Field optimizerIdWithDefaultOptimizer = adjusterWithDefaultOptimizer.getClass().getDeclaredField("optimizerID");
optimizerIdWithDefaultOptimizer.setAccessible(true);
OptimizerId getOptimizerIdWithDefaultOptimizer = (OptimizerId) optimizerIdWithDefaultOptimizer.get(adjusterWithDefaultOptimizer);
Assert.assertTrue(getOptimizerIdWithDefaultOptimizer == getOptimizerIdWithOptimizer);
}
}
package org.orekit.rugged.adjustment.util;
import java.io.File;
import java.net.URISyntaxException;
import java.util.List;
import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.hipparchus.random.GaussianRandomGenerator;
import org.hipparchus.random.UncorrelatedRandomVectorGenerator;
import org.hipparchus.random.Well19937a;
import org.hipparchus.util.FastMath;
import org.junit.Assert;
import org.orekit.bodies.BodyShape;
import org.orekit.bodies.GeodeticPoint;
import org.orekit.data.DataContext;
import org.orekit.data.DirectoryCrawler;
import org.orekit.errors.OrekitException;
import org.orekit.orbits.Orbit;
import org.orekit.rugged.TestUtils;
import org.orekit.rugged.adjustment.measurements.Observables;
import org.orekit.rugged.adjustment.measurements.SensorToGroundMapping;
import org.orekit.rugged.api.AlgorithmId;
import org.orekit.rugged.api.BodyRotatingFrameId;
import org.orekit.rugged.api.EllipsoidId;
import org.orekit.rugged.api.InertialFrameId;
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.time.AbsoluteDate;
import org.orekit.utils.AngularDerivativesFilter;
import org.orekit.utils.CartesianDerivativesFilter;
import org.orekit.utils.Constants;
import org.orekit.utils.TimeStampedAngularCoordinates;
import org.orekit.utils.TimeStampedPVCoordinates;
/** Initialization for ground refining (Ground Control Points GCP study) Junit tests.
* @author Guylaine Prat
*/
public class InitGroundRefiningTest {
/** Pleiades viewing model */
private PleiadesViewingModel pleiadesViewingModel;
/** Line sensor */
private LineSensor lineSensor;
/** Rugged's instance */
private Rugged rugged;
/** Number of parameters to adjust */
private int parameterToAdjust;
// Part of the name of parameter drivers
static final String rollSuffix = "_roll";
static final String pitchSuffix = "_pitch";
static final String factorName = "factor";
// Default values for disruption to apply to roll (deg), pitch (deg) and factor
static final double defaultRollDisruption = 0.004;
static final double defaultPitchDisruption = 0.0008;
static final double defaultFactorDisruption = 1.000000001;
/**
* Initialize ground refining tests with default values for disruptions on sensors characteristics
*/
public void initGroundRefiningTest() {
initGroundRefiningTest(defaultRollDisruption, defaultPitchDisruption, defaultFactorDisruption);
}
/** Initialize ground refining tests with disruption on sensors characteristics
* @param rollDisruption disruption to apply to roll angle for sensor (deg)
* @param pitchDisruption disruption to apply to pitch angle for sensor (deg)
* @param factorDisruption disruption to apply to homothety factor for sensor
*/
public void initGroundRefiningTest(double rollDisruption, double pitchDisruption, double factorDisruption) {
try {
String path = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(path)));
// Initialize refining context
// ---------------------------
final String sensorName = "line";
final double incidenceAngle = -5.0;
final String date = "2016-01-01T11:59:50.0";
this.pleiadesViewingModel = new PleiadesViewingModel(sensorName, incidenceAngle, date);
PleiadesOrbitModel orbitmodel = new PleiadesOrbitModel();
// Sensor's definition: creation of Pleiades viewing model
// --------------------------------------------------------
// Create Pleiades Viewing Model
final AbsoluteDate minDate = pleiadesViewingModel.getMinDate();
final AbsoluteDate maxDate = pleiadesViewingModel.getMaxDate();
final AbsoluteDate refDate = pleiadesViewingModel.getDatationReference();
this.lineSensor = pleiadesViewingModel.getLineSensor();
// ----Satellite position, velocity and attitude: create orbit model
BodyShape earth = TestUtils.createEarth();
Orbit orbit = orbitmodel.createOrbit(Constants.EIGEN5C_EARTH_MU, refDate);
// ----If no LOF Transform Attitude Provider is Nadir Pointing Yaw Compensation
final double [] rollPoly = {0.0,0.0,0.0};
final double[] pitchPoly = {0.025,0.0};
final double[] yawPoly = {0.0,0.0,0.0};
orbitmodel.setLOFTransform(rollPoly, pitchPoly, yawPoly, minDate);
// ----Satellite attitude
List<TimeStampedAngularCoordinates> satelliteQList = orbitmodel.orbitToQ(orbit, earth, minDate.shiftedBy(-0.0), maxDate.shiftedBy(+0.0), 0.25);
final int nbQPoints = 2;
// ----Position and velocities
List<TimeStampedPVCoordinates> satellitePVListA = orbitmodel.orbitToPV(orbit, earth, minDate.shiftedBy(-0.0), maxDate.shiftedBy(+0.0), 0.25);
final int nbPVPoints = 8;
// Rugged initialization
// ---------------------
RuggedBuilder ruggedBuilder = new RuggedBuilder();
ruggedBuilder.addLineSensor(lineSensor);
ruggedBuilder.setAlgorithm(AlgorithmId.IGNORE_DEM_USE_ELLIPSOID);
ruggedBuilder.setEllipsoid(EllipsoidId.WGS84, BodyRotatingFrameId.ITRF);
ruggedBuilder.setTimeSpan(minDate,maxDate, 0.001, 5.0);
ruggedBuilder.setTrajectory(InertialFrameId.EME2000, satellitePVListA, nbPVPoints,
CartesianDerivativesFilter.USE_PV, satelliteQList,
nbQPoints, AngularDerivativesFilter.USE_R);
ruggedBuilder.setLightTimeCorrection(false);
ruggedBuilder.setAberrationOfLightCorrection(false);
ruggedBuilder.setName("Rugged");
this.rugged = ruggedBuilder.build();
// Select parameters to adjust
// ---------------------------
RefiningParametersDriver.setSelectedRoll(rugged, sensorName);
RefiningParametersDriver.setSelectedPitch(rugged, sensorName);
this.parameterToAdjust = 2;
// Initialize disruptions:
// -----------------------
// introduce rotations around instrument axes (roll and pitch angles, scale factor)
// apply disruptions on physical model
RefiningParametersDriver.applyDisruptionsRoll(rugged, sensorName, FastMath.toRadians(rollDisruption));
RefiningParametersDriver.applyDisruptionsPitch(rugged, sensorName, FastMath.toRadians(pitchDisruption));
RefiningParametersDriver.applyDisruptionsFactor(rugged, sensorName, factorDisruption);
} catch (OrekitException oe) {
Assert.fail(oe.getLocalizedMessage());
} catch (URISyntaxException use) {
Assert.fail(use.getLocalizedMessage());
}
}
/**
* Get the Rugged instance
* @return rugged instance
*/
public Rugged getRugged(){
return this.rugged;
}
/** Generate noisy measurements (sensor to ground mapping)
* @param lineSampling line sampling
* @param pixelSampling pixel sampling
* @param flag to tell if the Rugged name used is the default one (true) or not (false)
*/
public Observables generateNoisyPoints(final int lineSampling, final int pixelSampling, boolean defaultRuggedName) {
// Generate reference mapping
SensorToGroundMapping groundMapping;
if (!defaultRuggedName) {
groundMapping = new SensorToGroundMapping(rugged.getName(), lineSensor.getName());
} else {
// The rugged name used in this test is the same as the dafult one in SensorToGroundMapping
groundMapping = new SensorToGroundMapping(lineSensor.getName());
}
// Observable which contains sensor to ground mapping (one model)
Observables observable = new Observables(1);
// Estimate latitude and longitude errors (rad)
final int pixelMiddle= lineSensor.getNbPixels() / 2;
final int lineMiddle = (int) FastMath.floor(pixelMiddle);
final AbsoluteDate dateMiddle = lineSensor.getDate(lineMiddle);
final GeodeticPoint gp_pix0 = rugged.directLocation(dateMiddle, lineSensor.getPosition(), lineSensor.getLOS(dateMiddle, pixelMiddle));
final AbsoluteDate date1 = lineSensor.getDate(lineMiddle + 1);
final GeodeticPoint gp_pix1 = rugged.directLocation(date1, lineSensor.getPosition(), lineSensor.getLOS(date1, pixelMiddle + 1));
final double latitudeErr = FastMath.abs(gp_pix0.getLatitude() - gp_pix1.getLatitude());
final double longitudeErr = FastMath.abs(gp_pix0.getLongitude() - gp_pix1.getLongitude());
// Generation noisy measurements
// distribution: gaussian(0), vector dimension: 3 (for latitude, longitude and altitude)
// Mean latitude, longitude and altitude
final double[] mean = {5.0,5.0,5.0};
// Standard deviation latitude, longitude and altitude
final double[] std = {0.1,0.1,0.1};
final double latErrorMean = mean[0] * latitudeErr;
final double lonErrorMean = mean[1] * longitudeErr;
final double latErrorStd = std[0] * latitudeErr;
final double lonErrorStd = std[1] * longitudeErr;
// Gaussian random generator
// Build a null mean random uncorrelated vector generator with standard deviation corresponding to the estimated error on ground
final double meanGenerator[] = {latErrorMean, lonErrorMean, mean[2]};
final double stdGenerator[] = {latErrorStd, lonErrorStd, std[2]};
// seed has been fixed for tests purpose
final GaussianRandomGenerator rng = new GaussianRandomGenerator(new Well19937a(0xefac03d9be4d24b9l));
final UncorrelatedRandomVectorGenerator rvg = new UncorrelatedRandomVectorGenerator(meanGenerator, stdGenerator, rng);
for (double line = 0; line < pleiadesViewingModel.getDimension(); line += lineSampling) {
final AbsoluteDate date = lineSensor.getDate(line);
for (int pixel = 0; pixel < lineSensor.getNbPixels(); pixel += pixelSampling) {
// Components of generated vector follow (independent) Gaussian distribution
final Vector3D vecRandom = new Vector3D(rvg.nextVector());
final GeodeticPoint gp2 = rugged.directLocation(date, lineSensor.getPosition(),
lineSensor.getLOS(date, pixel));
final GeodeticPoint gpNoisy = new GeodeticPoint(gp2.getLatitude() + vecRandom.getX(),
gp2.getLongitude() + vecRandom.getY(),
gp2.getAltitude() + vecRandom.getZ());
groundMapping.addMapping(new SensorPixel(line, pixel), gpNoisy);
}
}
observable.addGroundMapping(groundMapping);
return observable;
}
/** Get the number of parameters to adjust
* @return number of parameters to adjust
*/
public int getParameterToAdjust() {
return parameterToAdjust;
}
}
package org.orekit.rugged.adjustment.util;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.net.URISyntaxException;
import java.util.ArrayList;
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;
import org.hipparchus.random.Well19937a;
import org.hipparchus.util.FastMath;
import org.junit.After;
import org.junit.Assert;
import org.orekit.bodies.BodyShape;
import org.orekit.bodies.GeodeticPoint;
import org.orekit.data.DataContext;
import org.orekit.data.DirectoryCrawler;
import org.orekit.errors.OrekitException;
import org.orekit.orbits.Orbit;
import org.orekit.rugged.TestUtils;
import org.orekit.rugged.adjustment.InterSensorsOptimizationProblemBuilder;
import org.orekit.rugged.adjustment.measurements.Observables;
import org.orekit.rugged.adjustment.measurements.SensorToSensorMapping;
import org.orekit.rugged.api.AlgorithmId;
import org.orekit.rugged.api.BodyRotatingFrameId;
import org.orekit.rugged.api.EllipsoidId;
import org.orekit.rugged.api.InertialFrameId;
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.DerivativeGenerator;
import org.orekit.rugged.utils.SpacecraftToObservedBody;
import org.orekit.time.AbsoluteDate;
import org.orekit.utils.AngularDerivativesFilter;
import org.orekit.utils.CartesianDerivativesFilter;
import org.orekit.utils.Constants;
import org.orekit.utils.TimeStampedAngularCoordinates;
import org.orekit.utils.TimeStampedPVCoordinates;
/** Initialization for inter sensor refining Junit tests.
* @author Guylaine Prat
*/
public class InitInterRefiningTest {
/** Pleiades viewing model A */
private PleiadesViewingModel pleiadesViewingModelA;
/** Pleiades viewing model B */
private PleiadesViewingModel pleiadesViewingModelB;
/** Line sensor A */
private LineSensor lineSensorA;
/** Line sensor B */
private LineSensor lineSensorB;
/** RuggedA's instance */
private Rugged ruggedA;
/** RuggedB's instance */
private Rugged ruggedB;
/** Number of parameters to adjust */
private int parameterToAdjust;
// Part of the name of parameter drivers
static final String rollSuffix = "_roll";
static final String pitchSuffix = "_pitch";
static final String factorName = "factor";
// Default values for disruption to apply to roll (deg), pitch (deg) and factor
static final double defaultRollDisruptionA = 0.004;
static final double defaultPitchDisruptionA = 0.0008;
static final double defaultFactorDisruptionA = 1.000000001;
static final double defaultRollDisruptionB = -0.004;
static final double defaultPitchDisruptionB = 0.0008;
/**
* Initialize refining tests with default values for disruptions on sensors characteristics
*/
public void initRefiningTest() {
initRefiningTest(defaultRollDisruptionA, defaultPitchDisruptionA, defaultFactorDisruptionA,
defaultRollDisruptionB, defaultPitchDisruptionB);
}
/** Initialize refining tests with disruption on sensors characteristics
* @param rollDisruptionA disruption to apply to roll angle for sensor A (deg)
* @param pitchDisruptionA disruption to apply to pitch angle for sensor A (deg)
* @param factorDisruptionA disruption to apply to homothety factor for sensor A
* @param rollDisruptionB disruption to apply to roll angle for sensor B (deg)
* @param pitchDisruptionB disruption to apply to pitch angle for sensor B (deg)
*/
public void initRefiningTest(double rollDisruptionA, double pitchDisruptionA, double factorDisruptionA,
double rollDisruptionB, double pitchDisruptionB) {
try {
String path = getClass().getClassLoader().getResource("orekit-data").toURI().getPath();
DataContext.getDefault().getDataProvidersManager().addProvider(new DirectoryCrawler(new File(path)));
// Initialize refining context
// ---------------------------
final String sensorNameA = "SensorA";
final double incidenceAngleA = -5.0;
final String dateA = "2016-01-01T11:59:50.0";
this.pleiadesViewingModelA = new PleiadesViewingModel(sensorNameA, incidenceAngleA, dateA);
final String sensorNameB = "SensorB";
final double incidenceAngleB = 0.0;
final String dateB = "2016-01-01T12:02:50.0";
this.pleiadesViewingModelB = new PleiadesViewingModel(sensorNameB, incidenceAngleB, dateB);
PleiadesOrbitModel orbitmodelA = new PleiadesOrbitModel();
PleiadesOrbitModel orbitmodelB = new PleiadesOrbitModel();
// Sensors's definition: creation of 2 Pleiades viewing models
// -----------------------------------------------------------
// 1/- Create First Pleiades Viewing Model A
final AbsoluteDate minDateA = pleiadesViewingModelA.getMinDate();
final AbsoluteDate maxDateA = pleiadesViewingModelA.getMaxDate();
final AbsoluteDate refDateA = pleiadesViewingModelA.getDatationReference();
this.lineSensorA = pleiadesViewingModelA.getLineSensor();
// ----Satellite position, velocity and attitude: create orbit model A
BodyShape earthA = TestUtils.createEarth();
Orbit orbitA = orbitmodelA.createOrbit(Constants.EIGEN5C_EARTH_MU, refDateA);
// ----If no LOF Transform Attitude Provider is Nadir Pointing Yaw Compensation
final double [] rollPoly = {0.0,0.0,0.0};
final double[] pitchPoly = {0.025,0.0};
final double[] yawPoly = {0.0,0.0,0.0};
orbitmodelA.setLOFTransform(rollPoly, pitchPoly, yawPoly, minDateA);
// ----Satellite attitude
List<TimeStampedAngularCoordinates> satelliteQListA = orbitmodelA.orbitToQ(orbitA, earthA, minDateA.shiftedBy(-0.0), maxDateA.shiftedBy(+0.0), 0.25);
final int nbQPoints = 2;
// ----Position and velocities
List<TimeStampedPVCoordinates> satellitePVListA = orbitmodelA.orbitToPV(orbitA, earthA, minDateA.shiftedBy(-0.0), maxDateA.shiftedBy(+0.0), 0.25);
final int nbPVPoints = 8;
// Rugged A initialization
// ---------------------
RuggedBuilder ruggedBuilderA = new RuggedBuilder();
ruggedBuilderA.addLineSensor(lineSensorA);
ruggedBuilderA.setAlgorithm(AlgorithmId.IGNORE_DEM_USE_ELLIPSOID);
ruggedBuilderA.setEllipsoid(EllipsoidId.WGS84, BodyRotatingFrameId.ITRF);
ruggedBuilderA.setTimeSpan(minDateA,maxDateA, 0.001, 5.0);
ruggedBuilderA.setTrajectory(InertialFrameId.EME2000, satellitePVListA, nbPVPoints,
CartesianDerivativesFilter.USE_PV, satelliteQListA,
nbQPoints, AngularDerivativesFilter.USE_R);
ruggedBuilderA.setLightTimeCorrection(false);
ruggedBuilderA.setAberrationOfLightCorrection(false);
ruggedBuilderA.setName("RuggedA");
this.ruggedA = ruggedBuilderA.build();
// 2/- Create Second Pleiades Viewing Model
final AbsoluteDate minDateB = pleiadesViewingModelB.getMinDate();
final AbsoluteDate maxDateB = pleiadesViewingModelB.getMaxDate();
final AbsoluteDate refDateB = pleiadesViewingModelB.getDatationReference();
this.lineSensorB = pleiadesViewingModelB.getLineSensor();
// ----Satellite position, velocity and attitude: create orbit model B
BodyShape earthB = TestUtils.createEarth();
Orbit orbitB = orbitmodelB.createOrbit(Constants.EIGEN5C_EARTH_MU, refDateB);
// ----Satellite attitude
List<TimeStampedAngularCoordinates> satelliteQListB = orbitmodelB.orbitToQ(orbitB, earthB, minDateB.shiftedBy(-0.0), maxDateB.shiftedBy(+0.0), 0.25);
// ----Position and velocities
List<TimeStampedPVCoordinates> satellitePVListB = orbitmodelB.orbitToPV(orbitB, earthB, minDateB.shiftedBy(-0.0), maxDateB.shiftedBy(+0.0), 0.25);
// Rugged B initialization
// ---------------------
RuggedBuilder ruggedBuilderB = new RuggedBuilder();
ruggedBuilderB.addLineSensor(lineSensorB);
ruggedBuilderB.setAlgorithm(AlgorithmId.IGNORE_DEM_USE_ELLIPSOID);
ruggedBuilderB.setEllipsoid(EllipsoidId.WGS84, BodyRotatingFrameId.ITRF);
ruggedBuilderB.setTimeSpan(minDateB,maxDateB, 0.001, 5.0);
ruggedBuilderB.setTrajectory(InertialFrameId.EME2000, satellitePVListB, nbPVPoints,
CartesianDerivativesFilter.USE_PV, satelliteQListB,
nbQPoints, AngularDerivativesFilter.USE_R);
ruggedBuilderB.setLightTimeCorrection(false);
ruggedBuilderB.setAberrationOfLightCorrection(false);
ruggedBuilderB.setName("RuggedB");
this.ruggedB = ruggedBuilderB.build();
// Select parameters to adjust
// ---------------------------
RefiningParametersDriver.setSelectedRoll(ruggedA, sensorNameA);
RefiningParametersDriver.setSelectedPitch(ruggedA, sensorNameA);
RefiningParametersDriver.setSelectedRoll(ruggedB, sensorNameB);
RefiningParametersDriver.setSelectedPitch(ruggedB, sensorNameB);
this.parameterToAdjust = 4;
// Initialize disruptions:
// -----------------------
// introduce rotations around instrument axes (roll and pitch angles, scale factor)
// apply disruptions on physical model (acquisition A)
RefiningParametersDriver.applyDisruptionsRoll(ruggedA, sensorNameA, FastMath.toRadians(rollDisruptionA));
RefiningParametersDriver.applyDisruptionsPitch(ruggedA, sensorNameA, FastMath.toRadians(pitchDisruptionA));
RefiningParametersDriver.applyDisruptionsFactor(ruggedA, sensorNameA, factorDisruptionA);
// apply disruptions on physical model (acquisition B)
RefiningParametersDriver.applyDisruptionsRoll(ruggedB, sensorNameB, FastMath.toRadians(rollDisruptionB));
RefiningParametersDriver.applyDisruptionsPitch(ruggedB, sensorNameB, FastMath.toRadians(pitchDisruptionB));
} catch (OrekitException oe) {
Assert.fail(oe.getLocalizedMessage());
} catch (URISyntaxException use) {
Assert.fail(use.getLocalizedMessage());
}
}
/**
* Get the list of Rugged instances
* @return rugged instances as list
*/
public List<Rugged> getRuggedList(){
List<Rugged> ruggedList = Arrays.asList(ruggedA, ruggedB);
return ruggedList;
}
/** Compute the distances 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
*/
public double[] computeDistancesBetweenLOS(final SensorPixel realPixelA, final SensorPixel realPixelB) {
final SpacecraftToObservedBody scToBodyA = ruggedA.getScToBody();
final AbsoluteDate realDateA = lineSensorA.getDate(realPixelA.getLineNumber());
final AbsoluteDate realDateB = lineSensorB.getDate(realPixelB.getLineNumber());
final double[] distanceLOSB = ruggedB.distanceBetweenLOS(
lineSensorA, realDateA, realPixelA.getPixelNumber(),
scToBodyA,
lineSensorB, realDateB, realPixelB.getPixelNumber());
return distanceLOSB;
}
/** 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
* @deprecated as of 2.2, replaced by {@link #computeDistancesBetweenLOSGradient(SensorPixel, SensorPixel, double, double)}
*/
public DerivativeStructure[] computeDistancesBetweenLOSDerivatives(final SensorPixel realPixelA, final SensorPixel realPixelB,
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());
final AbsoluteDate realDateB = lineSensorB.getDate(realPixelB.getLineNumber());
final List<LineSensor> sensors = new ArrayList<LineSensor>();
sensors.addAll(ruggedA.getLineSensors());
sensors.addAll(ruggedB.getLineSensors());
final List<Rugged> ruggedList = new ArrayList<Rugged>();
ruggedList.add(ruggedA);
ruggedList.add(ruggedB);
// prepare generator
final Observables measurements = new Observables(2);
SensorToSensorMapping interMapping = new SensorToSensorMapping(lineSensorA.getName(), ruggedA.getName(), lineSensorB.getName(), ruggedB.getName());
interMapping.addMapping(realPixelA, realPixelB, losDistance, earthDistance);
measurements.addInterMapping(interMapping);
InterSensorsOptimizationProblemBuilder optimizationPbBuilder = new InterSensorsOptimizationProblemBuilder(sensors, measurements, ruggedList);
java.lang.reflect.Method createGenerator = InterSensorsOptimizationProblemBuilder.class.getSuperclass().getDeclaredMethod("createGenerator", List.class);
createGenerator.setAccessible(true);
List<LineSensor> listLineSensor = new ArrayList<LineSensor>();
listLineSensor.addAll(ruggedA.getLineSensors());
listLineSensor.addAll(ruggedB.getLineSensors());
@SuppressWarnings("unchecked")
DerivativeGenerator<Gradient> generator = (DerivativeGenerator<Gradient>) createGenerator.invoke(optimizationPbBuilder, listLineSensor);
return ruggedB.distanceBetweenLOSderivatives(lineSensorA, realDateA, realPixelA.getPixelNumber(),
scToBodyA,
lineSensorB, realDateB, realPixelB.getPixelNumber(),
generator);
}
/** Generate noisy measurements (sensor to sensor mapping)
* @param lineSampling line sampling
* @param pixelSampling pixel sampling
* @param earthConstraintWeight the earth constrint weight
* @param earthConstraintPostponed flag to tell if the earth constraint weight is set at construction (false) or after (true) - For JUnit coverage purpose
*/
public Observables generateNoisyPoints(final int lineSampling, final int pixelSampling, final double earthConstraintWeight, final boolean earthConstraintPostponed) {
// Outliers control
final double outlierValue = 1.e+2;
// Generate measurements with constraints on Earth distance and outliers control
// Generate reference mapping, with Earth distance constraints.
// Weighting will be applied as follow :
// (1-earthConstraintWeight) for losDistance weighting
// earthConstraintWeight for earthDistance weighting
SensorToSensorMapping interMapping;
if (! earthConstraintPostponed) {
interMapping = new SensorToSensorMapping(lineSensorA.getName(), ruggedA.getName(),
lineSensorB.getName(), ruggedB.getName(),
earthConstraintWeight);
} else { // used for JUnit coverage purpose
interMapping = new SensorToSensorMapping(lineSensorA.getName(), ruggedA.getName(),
lineSensorB.getName(), ruggedB.getName());
// set the earthConstraintWeight after construction
interMapping.setBodyConstraintWeight(earthConstraintWeight);
}
// Observables which contains sensor to sensor mapping
Observables observables = new Observables(2);
// Generation noisy measurements
// distribution: gaussian(0), vector dimension: 2
final double meanA[] = { 5.0, 5.0 };
final double stdA[] = { 0.1, 0.1 };
final double meanB[] = { 0.0, 0.0 };
final double stdB[] = { 0.1, 0.1 };
// Seed has been fixed for tests purpose
final GaussianRandomGenerator rngA = new GaussianRandomGenerator(new Well19937a(0xefac03d9be4d24b9l));
final UncorrelatedRandomVectorGenerator rvgA = new UncorrelatedRandomVectorGenerator(meanA, stdA, rngA);
// Seed has been fixed for tests purpose
final GaussianRandomGenerator rngB = new GaussianRandomGenerator(new Well19937a(0xdf1c03d9be0b34b9l));
final UncorrelatedRandomVectorGenerator rvgB = new UncorrelatedRandomVectorGenerator(meanB, stdB, rngB);
// Search the sensor pixel seeing point
final int minLine = 0;
final int maxLine = pleiadesViewingModelB.getDimension() - 1;
final String sensorNameB = lineSensorB.getName();
for (double line = 0; line < pleiadesViewingModelA.getDimension(); line += lineSampling) {
final AbsoluteDate dateA = lineSensorA.getDate(line);
for (double pixelA = 0; pixelA < lineSensorA.getNbPixels(); pixelA += pixelSampling) {
final GeodeticPoint gpA = ruggedA.directLocation(dateA, lineSensorA.getPosition(),
lineSensorA.getLOS(dateA, pixelA));
final SensorPixel sensorPixelB = ruggedB.inverseLocation(sensorNameB, gpA, minLine, maxLine);
// We need to test if the sensor pixel is found in the prescribed lines
// otherwise the sensor pixel is null
if (sensorPixelB != null) {
final AbsoluteDate dateB = lineSensorB.getDate(sensorPixelB.getLineNumber());
final double pixelB = sensorPixelB.getPixelNumber();
// Get spacecraft to body transform of Rugged instance A
final SpacecraftToObservedBody scToBodyA = ruggedA.getScToBody();
final GeodeticPoint gpB = ruggedB.directLocation(dateB, lineSensorB.getPosition(),
lineSensorB.getLOS(dateB, pixelB));
final double geoDistance = computeDistanceInMeter(gpA, gpB);
// Create the inter mapping if distance is below outlier value
if (geoDistance < outlierValue) {
final double[] vecRandomA = rvgA.nextVector();
final double[] vecRandomB = rvgB.nextVector();
final SensorPixel realPixelA = new SensorPixel(line + vecRandomA[0], pixelA + vecRandomA[1]);
final SensorPixel realPixelB = new SensorPixel(sensorPixelB.getLineNumber() + vecRandomB[0],
sensorPixelB.getPixelNumber() + vecRandomB[1]);
final AbsoluteDate realDateA = lineSensorA.getDate(realPixelA.getLineNumber());
final AbsoluteDate realDateB = lineSensorB.getDate(realPixelB.getLineNumber());
final double[] distanceLOSB = ruggedB.distanceBetweenLOS(lineSensorA, realDateA, realPixelA.getPixelNumber(), scToBodyA,
lineSensorB, realDateB, realPixelB.getPixelNumber());
final Double losDistance = 0.0;
final Double earthDistance = distanceLOSB[1];
interMapping.addMapping(realPixelA, realPixelB, losDistance, earthDistance);
} // end test if geoDistance < outlierValue
} // end test if sensorPixelB != null
} // end loop on pixel of sensorA
} // end loop on line of sensorA
observables.addInterMapping(interMapping);
return observables;
}
/** Generate simple noisy measurements (sensor to sensor mapping)
* @param lineSampling line sampling
* @param pixelSampling pixel sampling
* @param earthConstraintWeight the earth constrint weight
* @param earthConstraintPostponed flag to tell if the earth constraint weight is set at construction (false) or after (true) - For JUnit coverage purpose
*/
public Observables generateSimpleInterMapping(final int lineSampling, final int pixelSampling, final double earthConstraintWeight, final boolean earthConstraintPostponed) {
// Outliers control
final double outlierValue = 1.e+2;
// Generate measurements with constraints on Earth distance and outliers control
// Generate reference mapping, with Earth distance constraints.
// Weighting will be applied as follow :
// (1-earthConstraintWeight) for losDistance weighting
// earthConstraintWeight for earthDistance weighting
SensorToSensorMapping interMapping;
if (! earthConstraintPostponed) {
interMapping = new SensorToSensorMapping(lineSensorA.getName(), lineSensorB.getName(), earthConstraintWeight);
} else { // used for JUnit coverage purpose
interMapping = new SensorToSensorMapping(lineSensorA.getName(), lineSensorB.getName());
// set the earthConstraintWeight after construction
interMapping.setBodyConstraintWeight(earthConstraintWeight);
}
// Observables which contains sensor to sensor mapping
Observables observables = new Observables(2);
// Generation noisy measurements
// distribution: gaussian(0), vector dimension: 2
final double meanA[] = { 5.0, 5.0 };
final double stdA[] = { 0.1, 0.1 };
final double meanB[] = { 0.0, 0.0 };
final double stdB[] = { 0.1, 0.1 };
// Seed has been fixed for tests purpose
final GaussianRandomGenerator rngA = new GaussianRandomGenerator(new Well19937a(0xefac03d9be4d24b9l));
final UncorrelatedRandomVectorGenerator rvgA = new UncorrelatedRandomVectorGenerator(meanA, stdA, rngA);
// Seed has been fixed for tests purpose
final GaussianRandomGenerator rngB = new GaussianRandomGenerator(new Well19937a(0xdf1c03d9be0b34b9l));
final UncorrelatedRandomVectorGenerator rvgB = new UncorrelatedRandomVectorGenerator(meanB, stdB, rngB);
// Search the sensor pixel seeing point
final int minLine = 0;
final int maxLine = pleiadesViewingModelB.getDimension() - 1;
final String sensorNameB = lineSensorB.getName();
for (double line = 0; line < pleiadesViewingModelA.getDimension(); line += lineSampling) {
final AbsoluteDate dateA = lineSensorA.getDate(line);
for (double pixelA = 0; pixelA < lineSensorA.getNbPixels(); pixelA += pixelSampling) {
final GeodeticPoint gpA = ruggedA.directLocation(dateA, lineSensorA.getPosition(),
lineSensorA.getLOS(dateA, pixelA));
final SensorPixel sensorPixelB = ruggedB.inverseLocation(sensorNameB, gpA, minLine, maxLine);
// We need to test if the sensor pixel is found in the prescribed lines
// otherwise the sensor pixel is null
if (sensorPixelB != null) {
final AbsoluteDate dateB = lineSensorB.getDate(sensorPixelB.getLineNumber());
final double pixelB = sensorPixelB.getPixelNumber();
final GeodeticPoint gpB = ruggedB.directLocation(dateB, lineSensorB.getPosition(),
lineSensorB.getLOS(dateB, pixelB));
final double geoDistance = computeDistanceInMeter(gpA, gpB);
// Create the inter mapping if distance is below outlier value
if (geoDistance < outlierValue) {
final double[] vecRandomA = rvgA.nextVector();
final double[] vecRandomB = rvgB.nextVector();
final SensorPixel realPixelA = new SensorPixel(line + vecRandomA[0], pixelA + vecRandomA[1]);
final SensorPixel realPixelB = new SensorPixel(sensorPixelB.getLineNumber() + vecRandomB[0],
sensorPixelB.getPixelNumber() + vecRandomB[1]);
// dummy value for JUnit test purpose
final Double losDistance = FastMath.abs(vecRandomA[0]);
interMapping.addMapping(realPixelA, realPixelB, losDistance);
} // end test if geoDistance < outlierValue
} // end test if sensorPixelB != null
} // end loop on pixel of sensorA
} // end loop on line of sensorA
observables.addInterMapping(interMapping);
return observables;
}
/** Compute a geodetic distance in meters between two geodetic points.
* @param geoPoint1 first geodetic point (rad)
* @param geoPoint2 second geodetic point (rad)
* @return distance in meters
*/
private static double computeDistanceInMeter(final GeodeticPoint geoPoint1, final GeodeticPoint geoPoint2) {
// get vectors on unit sphere from angular coordinates
final Vector3D p1 = new Vector3D(geoPoint1.getLatitude(), geoPoint1.getLongitude());
final Vector3D p2 = new Vector3D(geoPoint2.getLatitude(), geoPoint2.getLongitude());
return Constants.WGS84_EARTH_EQUATORIAL_RADIUS * Vector3D.angle(p1, p2);
}
/** Get the number of parameters to adjust
* @return number of parameters to adjust
*/
public int getParameterToAdjust() {
return parameterToAdjust;
}
@After
public void tearDown() {
}
}
package org.orekit.rugged.adjustment.util;
import java.util.ArrayList;
import java.util.List;
import org.hipparchus.geometry.euclidean.threed.Rotation;
import org.hipparchus.geometry.euclidean.threed.RotationConvention;
import org.hipparchus.geometry.euclidean.threed.RotationOrder;
import org.hipparchus.geometry.euclidean.threed.Vector3D;
import org.hipparchus.util.FastMath;
import org.orekit.attitudes.AttitudeProvider;
import org.orekit.attitudes.LofOffset;
import org.orekit.attitudes.NadirPointing;
import org.orekit.attitudes.TabulatedLofOffset;
import org.orekit.attitudes.YawCompensation;
import org.orekit.bodies.BodyShape;
import org.orekit.frames.Frame;
import org.orekit.frames.FramesFactory;
import org.orekit.frames.LOFType;
import org.orekit.orbits.CircularOrbit;
import org.orekit.orbits.Orbit;
import org.orekit.orbits.PositionAngle;
import org.orekit.propagation.Propagator;
import org.orekit.propagation.analytical.KeplerianPropagator;
import org.orekit.time.AbsoluteDate;
import org.orekit.utils.AngularDerivativesFilter;
import org.orekit.utils.Constants;
import org.orekit.utils.TimeStampedAngularCoordinates;
import org.orekit.utils.TimeStampedPVCoordinates;
/**
* Class to compute Pleiades orbit for refining Junit tests.
*/
public class PleiadesOrbitModel {
/** Flag to change Attitude Law (by default Nadir Pointing Yaw Compensation). */
private boolean userDefinedLOFTransform;
/** User defined Roll law. */
private double[] lofTransformRollPoly;
/** User defined Pitch law. */
private double[] lofTransformPitchPoly;
/** User defined Yaw law. */
private double[] lofTransformYawPoly;
/** Reference date. */
private AbsoluteDate refDate;
/** Default constructor.
*/
public PleiadesOrbitModel() {
userDefinedLOFTransform = false;
}
/** Create a circular orbit.
*/
public Orbit createOrbit(final double mu, final AbsoluteDate date) {
// the following orbital parameters have been computed using
// Orekit tutorial about phasing, using the following configuration:
//
// orbit.date = 2012-01-01T00:00:00.000
// phasing.orbits.number = 143
// phasing.days.number = 10
// sun.synchronous.reference.latitude = 0
// sun.synchronous.reference.ascending = false
// sun.synchronous.mean.solar.time = 10:30:00
// gravity.field.degree = 12
// gravity.field.order = 12
final Frame eme2000 = FramesFactory.getEME2000();
return new CircularOrbit(694000.0 + Constants.WGS84_EARTH_EQUATORIAL_RADIUS,
-4.029194321683225E-4,
0.0013530362644647786,
FastMath.toRadians(98.2), // Pleiades inclination 98.2 deg
FastMath.toRadians(-86.47 + 180),
FastMath.toRadians(135.9 + 0.3),
PositionAngle.TRUE,
eme2000,
date,
mu);
}
/** Set the Local Orbital Frame characteristics.
*/
public void setLOFTransform(final double[] rollPoly, final double[] pitchPoly,
final double[] yawPoly, final AbsoluteDate date) {
this.userDefinedLOFTransform = true;
lofTransformRollPoly = rollPoly.clone();
lofTransformPitchPoly = pitchPoly.clone();
lofTransformYawPoly = yawPoly.clone();
this.refDate = date;
}
/** Recompute the polynom coefficients with shift.
*/
private double getPoly(final double[] poly, final double shift) {
double val = 0.0;
for (int coef = 0; coef < poly.length; coef++) {
val = val + poly[coef] * FastMath.pow(shift, coef);
}
return val;
}
/** Get the offset.
*/
private Rotation getOffset(final BodyShape earth, final Orbit orbit, final double shift) {
final LOFType type = LOFType.VVLH;
final double roll = getPoly(lofTransformRollPoly, shift);
final double pitch = getPoly(lofTransformPitchPoly, shift);
final double yaw = getPoly(lofTransformYawPoly, shift);
final LofOffset law = new LofOffset(orbit.getFrame(), type, RotationOrder.XYZ,
roll, pitch, yaw);
final Rotation offsetAtt = law.
getAttitude(orbit, orbit.getDate().shiftedBy(shift), orbit.getFrame()).
getRotation();
final NadirPointing nadirPointing = new NadirPointing(orbit.getFrame(), earth);
final Rotation nadirAtt = nadirPointing.
getAttitude(orbit, orbit.getDate().getDate().shiftedBy(shift), orbit.getFrame()).
getRotation();
final Rotation offsetProper = offsetAtt.compose(nadirAtt.revert(), RotationConvention.VECTOR_OPERATOR);
return offsetProper;
}
/** Create the attitude provider.
*/
public AttitudeProvider createAttitudeProvider(final BodyShape earth, final Orbit orbit) {
if (userDefinedLOFTransform) {
final LOFType type = LOFType.VVLH;
final List<TimeStampedAngularCoordinates> list = new ArrayList<TimeStampedAngularCoordinates>();
for (double shift = -10.0; shift < +10.0; shift += 1e-2) {
list.add(new TimeStampedAngularCoordinates(refDate.shiftedBy(shift),
getOffset(earth, orbit, shift),
Vector3D.ZERO,
Vector3D.ZERO));
}
final TabulatedLofOffset tabulated = new TabulatedLofOffset(orbit.getFrame(), type, list,
2, AngularDerivativesFilter.USE_R);
return tabulated;
} else {
return new YawCompensation(orbit.getFrame(), new NadirPointing(orbit.getFrame(), earth));
}
}
/** Generate the orbit.
*/
public List<TimeStampedPVCoordinates> orbitToPV(final Orbit orbit, final BodyShape earth,
final AbsoluteDate minDate, final AbsoluteDate maxDate,
final double step) {
final Propagator propagator = new KeplerianPropagator(orbit);
propagator.setAttitudeProvider(createAttitudeProvider(earth, orbit));
propagator.propagate(minDate);
final List<TimeStampedPVCoordinates> list = new ArrayList<TimeStampedPVCoordinates>();
propagator.getMultiplexer().add(step,
currentState -> list.add(new TimeStampedPVCoordinates(currentState.getDate(),
currentState.getPVCoordinates().getPosition(),
currentState.getPVCoordinates().getVelocity(),
Vector3D.ZERO)));
propagator.propagate(maxDate);
return list;
}
/** Generate the attitude.
*/
public List<TimeStampedAngularCoordinates> orbitToQ(final Orbit orbit, final BodyShape earth,
final AbsoluteDate minDate, final AbsoluteDate maxDate,
final double step) {
final Propagator propagator = new KeplerianPropagator(orbit);
propagator.setAttitudeProvider(createAttitudeProvider(earth, orbit));
propagator.propagate(minDate);
final List<TimeStampedAngularCoordinates> list = new ArrayList<>();
propagator.getMultiplexer().add(step,
currentState -> list.add(new TimeStampedAngularCoordinates(currentState.getDate(),
currentState.getAttitude().getRotation(),
Vector3D.ZERO,
Vector3D.ZERO)));
propagator.propagate(maxDate);
return list;
}
}
package org.orekit.rugged.adjustment.util;
import java.util.ArrayList;
import java.util.List;
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.linesensor.LineDatation;
import org.orekit.rugged.linesensor.LineSensor;
import org.orekit.rugged.linesensor.LinearLineDatation;
import org.orekit.rugged.los.FixedRotation;
import org.orekit.rugged.los.FixedZHomothety;
import org.orekit.rugged.los.LOSBuilder;
import org.orekit.rugged.los.TimeDependentLOS;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.TimeScale;
import org.orekit.time.TimeScalesFactory;
/**
* Pleiades viewing model for refining Junit tests.
*/
public class PleiadesViewingModel {
/** Pleiades parameters. */
private static final double FOV = 1.65; // 20km - alt 694km
private static final int DIMENSION = 40000;
private static final double LINE_PERIOD = 1.e-4;
private double incidenceAngle;
private LineSensor lineSensor;
private String referenceDate;
private String sensorName;
/** PleiadesViewingModel constructor.
* @param sensorName sensor name
* @param incidenceAngle incidence angle
* @param referenceDate reference date
*/
public PleiadesViewingModel(final String sensorName, final double incidenceAngle, final String referenceDate) {
this.sensorName = sensorName;
this.referenceDate = referenceDate;
this.incidenceAngle = incidenceAngle;
this.createLineSensor();
}
/** Create raw fixed Line Of sight
*/
public LOSBuilder rawLOS(final Vector3D center, final Vector3D normal, final double halfAperture, final int n) {
final List<Vector3D> list = new ArrayList<Vector3D>(n);
for (int i = 0; i < n; ++i) {
final double alpha = (halfAperture * (2 * i + 1 - n)) / (n - 1);
list.add(new Rotation(normal, alpha, RotationConvention.VECTOR_OPERATOR).applyTo(center));
}
return new LOSBuilder(list);
}
/** Build a LOS provider
*/
public TimeDependentLOS buildLOS() {
final LOSBuilder losBuilder = rawLOS(new Rotation(Vector3D.PLUS_I,
FastMath.toRadians(incidenceAngle),
RotationConvention.VECTOR_OPERATOR).applyTo(Vector3D.PLUS_K),
Vector3D.PLUS_I, FastMath.toRadians(FOV / 2), DIMENSION);
losBuilder.addTransform(new FixedRotation(sensorName + InitInterRefiningTest.rollSuffix, Vector3D.MINUS_I, 0.00));
losBuilder.addTransform(new FixedRotation(sensorName + InitInterRefiningTest.pitchSuffix, Vector3D.MINUS_J, 0.00));
// factor is a common parameters shared between all Pleiades models
losBuilder.addTransform(new FixedZHomothety(InitInterRefiningTest.factorName, 1.0));
return losBuilder.build();
}
/** Get the reference date.
*/
public AbsoluteDate getDatationReference() {
// We use Orekit for handling time and dates, and Rugged for defining the datation model:
final TimeScale utc = TimeScalesFactory.getUTC();
return new AbsoluteDate(referenceDate, utc);
}
/** Get the min date.
*/
public AbsoluteDate getMinDate() {
return lineSensor.getDate(0);
}
/** Get the max date.
*/
public AbsoluteDate getMaxDate() {
return lineSensor.getDate(DIMENSION);
}
/** Get the line sensor.
*/
public LineSensor getLineSensor() {
return lineSensor;
}
/** Get the sensor name.
*/
public String getSensorName() {
return sensorName;
}
/** Get the number of lines of the sensor.
* @return the number of lines of the sensor
*/
public int getDimension() {
return DIMENSION;
}
/** Create the line sensor.
*/
private void createLineSensor() {
// Offset of the MSI from center of mass of satellite
// one line sensor
// los: swath in the (YZ) plane, looking at 50° roll, 2.6" per pixel
final Vector3D msiOffset = new Vector3D(0, 0, 0);
final TimeDependentLOS lineOfSight = buildLOS();
final double rate = 1. / LINE_PERIOD;
// linear datation model: at reference time we get the middle line, and the rate is one line every 1.5ms
final LineDatation lineDatation = new LinearLineDatation(getDatationReference(), DIMENSION / 2, rate);
lineSensor = new LineSensor(sensorName, lineDatation, msiOffset, lineOfSight);
}
}