Commit 6d3c4c87 authored by Luc Maisonobe's avatar Luc Maisonobe
Browse files

Added LTM, UTM, FULL, LTMWCC and UTMWCC covariance ordering.

parent fb66d157
......@@ -43,28 +43,30 @@ public class Covariance implements TimeStamped {
/** Simple constructor.
* @param type type of the elements
* @param ordering ordering to use
* @param date entry date
* @param fields matrix elements
* @param first index of first field to consider
*/
public Covariance(final ElementsType type, final AbsoluteDate date,
public Covariance(final ElementsType type, final Ordering ordering, final AbsoluteDate date,
final String[] fields, final int first) {
final List<Unit> units = type.getUnits();
this.type = type;
this.date = date;
this.matrix = MatrixUtils.createRealMatrix(units.size(), units.size());
int k = 0;
for (int i = 0; i < matrix.getRowDimension(); ++i) {
final Unit ui = units.get(i);
for (int j = 0; j <= i; ++j) {
final Unit uj = units.get(j);
final double rawij = Double.parseDouble(fields[first + k++]);
final double cij = ui.toSI(uj.toSI(rawij));
matrix.setEntry(i, j, cij);
if (j < i) {
matrix.setEntry(j, i, cij);
final CovarianceIndexer indexer = new CovarianceIndexer(units.size());
for (int k = 0; first + k < fields.length; ++k) {
if (!indexer.isCrossCorrelation()) {
final int i = indexer.getRow();
final int j = indexer.getColumn();
final double raw = Double.parseDouble(fields[first + k]);
final double converted = units.get(i).toSI(units.get(j).toSI(raw));
matrix.setEntry(i, j, converted);
if (i != j) {
matrix.setEntry(j, i, converted);
}
}
ordering.update(indexer);
}
}
......
......@@ -65,6 +65,9 @@ public class CovarianceHistoryMetadata extends CommentsContainer {
/** Covariance element set type. */
private ElementsType covType;
/** Covariance ordering. */
private Ordering covOrdering;
/** Units of covariance element set. */
private List<Unit> covUnits;
......@@ -74,14 +77,15 @@ public class CovarianceHistoryMetadata extends CommentsContainer {
CovarianceHistoryMetadata(final AbsoluteDate epochT0) {
// we don't call the setXxx() methods in order to avoid
// calling refuseFurtherComments as a side effect
covBasis = "PREDICTED";
covReferenceFrame = new FrameFacade(null, null,
OrbitRelativeFrame.TNW_INERTIAL, null,
OrbitRelativeFrame.TNW_INERTIAL.name());
covFrameEpoch = epochT0;
covScaleMin = 1.0;
covScaleMax = 1.0;
covType = ElementsType.CARTPV;
covBasis = "PREDICTED";
covReferenceFrame = new FrameFacade(null, null,
OrbitRelativeFrame.TNW_INERTIAL, null,
OrbitRelativeFrame.TNW_INERTIAL.name());
covFrameEpoch = epochT0;
covScaleMin = 1.0;
covScaleMax = 1.0;
covType = ElementsType.CARTPV;
covOrdering = Ordering.LTM;
}
/** {@inheritDoc} */
......@@ -255,6 +259,21 @@ public class CovarianceHistoryMetadata extends CommentsContainer {
this.covType = covType;
}
/** Get covariance ordering.
* @return covariance ordering
*/
public Ordering getCovOrdering() {
return covOrdering;
}
/** Set covariance ordering.
* @param covOrdering covariance ordering
*/
public void setCovOrdering(final Ordering covOrdering) {
refuseFurtherComments();
this.covOrdering = covOrdering;
}
/** Get covariance element set units.
* @return covariance element set units
*/
......
......@@ -71,6 +71,9 @@ public enum CovarianceHistoryMetadataKey {
*/
COV_TYPE((token, context, container) -> token.processAsEnum(ElementsType.class, container::setCovType)),
/** Covariance ordering. */
COV_ORDERING((token, context, container) -> token.processAsEnum(Ordering.class, container::setCovOrdering)),
/** SI units for each elements of the covariance. */
COV_UNITS((token, context, container) -> token.processAsUnitList(container::setCovUnits));
......
......@@ -21,6 +21,7 @@ import java.io.IOException;
import java.util.List;
import org.hipparchus.linear.RealMatrix;
import org.hipparchus.util.FastMath;
import org.orekit.files.ccsds.definitions.TimeConverter;
import org.orekit.files.ccsds.section.AbstractWriter;
import org.orekit.files.ccsds.utils.FileFormat;
......@@ -76,20 +77,33 @@ class CovarianceHistoryWriter extends AbstractWriter {
generator.writeEntry(CovarianceHistoryMetadataKey.COV_CONFIDENCE.name(), metadata.getCovConfidence(), Unit.PERCENT, false);
// elements
generator.writeEntry(CovarianceHistoryMetadataKey.COV_TYPE.name(), metadata.getCovType(), false);
generator.writeEntry(CovarianceHistoryMetadataKey.COV_UNITS.name(), generator.unitsListToString(metadata.getCovUnits()), null, false);
generator.writeEntry(CovarianceHistoryMetadataKey.COV_TYPE.name(), metadata.getCovType(), false);
generator.writeEntry(CovarianceHistoryMetadataKey.COV_ORDERING.name(), metadata.getCovOrdering(), false);
generator.writeEntry(CovarianceHistoryMetadataKey.COV_UNITS.name(), generator.unitsListToString(metadata.getCovUnits()), null, false);
// data
final List<Unit> units = metadata.getCovType().getUnits();
for (final Covariance covariance : history.getCovariances()) {
final RealMatrix matrix = covariance.getMatrix();
final StringBuilder line = new StringBuilder();
final RealMatrix matrix = covariance.getMatrix();
final Ordering ordering = metadata.getCovOrdering();
final CovarianceIndexer indexer = new CovarianceIndexer(units.size());
final StringBuilder line = new StringBuilder();
line.append(generator.dateToString(timeConverter, covariance.getDate()));
for (int i = 0; i < units.size(); ++i) {
for (int j = 0; j <= i; ++j) {
line.append(' ');
line.append(AccurateFormatter.format(units.get(i).fromSI(units.get(j).fromSI(matrix.getEntry(i, j)))));
for (int k = 0; k < ordering.nbElements(units.size()); ++k) {
final int i = indexer.getRow();
final int j = indexer.getColumn();
final double cij;
if (indexer.isCrossCorrelation()) {
// we need to compute the cross-correlation
cij = matrix.getEntry(i, j) /
FastMath.sqrt(matrix.getEntry(i, i) * matrix.getEntry(j, j));
} else {
// we need to get the covariance
cij = units.get(i).fromSI(units.get(j).fromSI(matrix.getEntry(i, j)));
}
line.append(' ');
line.append(AccurateFormatter.format(cij));
ordering.update(indexer);
}
if (generator.getFormat() == FileFormat.XML) {
generator.writeEntry(OcmFile.COV_LINE, line.toString(), null, true);
......
/* Copyright 2002-2021 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.files.ccsds.ndm.odm.ocm;
/** Container for covariance matrix elements indices.
* @author Luc Maisonobe
* @since 11.0
*/
class CovarianceIndexer {
/** Matrix dimension. */
private final int dimension;
/** Row index. */
private int row;
/** Column index. */
private int column;
/** Flag for cross-correlation trems. */
private boolean crossCorrelation;
/** Build an indexer pointing at first row first column,.
* @param dimension matrix dimension
*/
CovarianceIndexer(final int dimension) {
this.dimension = dimension;
this.row = 0;
this.column = 0;
this.crossCorrelation = false;
}
/** Get matrix dimension.
* @return matrix dimension
*/
public int getDimension() {
return dimension;
}
/** Get row index.
* @return row index
*/
public int getRow() {
return row;
}
/** Set row index.
* @param row row index
*/
public void setRow(final int row) {
this.row = row;
}
/** Get column index.
* @return column index
*/
public int getColumn() {
return column;
}
/** Set column index.
* @param column column index
*/
public void setColumn(final int column) {
this.column = column;
}
/** Set cross-correlation flag.
* @param crossCorrelation if true, element is a cross-correlation term
*/
public void setCrossCorrelation(final boolean crossCorrelation) {
this.crossCorrelation = crossCorrelation;
}
/** Check if element is a cross-correlation term.
* @return true if element is a cross-correlation term
*/
public boolean isCrossCorrelation() {
return crossCorrelation;
}
}
......@@ -554,11 +554,12 @@ public class OcmParser extends OdmParser<OcmFile, OcmParser> implements Ephemeri
try {
final String[] fields = SPLIT_AT_BLANKS.split(token.getRawContent().trim());
final int n = currentCovarianceHistoryMetadata.getCovUnits().size();
if (fields.length != 1 + (n * (n + 1) / 2)) {
if (fields.length - 1 != currentCovarianceHistoryMetadata.getCovOrdering().nbElements(n)) {
throw new OrekitException(OrekitMessages.UNABLE_TO_PARSE_LINE_IN_FILE,
token.getLineNumber(), token.getFileName(), token.getContentAsNormalizedString());
}
currentCovarianceHistory.add(new Covariance(currentCovarianceHistoryMetadata.getCovType(),
currentCovarianceHistoryMetadata.getCovOrdering(),
context.getTimeSystem().getConverter(context).parse(fields[0]),
fields, 1));
return true;
......
/* Copyright 2002-2021 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.files.ccsds.ndm.odm.ocm;
/** Keys for {@link Covariance} elements ordering.
* @author Luc Maisonobe
* @since 11.0
*/
public enum Ordering {
/** Lower Triangular Matrix. */
LTM {
/** {@inheritDoc} */
@Override
int nbElements(final int dimension) {
return (dimension * (dimension + 1)) / 2;
}
/** {@inheritDoc} */
@Override
void update(final CovarianceIndexer indexer) {
final int i = indexer.getRow();
final int j = indexer.getColumn();
if (j < i) {
// continue on same row
indexer.setColumn(j + 1);
} else {
// start new row
indexer.setRow(i + 1);
indexer.setColumn(0);
}
}
},
/** Upper Triangular Matrix. */
UTM {
/** {@inheritDoc} */
@Override
int nbElements(final int dimension) {
return (dimension * (dimension + 1)) / 2;
}
/** {@inheritDoc} */
@Override
void update(final CovarianceIndexer indexer) {
final int i = indexer.getRow();
final int j = indexer.getColumn();
if (j + 1 < indexer.getDimension()) {
// continue on same row
indexer.setColumn(j + 1);
} else {
// start new row
indexer.setRow(i + 1);
indexer.setColumn(i + 1);
}
}
},
/** Full symmetrix Matrix. */
FULL {
/** {@inheritDoc} */
@Override
int nbElements(final int dimension) {
return dimension * dimension;
}
/** {@inheritDoc} */
@Override
void update(final CovarianceIndexer indexer) {
final int i = indexer.getRow();
final int j = indexer.getColumn();
if (j + 1 < indexer.getDimension()) {
// continue on same row
indexer.setColumn(j + 1);
} else {
// start new row
indexer.setRow(i + 1);
indexer.setColumn(0);
}
}
},
/** Lower Triangular Matrix conflated with cross-correlation terms. */
LTMWCC {
/** {@inheritDoc} */
@Override
int nbElements(final int dimension) {
return FULL.nbElements(dimension);
}
/** {@inheritDoc} */
@Override
void update(final CovarianceIndexer indexer) {
FULL.update(indexer);
indexer.setCrossCorrelation(indexer.getColumn() > indexer.getRow());
}
},
/** Upper Triangular Matrix conflated with cross-correlation terms. */
UTMWCC {
/** {@inheritDoc} */
@Override
int nbElements(final int dimension) {
return FULL.nbElements(dimension);
}
/** {@inheritDoc} */
@Override
void update(final CovarianceIndexer indexer) {
FULL.update(indexer);
indexer.setCrossCorrelation(indexer.getRow() > indexer.getColumn());
}
};
/** Get number of ordered elements.
* @param dimension matrix dimension
* @return number of ordered elements
*/
abstract int nbElements(int dimension);
/** Update indexer.
* @param indexer index to update for handling next element
*/
abstract void update(CovarianceIndexer indexer);
}
......@@ -1041,7 +1041,7 @@ public class OcmParserTest {
Assert.assertEquals( 300.0, ch0.getCovariances().get(1).getDate().durationFrom(epoch), 1.0e-10);
Assert.assertEquals(13.2e6, ch0.getCovariances().get(1).getMatrix().getEntry(2, 1), 1.0e-10);
Assert.assertEquals( 600.0, ch0.getCovariances().get(2).getDate().durationFrom(epoch), 1.0e-10);
Assert.assertEquals(26.5e6, ch0.getCovariances().get(2).getMatrix().getEntry(4, 5), 1.0e-10);
Assert.assertEquals(26.5e6, ch0.getCovariances().get(2).getMatrix().getEntry(4, 5), 1.0e-10);
CovarianceHistory ch1 = file.getData().getCovarianceBlocks().get(1);
Assert.assertEquals("this is number 2 COV comment", ch1.getMetadata().getComments().get(0));
Assert.assertEquals("covariance 2", ch1.getMetadata().getCovID());
......@@ -1049,10 +1049,12 @@ public class OcmParserTest {
Assert.assertEquals("covariance 3", ch1.getMetadata().getCovNextID());
Assert.assertEquals("SIMULATED", ch1.getMetadata().getCovBasis());
Assert.assertEquals("basis 2", ch1.getMetadata().getCovBasisID());
Assert.assertEquals(3, ch1.getCovariances().size());
Assert.assertEquals(1800.0, ch1.getCovariances().get(0).getDate().durationFrom(epoch), 1.0e-10);
Assert.assertEquals(2100.0, ch1.getCovariances().get(1).getDate().durationFrom(epoch), 1.0e-10);
Assert.assertEquals(2400.0, ch1.getCovariances().get(2).getDate().durationFrom(epoch), 1.0e-10);
Assert.assertEquals(1, ch1.getCovariances().size());
Assert.assertEquals(1800.0, ch1.getCovariances().get(0).getDate().durationFrom(epoch), 1.0e-10);
Assert.assertEquals(43.0e6, ch1.getCovariances().get(0).getMatrix().getEntry(0, 0), 1.0e-10);
Assert.assertEquals(20.0e6, ch1.getCovariances().get(0).getMatrix().getEntry(0, 1), 1.0e-10);
Assert.assertEquals( 6.0e6, ch1.getCovariances().get(0).getMatrix().getEntry(0, 5), 1.0e-10);
Assert.assertEquals( 2.0e6, ch1.getCovariances().get(0).getMatrix().getEntry(4, 3), 1.0e-10);
// check maneuver data
Assert.assertEquals(3, file.getData().getManeuverBlocks().size());
......
/* Copyright 2002-2021 CS GROUP
* Licensed to CS Systèmes d'Information (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.files.ccsds.ndm.odm.ocm;
import org.junit.Assert;
import org.junit.Test;
public class OrderingTest {
@Test
public void testLTM() {
Assert.assertEquals(10, Ordering.LTM.nbElements(4));
final CovarianceIndexer indexer = new CovarianceIndexer(4);
checkIndexer(indexer, 0, 0, false);
Ordering.LTM.update(indexer);
checkIndexer(indexer, 1, 0, false);
Ordering.LTM.update(indexer);
checkIndexer(indexer, 1, 1, false);
Ordering.LTM.update(indexer);
checkIndexer(indexer, 2, 0, false);
Ordering.LTM.update(indexer);
checkIndexer(indexer, 2, 1, false);
Ordering.LTM.update(indexer);
checkIndexer(indexer, 2, 2, false);
Ordering.LTM.update(indexer);
checkIndexer(indexer, 3, 0, false);
Ordering.LTM.update(indexer);
checkIndexer(indexer, 3, 1, false);
Ordering.LTM.update(indexer);
checkIndexer(indexer, 3, 2, false);
Ordering.LTM.update(indexer);
checkIndexer(indexer, 3, 3, false);
}
@Test
public void testUTM() {
Assert.assertEquals(10, Ordering.UTM.nbElements(4));
final CovarianceIndexer indexer = new CovarianceIndexer(4);
checkIndexer(indexer, 0, 0, false);
Ordering.UTM.update(indexer);
checkIndexer(indexer, 0, 1, false);
Ordering.UTM.update(indexer);
checkIndexer(indexer, 0, 2, false);
Ordering.UTM.update(indexer);
checkIndexer(indexer, 0, 3, false);
Ordering.UTM.update(indexer);
checkIndexer(indexer, 1, 1, false);
Ordering.UTM.update(indexer);
checkIndexer(indexer, 1, 2, false);
Ordering.UTM.update(indexer);
checkIndexer(indexer, 1, 3, false);
Ordering.UTM.update(indexer);
checkIndexer(indexer, 2, 2, false);
Ordering.UTM.update(indexer);
checkIndexer(indexer, 2, 3, false);
Ordering.UTM.update(indexer);
checkIndexer(indexer, 3, 3, false);
}
@Test
public void testFULL() {
Assert.assertEquals(9, Ordering.FULL.nbElements(3));
final CovarianceIndexer indexer = new CovarianceIndexer(3);
checkIndexer(indexer, 0, 0, false);
Ordering.FULL.update(indexer);
checkIndexer(indexer, 0, 1, false);
Ordering.FULL.update(indexer);
checkIndexer(indexer, 0, 2, false);
Ordering.FULL.update(indexer);
checkIndexer(indexer, 1, 0, false);
Ordering.FULL.update(indexer);
checkIndexer(indexer, 1, 1, false);
Ordering.FULL.update(indexer);
checkIndexer(indexer, 1, 2, false);
Ordering.FULL.update(indexer);
checkIndexer(indexer, 2, 0, false);
Ordering.FULL.update(indexer);
checkIndexer(indexer, 2, 1, false);
Ordering.FULL.update(indexer);
checkIndexer(indexer, 2, 2, false);
}
@Test
public void testLTMWCC() {
Assert.assertEquals(9, Ordering.LTMWCC.nbElements(3));
final CovarianceIndexer indexer = new CovarianceIndexer(3);
checkIndexer(indexer, 0, 0, false);
Ordering.LTMWCC.update(indexer);
checkIndexer(indexer, 0, 1, true);
Ordering.LTMWCC.update(indexer);
checkIndexer(indexer, 0, 2, true);
Ordering.LTMWCC.update(indexer);
checkIndexer(indexer, 1, 0, false);
Ordering.LTMWCC.update(indexer);
checkIndexer(indexer, 1, 1, false);
Ordering.LTMWCC.update(indexer);
checkIndexer(indexer, 1, 2, true);
Ordering.LTMWCC.update(indexer);
checkIndexer(indexer, 2, 0, false);
Ordering.LTMWCC.update(indexer);
checkIndexer(indexer, 2, 1, false);
Ordering.LTMWCC.update(indexer);
checkIndexer(indexer, 2, 2, false);