JPL Ephemeris Library for Elixir
A comprehensive Elixir library for astronomical calculations using NASA JPL ephemeris data. This library provides high-precision celestial mechanics calculations with built-in caching, coordinate transformations, and time scale conversions.
Features
- Time Scale Conversions: UTC ↔ Julian Day, UTC → Terrestrial Time (TT), TT → Barycentric Dynamical Time (TDB)
- Coordinate Transformations: ICRF/J2000 ↔ Ecliptic, Cartesian ↔ Spherical, RA/Dec conversions
- High-Performance Caching: ETS-based caching with TTL, statistics tracking, and automatic garbage collection
- Precise Calculations: Leap second handling, obliquity corrections, unit conversions (AU ↔ km)
- Vector Mathematics: Comprehensive 3D vector operations for astronomical calculations
- Production Ready: Supervision tree, concurrent access, comprehensive error handling
Quick Start
# Convert current time to Julian Day
{:ok, jd} = JPLEphem.Time.utc_to_jd(DateTime.utc_now())
# Transform coordinates from ICRF to Ecliptic
{:ok, ecliptic_pos} = JPLEphem.Coord.icrf_to_ecliptic({1.0, 0.0, 0.0})
# Cache expensive calculations
key = {:mars, ~U[2025-08-24 12:00:00Z], []}
position = {{1.523, 0.321, -0.043}, {0.012, 0.009, -0.001}}
JPLEphem.Cache.put(key, position, 3600) # Cache for 1 hour
{:ok, cached_position} = JPLEphem.Cache.get(key)Installation
Add jpl_ephem to your list of dependencies in mix.exs:
def deps do
[
{:jpl_ephem, "~> 0.1.0"}
]
endThen run:
mix deps.getThe library automatically starts its supervision tree with your application.
Core Modules
Time Module (JPLEphem.Time)
Handles time scale conversions and Julian Day calculations with leap second support.
# UTC to Julian Day conversion
{:ok, jd} = JPLEphem.Time.utc_to_jd(~U[2025-01-01 12:00:00Z])
# => {:ok, 2460677.0}
# Julian Day to UTC conversion
{:ok, datetime} = JPLEphem.Time.jd_to_utc(2460677.0)
# => {:ok, ~U[2025-01-01 12:00:00.000Z]}
# UTC to Terrestrial Time (TT)
{:ok, tt_jd} = JPLEphem.Time.utc_to_tt(~U[2025-01-01 12:00:00Z])
# TT to Barycentric Dynamical Time (TDB)
{:ok, tdb_jd} = JPLEphem.Time.tt_to_tdb(2460677.0)
# Get leap seconds at a specific date
leap_secs = JPLEphem.Time.leap_seconds_at(~U[2025-01-01 12:00:00Z])
# => 37 # Current leap seconds as of 2017
Coordinate Module (JPLEphem.Coord)
Provides coordinate system transformations and vector mathematics.
# ICRF to Ecliptic coordinate transformation
{:ok, ecliptic} = JPLEphem.Coord.icrf_to_ecliptic({1.0, 0.0, 0.0})
# Ecliptic to ICRF (reverse transformation)
{:ok, icrf} = JPLEphem.Coord.ecliptic_to_icrf(ecliptic)
# Cartesian to Spherical conversion (physics convention)
{:ok, {r, theta, phi}} = JPLEphem.Coord.to_spherical({3.0, 4.0, 5.0})
# phi is polar angle from Z-axis, theta is azimuthal angle
# Spherical to Cartesian conversion
{:ok, cartesian} = JPLEphem.Coord.from_spherical(r, theta, phi)
# Right Ascension / Declination
{:ok, {ra, dec}} = JPLEphem.Coord.to_ra_dec({1.0, 0.0, 0.0})
{:ok, position} = JPLEphem.Coord.from_ra_dec({ra, dec}, 1.0)
# Unit conversions
position_km = JPLEphem.Coord.au_to_km({1.0, 0.5, 0.0}) # AU to kilometers
position_au = JPLEphem.Coord.km_to_au(position_km) # km to AU
# Vector operations
magnitude = JPLEphem.Coord.vector_magnitude({3.0, 4.0, 0.0}) # => 5.0
unit_vector = JPLEphem.Coord.normalize_vector({3.0, 4.0, 0.0})
dot = JPLEphem.Coord.dot_product({1,0,0}, {0,1,0}) # => 0.0
cross = JPLEphem.Coord.cross_product({1,0,0}, {0,1,0}) # => {0,0,1}
Cache Module (JPLEphem.Cache)
High-performance ETS-based caching with automatic TTL and garbage collection.
# Store ephemeris data with 1-hour TTL
key = {:mars, ~U[2025-08-24 12:00:00Z], [observer: :earth]}
position = {{1.523679, 0.321456, -0.043211}, {0.012345, 0.008765, -0.001234}}
JPLEphem.Cache.put(key, position, 3600)
# Retrieve cached data
case JPLEphem.Cache.get(key) do
{:ok, cached_position} -> IO.puts("Cache hit!")
:not_found -> IO.puts("Cache miss or expired")
end
# Cache statistics
stats = JPLEphem.Cache.stats()
# => %{size: 42, hits: 156, misses: 23, hit_rate: 0.871}
# Manual garbage collection
JPLEphem.Cache.gc()
# Configure cache
JPLEphem.Cache.set_ttl(7200) # Set default TTL to 2 hours
JPLEphem.Cache.set_max_size(50_000) # Set maximum cache size
# Clear all entries
JPLEphem.Cache.clear()Time Scales and Coordinate Systems
Time Scales
- UTC (Coordinated Universal Time): Standard civil time with leap seconds
- TT (Terrestrial Time): Uniform time scale for Earth-based observations
- TDB (Barycentric Dynamical Time): Time scale for solar system dynamics
- Julian Day (JD): Continuous count of days since noon UT on January 1, 4713 BCE
Coordinate Systems
- ICRF/J2000: International Celestial Reference Frame, standard for stellar positions
- Ecliptic: Coordinate system based on Earth's orbital plane
- Spherical: Physics convention (r, θ, φ) where φ is polar angle from Z-axis
- RA/Dec: Right Ascension and Declination for celestial navigation
Key Constants
- J2000.0 Obliquity: 23.43929111° (angle between equatorial and ecliptic planes)
- AU: 149,597,870.7 km (Astronomical Unit)
- Leap Seconds: Automatically handled for dates 1972-2017+
Error Handling
The library uses comprehensive error handling with descriptive error atoms:
case JPLEphem.Time.utc_to_jd(invalid_date) do
{:ok, jd} -> # Success
{:error, :time_out_of_range} -> # Date outside supported range
end
case JPLEphem.Coord.to_spherical({0.0, 0.0, 0.0}) do
{:ok, spherical} -> # Success
{:error, :zero_vector} -> # Cannot convert zero vector
end
case JPLEphem.Coord.normalize_vector({0.0, 0.0, 0.0}) do
{:ok, unit_vector} -> # Success
{:error, :zero_vector} -> # Cannot normalize zero vector
endPerformance and Caching
The library is designed for high-performance astronomical calculations:
- ETS Tables: Concurrent read/write access with minimal locking
- Automatic TTL: Configurable time-to-live with background garbage collection
- Statistics Tracking: Monitor cache hit rates and performance metrics
- Memory Efficient: Automatic cleanup of expired entries
- Production Ready: Supervised processes with graceful error handling
Cache Performance Tips
# Use structured keys for better organization
key = {body, datetime, options_list}
# Set appropriate TTL based on calculation precision needs
JPLEphem.Cache.put(key, result, 3600) # 1 hour for ephemeris data
JPLEphem.Cache.put(key, result, 86400) # 24 hours for less precise data
# Monitor cache performance
stats = JPLEphem.Cache.stats()
if stats.hit_rate < 0.8 do
IO.puts("Consider increasing TTL or cache size")
endDevelopment
Running Tests
# Run all tests
mix test
# Run tests with coverage
mix test --cover
# Run specific test modules
mix test test/jpl_ephem/time_test.exs
mix test test/jpl_ephem/coord_test.exs
mix test test/jpl_ephem/cache_test.exs
# Run tests in watch mode during development
mix test.watchCode Quality
# Format code
mix format
# Run static analysis
mix credo
# Type checking (if using Dialyzer)
mix dialyzer
# Generate documentation
mix docsProject Structure
jpl_ephem/
├── lib/
│ └── jpl_ephem/
│ ├── application.ex # Application supervisor
│ ├── time.ex # Time scale conversions
│ ├── coord.ex # Coordinate transformations
│ └── cache.ex # ETS-based caching
├── test/
│ ├── support/
│ │ ├── test_helpers.ex # Test utilities
│ │ └── test_data.ex # Reference data
│ └── jpl_ephem/
│ ├── time_test.exs # Time module tests
│ ├── coord_test.exs # Coordinate tests
│ └── cache_test.exs # Cache tests
├── docs/
│ ├── PRD.md # Product Requirements
│ ├── SPEC.md # Technical Specifications
│ ├── API_SPEC.md # API Documentation
│ └── TDD_PLAN.md # Test-Driven Development Plan
└── mix.exs # Project configurationTesting Philosophy
This library was developed using strict Test-Driven Development (TDD):
- Red: Write failing tests first
- Green: Implement minimal code to pass tests
- Refactor: Improve code while maintaining test coverage
- Commit: Regular commits at each TDD cycle
All modules have comprehensive test coverage with:
- Happy path testing
- Edge case validation
- Error condition handling
- Precision validation for numerical calculations
- Concurrent access testing
- Performance validation
Use Cases
Astronomical Software
- Planetarium applications
- Telescope pointing systems
- Satellite tracking
- Astronomical observation planning
Scientific Computing
- Orbital mechanics simulations
- Celestial navigation systems
- Space mission planning
- Educational astronomy tools
Web Applications
- Astronomical event calculators
- Sky viewing applications
- Solar system visualizations
- Ephemeris data APIs
API Reference
Complete API documentation is available at HexDocs.
For detailed technical specifications, see:
Contributing
We welcome contributions! Please see our contributing guidelines:
- Fork the repository
- Create a feature branch:
git checkout -b feature-name - Write tests for your changes (TDD approach)
- Implement the feature with tests passing
- Run the full test suite:
mix test - Commit your changes:
git commit -m 'Add feature' - Push to your branch:
git push origin feature-name - Submit a pull request
Code Standards
-
Follow Elixir formatting conventions (
mix format) - Maintain test coverage above 95%
- Add documentation for public functions
- Use descriptive commit messages
- Include tests for edge cases and error conditions
License
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
Acknowledgments
- NASA JPL for ephemeris data and algorithms
- International Astronomical Union (IAU) for coordinate system standards
- The Elixir community for excellent libraries and conventions
- Contributors and maintainers of this project
Changelog
See CHANGELOG.md for version history and release notes.
Made with ❤️ for the astronomical community