Hey @Rafa, hope you’re doing great!
Quick update on the PCK parser you kindly put together (sorry it took a while — my non-existent C skills slowed me down a bit when trying to build something to validate the PCK file
).
A couple of things:
- First off, the file looks like it’s actually a type 2 PCK — which was unexpected, but hey, it seems to work.
- I wrote a test for the type 2 format (pasted below), and everything mostly lines up — so great job there

The only thing that’s a bit off is the start and end addresses in the segment. I expected them to be 641 and 1,280,644 bytes (in bits in the test), but they’re different in the parsed result. I’m not sure if that’s a real issue or just me misunderstanding something. Any idea what might be going on?
Next, I’m planning to finish up the bit that extracts the frame orientation from the polynomials. I’ll keep you posted once that’s done.
Cheers,
Davide
package org.orekit.files.daf.pck;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.orekit.data.DataSource;
import org.orekit.files.daf.pck.PCKSegmentDataTypes.PCKSegmentDataType2;
import org.orekit.files.daf.spk.SPKChebyshev;
import org.orekit.files.daf.spk.SPKSegmentDataTypes.SPKSegmentDataChebyshevPositionSingleRecord;
import org.orekit.time.AbsoluteDate;
import org.orekit.time.TimeScale;
import org.orekit.time.TimeScalesFactory;
public class PCKEvaluationTest {
private final TimeScale tdb = TimeScalesFactory.getTDB();
private final AbsoluteDate j2000InTDB = new AbsoluteDate(2000, 1, 1, 12, 0, 0, tdb);
private final double tolerance = 1e-2;
@Test
public void testParsePCKType2() {
// Load and parse the binary PCK file
final String ex = "/daf/moon_pa_de440_200625.bpc";
final DataSource source = new DataSource(ex, () -> getClass().getResourceAsStream(ex));
final PCK parsedFile = new PCKParser().parse(source);
// Check that the comment section ends with a specific timestamp
System.out.println(parsedFile.getComments());
Assertions.assertTrue(parsedFile.getComments().endsWith("2650 JAN 25 00:00:00.000\n"));
final List<PCKSegment> segments = parsedFile.getSegments();
// Expect exactly two segments in the file
Assertions.assertEquals(2, segments.size());
final PCKSegment firstSegment = segments.get(0);
// Validate metadata from the first segment
Assertions.assertEquals("1549-12-20T23:59:27.815889091506362198 TAI",
firstSegment.getSegmentSummary().getInitialEpoch().toString());
Assertions.assertEquals("de440.nio", firstSegment.getSegmentName());
final PCKSegmentSummary firstSegmentSummary = firstSegment.getSegmentSummary();
Assertions.assertEquals(2, firstSegmentSummary.getPCKTypeCode());
Assertions.assertEquals("Chebyshev (angles only)", firstSegmentSummary.getPCKType());
Assertions.assertEquals(31008, firstSegmentSummary.getTargetNAIFCode());
Assertions.assertEquals(1, firstSegmentSummary.getFrameNAIFCode());
Assertions.assertEquals(641*8-7, firstSegmentSummary.getInitialArrayAddress());
Assertions.assertEquals(1280644*8+1, firstSegmentSummary.getFinalArrayAddress());
// Verify time range of the segment
final AbsoluteDate initialEpoch = firstSegmentSummary.getInitialEpoch();
final double initialEpochET = initialEpoch.durationFrom(j2000InTDB);
Assertions.assertEquals(-14200747200.0, initialEpochET, tolerance);
final AbsoluteDate finalEpoch = firstSegmentSummary.getFinalEpoch();
final double finalEpochET = finalEpoch.durationFrom(j2000InTDB);
Assertions.assertEquals(13447252800.0, finalEpochET, tolerance);
// Check number of data records
final ArrayList<SPKSegmentDataChebyshevPositionSingleRecord> dataRecords =
((PCKSegmentDataType2) firstSegment.getSegmentData()).getDataRecords();
Assertions.assertEquals(40000, dataRecords.size());
// Verify the final data record
final SPKSegmentDataChebyshevPositionSingleRecord lastRecord =
dataRecords.get(dataRecords.size() - 1);
final AbsoluteDate lastRecordFinalDate = lastRecord.getFinalDate();
final double lastRecordFinalDateET = lastRecordFinalDate.durationFrom(j2000InTDB);
Assertions.assertEquals(13447252800.0, lastRecordFinalDateET, tolerance);
// Validate Chebyshev polynomial metadata
SPKChebyshev lastRecordChebyshev = lastRecord.getPositionChebyshev();
assertEquals(13446561600.0, lastRecordChebyshev.getInitialDate().durationFrom(j2000InTDB),
tolerance, "Initial date mismatch");
assertEquals(13446907200.0, lastRecordChebyshev.getMidpoint().durationFrom(j2000InTDB),
tolerance, "Midpoint mismatch");
assertEquals(10, lastRecordChebyshev.getInterpolationPoints(), "Interpolation points mismatch");
assertEquals(345600.0, lastRecordChebyshev.getRadius(), tolerance, "Radius mismatch");
assertEquals(1.0, lastRecordChebyshev.getScaleFactor(), tolerance, "Scale factor mismatch");
// Check Chebyshev coefficients for RA
final double[] ChebCoeffRA = lastRecordChebyshev.getXCoeffs();
final double[] expectedChebichevCoeffRA = {
-2.44226466836715977e-02, 3.34128441574723452e-04,
9.63191168732138627e-05, -3.45913469999950336e-06,
-3.64485999790243449e-06, -6.01443784629434927e-07,
4.77195547433532325e-08, 1.12182197744218538e-08,
-1.38409453070187985e-10, -4.70879573201374059e-12
};
for (int i = 0; i < expectedChebichevCoeffRA.length; i++) {
Assertions.assertEquals(expectedChebichevCoeffRA[i], ChebCoeffRA[i], 1e-20);
}
// Check Chebyshev coefficients for DEC
final double[] ChebCoeffDEC = lastRecordChebyshev.getYCoeffs();
final double[] expectedChebichevCoeffDEC = {
4.33353953157573968e-01, 9.84902562548158972e-05,
-3.85336096648213384e-05, -9.18606199566445448e-06,
-8.81890561078146453e-07, 2.00790889517800090e-07,
4.17664889171795721e-08, -1.28238703118691811e-09,
-3.32830630006246497e-10, 1.05359126361415703e-11
};
for (int i = 0; i < expectedChebichevCoeffDEC.length; i++) {
Assertions.assertEquals(expectedChebichevCoeffDEC[i], ChebCoeffDEC[i], 1e-20);
}
// Check Chebyshev coefficients for W
final double[] ChebCoeffW = lastRecordChebyshev.getZCoeffs();
final double[] expectedChebichevCoeffW = {
3.83558564678053226e+04, 9.19663049848119196e-01,
-9.90929406934630184e-05, 1.40898711404538427e-06,
3.40895871148744643e-06, 5.58736091026859832e-07,
-4.29705937151806628e-08, -1.00535157712960103e-08,
1.47689031933346115e-10, 3.15332388392443341e-12
};
for (int i = 0; i < expectedChebichevCoeffW.length; i++) {
Assertions.assertEquals(expectedChebichevCoeffW[i], ChebCoeffW[i], 1e-20);
}
}
}