public double[] Interpolate(double jdtdb, EphemerisComponent target, EphemerisComponent center = EphemerisComponent.SolarSystemBarycenter) { if (jdtdb < StartEpoch || jdtdb > FinalEpoch) { throw new ArgumentOutOfRangeException(nameof(jdtdb), TimeOutOfRange); } var targetCoordinates = new double[6]; var centerCoordinates = new double[6]; // Nutation, Libration, Angular Velocity and TT-TDB. if (target == EphemerisComponent.EarthNutation || target == EphemerisComponent.MoonLibration || target == EphemerisComponent.MoonAngularVelocity || target == EphemerisComponent.TTMinusTDB) { return(InterpolateChebyshev(jdtdb, target)); } // Moon at Earth Geocenter. if (target == EphemerisComponent.Moon && center == EphemerisComponent.Earth) { targetCoordinates = InterpolateChebyshev(jdtdb, target); } // Earth at Moon Geocenter. else if (target == EphemerisComponent.Earth && center == EphemerisComponent.Moon) { targetCoordinates = InterpolateChebyshev(jdtdb, center); for (var axis = 0; axis < targetCoordinates.Length; axis++) { targetCoordinates[axis] = -targetCoordinates[axis]; } } // Anything that relates to either Earth or Moon. else if (target == EphemerisComponent.Earth || target == EphemerisComponent.Moon || center == EphemerisComponent.Earth || center == EphemerisComponent.Moon) { var emrat = 1.0 / (1.0 + constants["EMRAT"]); if (target == EphemerisComponent.Moon || center == EphemerisComponent.Moon) { emrat -= 1.0; } var embCoordinates = InterpolateChebyshev(jdtdb, EphemerisComponent.EarthMoonBarycenter); var moonCoordinates = InterpolateChebyshev(jdtdb, EphemerisComponent.Moon); // Earth/Moon at Planetocenter/SSB. if (target == EphemerisComponent.Earth || target == EphemerisComponent.Moon) { if (center != EphemerisComponent.SolarSystemBarycenter) { targetCoordinates = InterpolateChebyshev(jdtdb, center); } for (var axis = 0; axis < targetCoordinates.Length; axis++) { targetCoordinates[axis] = (embCoordinates[axis] - emrat * moonCoordinates[axis]) - targetCoordinates[axis]; } } // Planet/SSB at Earth/Moon Geocenter. else { if (target != EphemerisComponent.SolarSystemBarycenter) { targetCoordinates = InterpolateChebyshev(jdtdb, target); } for (var axis = 0; axis < targetCoordinates.Length; axis++) { targetCoordinates[axis] = targetCoordinates[axis] - (embCoordinates[axis] - emrat * moonCoordinates[axis]); } } } // Anything that relates to bodies other than Earth/Moon. else { if (target != EphemerisComponent.SolarSystemBarycenter) { targetCoordinates = InterpolateChebyshev(jdtdb, target); } if (center != EphemerisComponent.SolarSystemBarycenter) { centerCoordinates = InterpolateChebyshev(jdtdb, center); } for (var axis = 0; axis < targetCoordinates.Length; axis++) { targetCoordinates[axis] -= centerCoordinates[axis]; } } for (var axis = 0; axis < targetCoordinates.Length; axis++) { targetCoordinates[axis] /= constants["AU"]; } return(targetCoordinates); }
private double[] InterpolateChebyshev(double tdb, EphemerisComponent component) { if (!pointers.ContainsKey(component) || pointers[component].CoefficientSetCount == 0) { throw new ArgumentException(EphemerisComponentNotAvailable, nameof(component)); } var recordPointer = pointers[component]; var interval = (tdb - StartEpoch) / recordSpan; var segment = (int)Math.Floor(interval); // Use previous segment if time is final epoch. if (Math.Abs(tdb - FinalEpoch) < double.Epsilon) { segment--; } var subInterval = (interval - segment) * recordPointer.CoefficientSetCount; var subSegment = (int)Math.Floor(subInterval); var timeSegment = 2.0 * (subInterval - subSegment) - 1.0; // Load segment if not already loaded. if (isFirstReading || tdb < coefficients[0] || tdb >= coefficients[1]) { reader.BaseStream.Seek(dataOffset + segment * coefficients.Length * sizeof(double), SeekOrigin.Begin); for (var i = 0; i < coefficients.Length; i++) { coefficients[i] = reader.ReadDouble(); } isFirstReading = false; } // Default is set to cartesian axes count. var coordinateCount = 3; if (component == EphemerisComponent.EarthNutation) { coordinateCount = 2; } else if (component == EphemerisComponent.TTMinusTDB) { coordinateCount = 1; } var coordinates = new double[coordinateCount * 2]; for (var axis = 0; axis < coordinateCount; axis++) { var p0 = 1.0; var p1 = timeSegment; var p2 = 0.0; var v0 = 0.0; var v1 = 1.0; var v2 = 0.0; var offset = recordPointer.CoefficientCountPerSet * (coordinateCount * subSegment + axis) + recordPointer.Offset; coordinates[axis] = coefficients[offset]; for (var i = 1; i < recordPointer.CoefficientCountPerSet; i++) { coordinates[axis] += coefficients[offset + i] * p1; coordinates[axis + coordinateCount] += coefficients[offset + i] * v1; p2 = 2.0 * timeSegment * p1 - p0; v2 = 2.0 * timeSegment * v1 - v0 + 2 * p1; p0 = p1; p1 = p2; v0 = v1; v1 = v2; } coordinates[axis + coordinateCount] *= (2 * recordPointer.CoefficientSetCount) / recordSpan; } return(coordinates); }