View Javadoc
1   /*
2    * Copyright (C) 2019 Alberto Irurueta Carro (alberto@irurueta.com)
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *         http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package com.irurueta.navigation.frames.converters;
17  
18  import com.irurueta.algebra.Matrix;
19  import com.irurueta.algebra.WrongSizeException;
20  import com.irurueta.geometry.InvalidRotationMatrixException;
21  import com.irurueta.navigation.frames.CoordinateTransformation;
22  import com.irurueta.navigation.frames.ECEFFrame;
23  import com.irurueta.navigation.frames.ECIFrame;
24  import com.irurueta.navigation.frames.ECIorECEFFrame;
25  import com.irurueta.navigation.frames.FrameType;
26  import com.irurueta.navigation.frames.InvalidSourceAndDestinationFrameTypeException;
27  import com.irurueta.navigation.geodesic.Constants;
28  import com.irurueta.units.Time;
29  import com.irurueta.units.TimeConverter;
30  import com.irurueta.units.TimeUnit;
31  
32  /**
33   * Converts from ECEF frame to ECI frame.
34   * This implementation is based on the equations defined in "Principles of GNSS, Inertial, and Multi-sensor
35   * Integrated Navigation Systems, Second Edition" and on the companion software available at:
36   * <a href="https://github.com/ymjdz/MATLAB-Codes/blob/master/ECEF_to_ECI.m">
37   *     https://github.com/ymjdz/MATLAB-Codes/blob/master/ECEF_to_ECI.m
38   * </a>
39   */
40  public class ECEFtoECIFrameConverter implements TimeIntervalFrameConverter<ECEFFrame, ECIFrame> {
41  
42      /**
43       * Earth rotation rate expressed in radians per second (rad/s).
44       */
45      public static final double EARTH_ROTATION_RATE = Constants.EARTH_ROTATION_RATE;
46  
47      /**
48       * Converts source ECEF frame to a new ECI frame instance.
49       *
50       * @param timeInterval a time interval expressed in seconds (s).
51       * @param source       source frame to convert from.
52       * @return a new destination frame instance.
53       */
54      @Override
55      public ECIFrame convertAndReturnNew(final double timeInterval, final ECEFFrame source) {
56          return convertECEFtoECIAndReturnNew(timeInterval, source);
57      }
58  
59      /**
60       * Converts source frame to a new destination frame instance.
61       *
62       * @param timeInterval a time interval.
63       * @param source       source frame to convert from.
64       * @return a new destination frame instance.
65       */
66      @Override
67      public ECIFrame convertAndReturnNew(final Time timeInterval, final ECEFFrame source) {
68          return convertECEFtoECIAndReturnNew(timeInterval, source);
69      }
70  
71      /**
72       * Converts source ECEF frame to destination ECI frame.
73       *
74       * @param timeInterval a time interval expressed in seconds (s).
75       * @param source       source frame to convert from.
76       * @param destination  destination frame instance to convert to.
77       */
78      @Override
79      public void convert(final double timeInterval, final ECEFFrame source, final ECIFrame destination) {
80          convertECEFtoECI(timeInterval, source, destination);
81      }
82  
83      /**
84       * Converts source frame to destination frame.
85       *
86       * @param timeInterval a time interval.
87       * @param source       source frame to convert from.
88       * @param destination  destination frame instance to covert to.
89       */
90      @Override
91      public void convert(final Time timeInterval, final ECEFFrame source, final ECIFrame destination) {
92          convertECEFtoECI(timeInterval, source, destination);
93      }
94  
95      /**
96       * Gets source frame type.
97       *
98       * @return source frame type.
99       */
100     @Override
101     public FrameType getSourceType() {
102         return FrameType.EARTH_CENTERED_EARTH_FIXED_FRAME;
103     }
104 
105     /**
106      * Gets destination frame type.
107      *
108      * @return destination frame type.
109      */
110     @Override
111     public FrameType getDestinationType() {
112         return FrameType.EARTH_CENTERED_INERTIAL_FRAME;
113     }
114 
115     /**
116      * Converts source ECEF frame to a new ECI frame instance.
117      *
118      * @param timeInterval a time interval expressed in seconds (s).
119      * @param source       source frame to convert from.
120      * @return a new destination frame instance.
121      */
122     public static ECIFrame convertECEFtoECIAndReturnNew(final double timeInterval, final ECEFFrame source) {
123         final var result = new ECIFrame();
124         convertECEFtoECI(timeInterval, source, result);
125         return result;
126     }
127 
128     /**
129      * Converts source ECEF frame to a new ECI frame instance.
130      *
131      * @param timeInterval a time interval.
132      * @param source       source frame to convert from.
133      * @return a new destination frame instance.
134      */
135     public static ECIFrame convertECEFtoECIAndReturnNew(final Time timeInterval, final ECEFFrame source) {
136         return convertECEFtoECIAndReturnNew(TimeConverter.convert(timeInterval.getValue().doubleValue(),
137                 timeInterval.getUnit(), TimeUnit.SECOND), source);
138     }
139 
140     /**
141      * Converts source ECEF frame to destination ECI frame.
142      *
143      * @param timeInterval a time interval expressed in seconds (s).
144      * @param source       source frame to convert from.
145      * @param destination  destination frame instance to convert to.
146      */
147     @SuppressWarnings("DuplicatedCode")
148     public static void convertECEFtoECI(final double timeInterval, final ECEFFrame source, final ECIFrame destination) {
149         try {
150             // Calculate ECEF to ECI coordinate transformation matrix using (2.145)
151             final var alpha = EARTH_ROTATION_RATE * timeInterval;
152             final var cei = CoordinateTransformation.ecefToEciMatrixFromAngle(alpha);
153 
154             // Transform position using (2.146)
155             final var rEbe = new Matrix(ECIorECEFFrame.NUM_POSITION_COORDINATES, 1);
156             rEbe.setElementAtIndex(0, source.getX());
157             rEbe.setElementAtIndex(1, source.getY());
158             rEbe.setElementAtIndex(2, source.getZ());
159 
160             final var rIbi = cei.multiplyAndReturnNew(rEbe);
161 
162             destination.setCoordinates(rIbi.getElementAtIndex(0),
163                     rIbi.getElementAtIndex(1), rIbi.getElementAtIndex(2));
164 
165             // Transform velocity using (2.145)
166             final var tmp = new Matrix(ECIorECEFFrame.NUM_POSITION_COORDINATES, 1);
167             tmp.setElementAtIndex(0, -source.getY());
168             tmp.setElementAtIndex(1, source.getX());
169             tmp.setElementAtIndex(2, 0.0);
170             tmp.multiplyByScalar(EARTH_ROTATION_RATE);
171 
172             final var vEbe = new Matrix(ECIorECEFFrame.NUM_VELOCITY_COORDINATES, 1);
173             vEbe.setElementAtIndex(0, source.getVx());
174             vEbe.setElementAtIndex(1, source.getVy());
175             vEbe.setElementAtIndex(2, source.getVz());
176 
177             // vEbe + omega * [-y;x;0]
178             vEbe.add(tmp);
179 
180             final var vIbi = cei.multiplyAndReturnNew(vEbe);
181 
182             destination.setVelocityCoordinates(vIbi.getElementAtIndex(0),
183                     vIbi.getElementAtIndex(1), vIbi.getElementAtIndex(2));
184 
185             // Transform attitude using (2.15)
186             // cbi = cei * cbe
187             final var cbe = source.getCoordinateTransformationMatrix();
188             cei.multiply(cbe);
189 
190             final var c = new CoordinateTransformation(cei,
191                     FrameType.BODY_FRAME, FrameType.EARTH_CENTERED_INERTIAL_FRAME);
192             destination.setCoordinateTransformation(c);
193         } catch (final WrongSizeException | InvalidSourceAndDestinationFrameTypeException |
194                 InvalidRotationMatrixException ignore) {
195             // never happens
196         }
197     }
198 
199     /**
200      * Converts source ECEF frame to destination ECI frame.
201      *
202      * @param timeInterval a time interval.
203      * @param source       source frame to convert from.
204      * @param destination  destination frame instance to convert to.
205      */
206     public static void convertECEFtoECI(final Time timeInterval, final ECEFFrame source, final ECIFrame destination) {
207         convertECEFtoECI(TimeConverter.convert(timeInterval.getValue().doubleValue(), timeInterval.getUnit(),
208                 TimeUnit.SECOND), source, destination);
209     }
210 }