1 /* Copyright 2002-2024 CS GROUP
2 * Licensed to CS GROUP (CS) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * CS licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.orekit.forces.empirical;
18
19 import java.util.List;
20 import java.util.stream.Stream;
21
22 import org.hipparchus.CalculusFieldElement;
23 import org.hipparchus.Field;
24 import org.hipparchus.geometry.euclidean.threed.FieldRotation;
25 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
26 import org.hipparchus.geometry.euclidean.threed.Rotation;
27 import org.hipparchus.geometry.euclidean.threed.Vector3D;
28 import org.orekit.attitudes.AttitudeProvider;
29 import org.orekit.forces.ForceModel;
30 import org.orekit.propagation.FieldSpacecraftState;
31 import org.orekit.propagation.SpacecraftState;
32 import org.orekit.propagation.events.EventDetector;
33 import org.orekit.propagation.events.FieldEventDetector;
34 import org.orekit.time.AbsoluteDate;
35 import org.orekit.time.FieldAbsoluteDate;
36 import org.orekit.utils.ParameterDriver;
37
38 /** This class implements a parametric acceleration.
39 * <p>Parametric accelerations are intended to model lesser-known
40 * forces, estimating a few defining parameters from a parametric
41 * function using orbit determination. Typical parametric functions
42 * are polynomial (often limited to a constant term) and harmonic
43 * (often with either orbital period or half orbital period).</p>
44 * <p>An important operational example is the infamous GPS Y-bias,
45 * which is thought to be related to a radiator thermal radiation.
46 * Other examples could be to model leaks that produce roughly constant
47 * trust in some spacecraft-related direction.</p>
48 * <p>The acceleration direction is considered constant in either:
49 * </p>
50 * <ul>
51 * <li>inertial frame</li>
52 * <li>spacecraft frame</li>
53 * <li>a dedicated attitude frame overriding spacecraft attitude
54 * (this could for example be used to model solar arrays orientation
55 * if the force is related to solar arrays)</li>
56 * </ul>
57 * <p>
58 * If the direction of the acceleration is unknown, then three instances
59 * of this class should be used, one along the X axis, one along the Y
60 * axis and one along the Z axis and their parameters estimated as usual.
61 * </p>
62 * @since 10.3
63 * @author Luc Maisonobe
64 * @author Bryan Cazabonne
65 * @author Melina Vanel
66 */
67 public class ParametricAcceleration implements ForceModel {
68
69 /** Direction of the acceleration in defining frame. */
70 private final Vector3D direction;
71
72 /** Flag for inertial acceleration direction. */
73 private final boolean isInertial;
74
75 /** The attitude to override, if set. */
76 private final AttitudeProvider attitudeOverride;
77
78 /** Acceleration model. */
79 private final AccelerationModel accelerationModel;
80
81 /** Simple constructor.
82 * @param direction acceleration direction in overridden spacecraft frame
83 * @param isInertial if true, direction is defined in the same inertial
84 * frame used for propagation (i.e. {@link SpacecraftState#getFrame()}),
85 * otherwise direction is defined in spacecraft frame (i.e. using the
86 * propagation {@link
87 * org.orekit.propagation.Propagator#setAttitudeProvider(AttitudeProvider)
88 * attitude law})
89 * @param accelerationModel acceleration model used to compute the contribution of the empirical acceleration
90 * direction
91 */
92 public ParametricAcceleration(final Vector3D direction,
93 final boolean isInertial,
94 final AccelerationModel accelerationModel) {
95 this(direction, isInertial, null, accelerationModel);
96 }
97
98 /** Simple constructor.
99 * @param direction acceleration direction in overridden spacecraft frame
100 * frame used for propagation (i.e. {@link SpacecraftState#getFrame()}),
101 * otherwise direction is defined in spacecraft frame (i.e. using the
102 * propagation {@link
103 * org.orekit.propagation.Propagator#setAttitudeProvider(AttitudeProvider)
104 * attitude law})
105 * @param attitudeOverride provider for attitude used to compute acceleration
106 * @param accelerationModel acceleration model used to compute the contribution of the empirical acceleration
107 * direction
108 */
109 public ParametricAcceleration(final Vector3D direction,
110 final AttitudeProvider attitudeOverride,
111 final AccelerationModel accelerationModel) {
112 this(direction, false, attitudeOverride, accelerationModel);
113 }
114
115 /** Simple constructor.
116 * @param direction acceleration direction in overridden spacecraft frame
117 * @param isInertial if true, direction is defined in the same inertial
118 * frame used for propagation (i.e. {@link SpacecraftState#getFrame()}),
119 * otherwise direction is defined in spacecraft frame (i.e. using the
120 * propagation {@link
121 * org.orekit.propagation.Propagator#setAttitudeProvider(AttitudeProvider)
122 * attitude law})
123 * @param attitudeOverride provider for attitude used to compute acceleration
124 * @param accelerationModel acceleration model used to compute the contribution of the empirical acceleration
125 * direction
126 */
127 private ParametricAcceleration(final Vector3D direction,
128 final boolean isInertial,
129 final AttitudeProvider attitudeOverride,
130 final AccelerationModel accelerationModel) {
131 this.direction = direction;
132 this.isInertial = isInertial;
133 this.attitudeOverride = attitudeOverride;
134 this.accelerationModel = accelerationModel;
135 }
136
137 /** {@inheritDoc} */
138 @Override
139 public boolean dependsOnPositionOnly() {
140 return isInertial;
141 }
142
143 /** {@inheritDoc} */
144 @Override
145 public List<ParameterDriver> getParametersDrivers() {
146 return accelerationModel.getParametersDrivers();
147 }
148
149 /** {@inheritDoc} */
150 @Override
151 public void init(final SpacecraftState initialState, final AbsoluteDate target) {
152 accelerationModel.init(initialState, target);
153 }
154
155 /** {@inheritDoc} */
156 @Override
157 public Vector3D acceleration(final SpacecraftState state,
158 final double[] parameters) {
159
160 // Date
161 final AbsoluteDate date = state.getDate();
162
163 final Vector3D inertialDirection;
164 if (isInertial) {
165 // the acceleration direction is already defined in the inertial frame
166 inertialDirection = direction;
167 } else {
168 final Rotation rotation;
169 if (attitudeOverride == null) {
170 // the acceleration direction is defined in spacecraft frame as set by the propagator
171 rotation = state.getAttitude().getRotation();
172 } else {
173 // the acceleration direction is defined in a dedicated frame
174 rotation = attitudeOverride.getAttitudeRotation(state.getOrbit(), date, state.getFrame());
175 }
176 inertialDirection = rotation.applyInverseTo(direction);
177 }
178
179 // Call the acceleration model to compute the acceleration
180 return new Vector3D(accelerationModel.signedAmplitude(state, parameters), inertialDirection);
181
182 }
183
184 /** {@inheritDoc} */
185 @Override
186 public <T extends CalculusFieldElement<T>> FieldVector3D<T> acceleration(final FieldSpacecraftState<T> state,
187 final T[] parameters) {
188
189 // Date
190 final FieldAbsoluteDate<T> date = state.getDate();
191
192 final FieldVector3D<T> inertialDirection;
193 if (isInertial) {
194 // the acceleration direction is already defined in the inertial frame
195 inertialDirection = new FieldVector3D<>(date.getField(), direction);
196 } else {
197 final FieldRotation<T> rotation;
198 if (attitudeOverride == null) {
199 // the acceleration direction is defined in spacecraft frame as set by the propagator
200 rotation = state.getAttitude().getRotation();
201 } else {
202 // the acceleration direction is defined in a dedicated frame
203 rotation = attitudeOverride.getAttitudeRotation(state.getOrbit(), date, state.getFrame());
204 }
205 inertialDirection = rotation.applyInverseTo(direction);
206 }
207
208 // Call the acceleration model to compute the acceleration
209 return new FieldVector3D<>(accelerationModel.signedAmplitude(state, parameters), inertialDirection);
210
211 }
212
213
214 /** {@inheritDoc} */
215 @Override
216 public Stream<EventDetector> getEventDetectors() {
217 return Stream.empty();
218 }
219
220 /** {@inheritDoc} */
221 @Override
222 public <T extends CalculusFieldElement<T>> Stream<FieldEventDetector<T>> getFieldEventDetectors(final Field<T> field) {
223 return Stream.empty();
224 }
225
226 }