LofOffset NTW attitude behavior

Hi,
I’m currently testing different set of attitude laws on a basic Hohman Transfer scenario with Orekit ImpulseManeuver detector.
I would like to make use of an attitude setup where X or Y direction is aligned with the velocity. The objective is to provide with both Hohman Transfer impulsive maneuvers towards the spacecraft velocity direction. To do so, I’ve decided to make use of the LofOffset class, providing with built-in orbital frames.

Curiously, the NTW LoF (Y axis aligned with velocity, Z axis aligned with orbital momentum) seems to behave in an unexpected way. I’ve tried to build the Hohman Transfer scenario with both impulsive maneuvers set up on its Y direction, but the reached altitude and final eccentricity is far from a standard 2-body problem Hohman Transfer.

On the opposite, LVLH frame (X axis aligned with position, Z axis aligned with orbital momentum) does provide with the expected results when the thrust direction is set on the Y direction.

Would you know where this might come from ?
Please see below the defined scenario, the script and final results.

Hohman Transfer scenario:
Initial sma (m): 7378136.6
Target sma (m): 8378136.6
dVInit (m/s): 229.6569934
dVFinal (m/s): 222.470549
Transfert Time (s): 3479.495227
Inclination (deg) : 10

Hohman Transfer script (NTW Lof):
// Hohman Transfer computation
double rInit = 7378136.6;
double rFinal = 8378136.6;
double aTrans = (rInit + rFinal)/2;
double vInit = FastMath.sqrt(mu/rInit);
double vFinal = FastMath.sqrt(mu/rFinal);

double vTransInit = FastMath.sqrt(((2mu)/rInit)-(mu/aTrans));
double vTransFinal = FastMath.sqrt(((2
mu)/rFinal)-(mu/aTrans));

double deltaVInit = vTransInit - vInit;
double deltaVFinal = vFinal - vTransFinal;
double tTransfer = FastMath.PI*FastMath.sqrt(FastMath.pow(aTrans, 3)/mu);

// Load Orekit data
DataContext.getDefault().getDataProvidersManager().addProvider(new ClasspathCrawler(“orekit-data.zip”));

// reference Frame
Frame refFrame = FramesFactory.getGCRF();

// spacecraft mass
double mass = 500; // kg

// spacecraft initial state epoch
DateScalesEnum timeScale = DateScalesEnum.UTC;
double[] calendarEpochArray = {2022, 4, 7, 10, 10, 0.0};
Epoch initialEpoch = FotBuildersFactory.buildEpoch(calendarEpochArray, timeScale);
AbsoluteDate initialDate = Fot2Orekit.mapToOrekitAbsoluteDate(initialEpoch);

// initial state
double a = 7378136.6;
double e = 0.0;
double i = FastMath.toRadians(10.0);
double raan = FastMath.toRadians(0.0);
double argPer = FastMath.toRadians(0.0);
double trueAnomaly = 0.0;

KeplerianOrbit initialOrbit = new KeplerianOrbit(a, e, i, raan, argPer, trueAnomaly, PositionAngle.TRUE, refFrame, initialDate, mu);

// attitude provider definition
LofOffset attitudeProvider = new LofOffset(refFrame, LOFType.NTW);

// build orbit propagator
KeplerianPropagator propagator = new KeplerianPropagator(initialOrbit);

// define events detectors
// first event: date detector
double[] eventCalendarEpochArray = {2022, 4, 7, 20, 10, 0.0};
Epoch eventEpoch = FotBuildersFactory.buildEpoch(eventCalendarEpochArray, timeScale);
AbsoluteDate target = Fot2Orekit.mapToOrekitAbsoluteDate(eventEpoch);
ìEventDetector dateDetector = new DateDetector(target);

// second event: date detector
EventDetector endDateDetector = new DateDetector(target.shiftedBy(tTransfer));

// define impulsive maneuvers
// first maneuver
Vector3D deltaVSat1 = new Vector3D(0.0, deltaVInit, 0.0);
double isp = 285;
ImpulseManeuver firstManeuver = new ImpulseManeuver(dateDetector, attitudeProvider, deltaVSat1, isp);

// second maneuver
Vector3D deltaVSat2 = new Vector3D(0.0, deltaVFinal, 0.0);
ImpulseManeuver secondManeuver = new ImpulseManeuver(endDateDetector, attitudeProvider, deltaVSat2, isp);

// propagate
propagator.addEventDetector(firstManeuver);
propagator.addEventDetector(secondManeuver);

