1 /* Copyright 2002-2021 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.Field;
23 import org.hipparchus.CalculusFieldElement;
24 import org.hipparchus.geometry.euclidean.threed.FieldVector3D;
25 import org.hipparchus.geometry.euclidean.threed.Vector3D;
26 import org.orekit.attitudes.Attitude;
27 import org.orekit.attitudes.AttitudeProvider;
28 import org.orekit.attitudes.FieldAttitude;
29 import org.orekit.forces.AbstractForceModel;
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.utils.ParameterDriver;
36
37 /** This class implements a parametric acceleration.
38 * <p>Parametric accelerations are intended to model lesser-known
39 * forces, estimating a few defining parameters from a parametric
40 * function using orbit determination. Typical parametric functions
41 * are polynomial (often limited to a constant term) and harmonic
42 * (often with either orbital period or half orbital period).</p>
43 * <p>An important operational example is the infamous GPS Y-bias,
44 * which is thought to be related to a radiator thermal radiation.
45 * Other examples could be to model leaks that produce roughly constant
46 * trust in some spacecraft-related direction.</p>
47 * <p>The acceleration direction is considered constant in either:
48 * </p>
49 * <ul>
50 * <li>inertial frame</li>
51 * <li>spacecraft frame</li>
52 * <li>a dedicated attitude frame overriding spacecraft attitude
53 * (this could for example be used to model solar arrays orientation
54 * if the force is related to solar arrays)</li>
55 * </ul>
56 * <p>
57 * If the direction of the acceleration is unknown, then three instances
58 * of this class should be used, one along the X axis, one along the Y
59 * axis and one along the Z axis and their parameters estimated as usual.
60 * </p>
61 * @since 10.3
62 * @author Luc Maisonobe
63 * @author Bryan Cazabonne
64 */
65 public class ParametricAcceleration extends AbstractForceModel {
66
67 /** Direction of the acceleration in defining frame. */
68 private final Vector3D direction;
69
70 /** Flag for inertial acceleration direction. */
71 private final boolean isInertial;
72
73 /** The attitude to override, if set. */
74 private final AttitudeProvider attitudeOverride;
75
76 /** Acceleration model. */
77 private final AccelerationModel accelerationModel;
78
79 /** Simple constructor.
80 * @param direction acceleration direction in overridden spacecraft frame
81 * @param isInertial if true, direction is defined in the same inertial
82 * frame used for propagation (i.e. {@link SpacecraftState#getFrame()}),
83 * otherwise direction is defined in spacecraft frame (i.e. using the
84 * propagation {@link
85 * org.orekit.propagation.Propagator#setAttitudeProvider(AttitudeProvider)
86 * attitude law})
87 * @param accelerationModel acceleration model used to compute the contribution of the empirical acceleration
88 * direction
89 */
90 public ParametricAcceleration(final Vector3D direction,
91 final boolean isInertial,
92 final AccelerationModel accelerationModel) {
93 this(direction, isInertial, null, accelerationModel);
94 }
95
96 /** Simple constructor.
97 * @param direction acceleration direction in overridden spacecraft frame
98 * frame used for propagation (i.e. {@link SpacecraftState#getFrame()}),
99 * otherwise direction is defined in spacecraft frame (i.e. using the
100 * propagation {@link
101 * org.orekit.propagation.Propagator#setAttitudeProvider(AttitudeProvider)
102 * attitude law})
103 * @param attitudeOverride provider for attitude used to compute acceleration
104 * @param accelerationModel acceleration model used to compute the contribution of the empirical acceleration
105 * direction
106 */
107 public ParametricAcceleration(final Vector3D direction,
108 final AttitudeProvider attitudeOverride,
109 final AccelerationModel accelerationModel) {
110 this(direction, false, attitudeOverride, accelerationModel);
111 }
112
113 /** Simple constructor.
114 * @param direction acceleration direction in overridden spacecraft frame
115 * @param isInertial if true, direction is defined in the same inertial
116 * frame used for propagation (i.e. {@link SpacecraftState#getFrame()}),
117 * otherwise direction is defined in spacecraft frame (i.e. using the
118 * propagation {@link
119 * org.orekit.propagation.Propagator#setAttitudeProvider(AttitudeProvider)
120 * attitude law})
121 * @param attitudeOverride provider for attitude used to compute acceleration
122 * @param accelerationModel acceleration model used to compute the contribution of the empirical acceleration
123 * direction
124 */
125 private ParametricAcceleration(final Vector3D direction,
126 final boolean isInertial,
127 final AttitudeProvider attitudeOverride,
128 final AccelerationModel accelerationModel) {
129 this.direction = direction;
130 this.isInertial = isInertial;
131 this.attitudeOverride = attitudeOverride;
132 this.accelerationModel = accelerationModel;
133 }
134
135 /** {@inheritDoc} */
136 @Override
137 public boolean dependsOnPositionOnly() {
138 return isInertial;
139 }
140
141 /** {@inheritDoc} */
142 @Override
143 public List<ParameterDriver> getParametersDrivers() {
144 return accelerationModel.getParametersDrivers();
145 }
146
147 /** {@inheritDoc} */
148 @Override
149 public void init(final SpacecraftState initialState, final AbsoluteDate target) {
150 accelerationModel.init(initialState, target);
151 }
152
153 /** {@inheritDoc} */
154 @Override
155 public Vector3D acceleration(final SpacecraftState state,
156 final double[] parameters) {
157
158 final Vector3D inertialDirection;
159 if (isInertial) {
160 // the acceleration direction is already defined in the inertial frame
161 inertialDirection = direction;
162 } else {
163 final Attitude attitude;
164 if (attitudeOverride == null) {
165 // the acceleration direction is defined in spacecraft frame as set by the propagator
166 attitude = state.getAttitude();
167 } else {
168 // the acceleration direction is defined in a dedicated frame
169 attitude = attitudeOverride.getAttitude(state.getOrbit(), state.getDate(), state.getFrame());
170 }
171 inertialDirection = attitude.getRotation().applyInverseTo(direction);
172 }
173
174 // Call the acceleration model to compute the acceleration
175 return new Vector3D(accelerationModel.signedAmplitude(state, parameters), inertialDirection);
176
177 }
178
179 /** {@inheritDoc} */
180 @Override
181 public <T extends CalculusFieldElement<T>> FieldVector3D<T> acceleration(final FieldSpacecraftState<T> state,
182 final T[] parameters) {
183
184 final FieldVector3D<T> inertialDirection;
185 if (isInertial) {
186 // the acceleration direction is already defined in the inertial frame
187 inertialDirection = new FieldVector3D<>(state.getDate().getField(), direction);
188 } else {
189 final FieldAttitude<T> attitude;
190 if (attitudeOverride == null) {
191 // the acceleration direction is defined in spacecraft frame as set by the propagator
192 attitude = state.getAttitude();
193 } else {
194 // the acceleration direction is defined in a dedicated frame
195 attitude = attitudeOverride.getAttitude(state.getOrbit(), state.getDate(), state.getFrame());
196 }
197 inertialDirection = attitude.getRotation().applyInverseTo(direction);
198 }
199
200 // Call the acceleration model to compute the acceleration
201 return new FieldVector3D<>(accelerationModel.signedAmplitude(state, parameters), inertialDirection);
202
203 }
204
205 /** {@inheritDoc} */
206 @Override
207 public Stream<EventDetector> getEventsDetectors() {
208 return Stream.empty();
209 }
210
211 /** {@inheritDoc} */
212 @Override
213 public <T extends CalculusFieldElement<T>> Stream<FieldEventDetector<T>> getFieldEventsDetectors(final Field<T> field) {
214 return Stream.empty();
215 }
216
217 }