DateScalesEnum endTimeScale = DateScalesEnum.UTC;
double[] endCalendarEpochArray = {2022, 4, 8, 1, 0, 0.0};
Epoch endEpoch = FotBuildersFactory.buildEpoch(endCalendarEpochArray, endTimeScale);
AbsoluteDate date = Fot2Orekit.mapToOrekitAbsoluteDate(endEpoch);

SpacecraftState state = propagator.propagate(date);

double finalAltitude = (state.getOrbit().getA());
double finalEccentricity = (state.getOrbit.getE());

Results
final sma (m) = 7392125.381281967 while theoritical is 8378136.6
final eccentricity = 3.0646135651698694E-4

Hohman Transfer script (LVLH Lof):
// Hohman Transfer computation
double rInit = 7378136.6;
double rFinal = 8378136.6;
double aTrans = (rInit + rFinal)/2;
double vInit = FastMath.sqrt(mu/rInit);
double vFinal = FastMath.sqrt(mu/rFinal);

double vTransInit = FastMath.sqrt(((2mu)/rInit)-(mu/aTrans));
double vTransFinal = FastMath.sqrt(((2
mu)/rFinal)-(mu/aTrans));

double deltaVInit = vTransInit - vInit;
double deltaVFinal = vFinal - vTransFinal;
double tTransfer = FastMath.PI*FastMath.sqrt(FastMath.pow(aTrans, 3)/mu);

// Load Orekit data
DataContext.getDefault().getDataProvidersManager().addProvider(new ClasspathCrawler(“orekit-data.zip”));

// reference Frame
Frame refFrame = FramesFactory.getGCRF();

// spacecraft mass
double mass = 500; // kg

// spacecraft initial state epoch
DateScalesEnum timeScale = DateScalesEnum.UTC;
double[] calendarEpochArray = {2022, 4, 7, 10, 10, 0.0};
Epoch initialEpoch = FotBuildersFactory.buildEpoch(calendarEpochArray, timeScale);
AbsoluteDate initialDate = Fot2Orekit.mapToOrekitAbsoluteDate(initialEpoch);

// initial state
double a = 7378136.6;
double e = 0.0;
double i = FastMath.toRadians(10.0);
double raan = FastMath.toRadians(0.0);
double argPer = FastMath.toRadians(0.0);
double trueAnomaly = 0.0;

KeplerianOrbit initialOrbit = new KeplerianOrbit(a, e, i, raan, argPer, trueAnomaly, PositionAngle.TRUE, refFrame, initialDate, mu);

// attitude provider definition
LofOffset attitudeProvider = new LofOffset(refFrame, LOFType.NTW);

// build orbit propagator
KeplerianPropagator propagator = new KeplerianPropagator(initialOrbit);

// define events detectors
// first event: date detector
double[] eventCalendarEpochArray = {2022, 4, 7, 20, 10, 0.0};
Epoch eventEpoch = FotBuildersFactory.buildEpoch(eventCalendarEpochArray, timeScale);
AbsoluteDate target = Fot2Orekit.mapToOrekitAbsoluteDate(eventEpoch);
ìEventDetector dateDetector = new DateDetector(target);

// second event: date detector
EventDetector endDateDetector = new DateDetector(target.shiftedBy(tTransfer));

// define impulsive maneuvers
// first maneuver
Vector3D deltaVSat1 = new Vector3D(0.0, deltaVInit, 0.0);
double isp = 285;
ImpulseManeuver firstManeuver = new ImpulseManeuver(dateDetector, attitudeProvider, deltaVSat1, isp);

// second maneuver
Vector3D deltaVSat2 = new Vector3D(0.0, deltaVFinal, 0.0);
ImpulseManeuver secondManeuver = new ImpulseManeuver(endDateDetector, attitudeProvider, deltaVSat2, isp);

// propagate
propagator.addEventDetector(firstManeuver);
propagator.addEventDetector(secondManeuver);

DateScalesEnum endTimeScale = DateScalesEnum.UTC;
double[] endCalendarEpochArray = {2022, 4, 8, 1, 0, 0.0};
Epoch endEpoch = FotBuildersFactory.buildEpoch(endCalendarEpochArray, endTimeScale);
AbsoluteDate date = Fot2Orekit.mapToOrekitAbsoluteDate(endEpoch);

SpacecraftState state = propagator.propagate(date);

double finalAltitude = (state.getOrbit().getA());
double finalEccentricity = (state.getOrbit.getE());

Results
final sma (m) = 8378136.599999996 while theoritical is 8378136.6
final eccentricity = 1.8563356288540018E-16

Hello,

I think you have encountered this bug:

Christophe

Hi Christophe,

Thanks for the support.
I believe this is the issue indeed.

Have a nice day.
Gueorguy

Also note that Maxime fixed this bug about one month ago and the fix was released as part of version 11.1.2.

1 Like