Timing Precision Full Pipeline: End-to-End Error Budget¶
Status: Technical specification Relates to: [[Timing Precision Budget]], [[TTV Sensitivity and N-Body Math]], [[Occultation Geometry and Chord Reconstruction]] Depends on: astropy >= 5.0, barycorrpy (optional cross-check) Last derived: 2026-03-21
1. The Full Pipeline Map¶
The complete signal chain from physical photon to science output, with every timing contribution:
Physical photon arrival at CCD/CMOS
โ
โโ[A] Exposure start/end (mechanical shutter or electronic rolling/global)
โ Offset: 0โ50 ms from command to actual integration start
โ Uncertainty: ยฑ5โ50 ms (random, OS-scheduler-dependent)
โ Type: Random (jitter from USB/driver latency)
โ
โโ[B] Camera driver timestamp (OS system clock at readout completion)
โ Offset: depends on whether driver stamps start or end of exposure
โ Uncertainty: ยฑ0 ms if camera hardware reports; ยฑ10โ50 ms if OS clock
โ Type: Quasi-random
โ
โโ[C] OS system clock accuracy (NTP or GPS-PPS disciplined)
โ NTP offset: 0 mean, ยฑ5โ50 ms (1ฯ) โ random
โ GPS-PPS offset: 0 mean, ยฑ0.001โ0.05 ms (1ฯ) โ random
โ Type: Random (zero-mean for NTP; near-zero for GPS-PPS)
โ
โโ[D] ASCOM Alpaca driver latency (REST API round-trip)
โ Offset: ~5โ20 ms (localhost); ~50โ200 ms (network)
โ Uncertainty: ยฑ5โ15 ms (random, from HTTP + OS scheduler)
โ Type: Random (jitter); small systematic bias possible
โ
โโ[E] FITS header write (DATE-OBS, DATE-BEG, DATE-END)
โ Offset: 0 if correctly written at exposure start
โ Uncertainty: 0 if format is unambiguous ISO 8601 UTC
โ Type: Systematic if wrong (e.g., DATE-OBS = end instead of start)
โ CRITICAL: ambiguity in whether DATE-OBS is start or end of exposure
โ
โโ[F] Upload to OpenAstro server
โ No timing contribution (timestamps already fixed in FITS header)
โ
โโ[G] Plate solve + WCS fit
โ No timing contribution (spatial calibration only)
โ
โโ[H] Time standard conversion: UTC โ TDB
โ Offset: +69.184 s (deterministic: TT-TAI = 32.184 s + 37 leap seconds)
โ Uncertainty: <1 ยตs (known to sub-microsecond from IERS bulletins)
โ Type: Systematic (known, must be applied)
โ
โโ[I] Barycentric correction: topocentric โ solar system barycentre
โ Offset: up to ยฑ8.3 minutes (light travel time projection)
โ Uncertainty: ~1 ms (from Earth ephemeris accuracy, DE440)
โ Type: Systematic (known, must be applied)
โ
โโ[J] Exposure mid-point calculation: T_mid = T_start + t_exp/2
โ Offset: t_exp/2 (deterministic)
โ Uncertainty: ฮด(t_exp)/2, typically <1 ms for cameras reporting ms precision
โ Type: Deterministic
โ
โโ[K] Light curve extraction (differential photometry)
โ No direct timing contribution (photometric noise affects fitted time)
โ
โโ[L] Transit model fit / occultation edge fit
โ Output: T_mid (transit) or T_D, T_R (occultation) with fitted uncertainty
โ The fitted uncertainty incorporates photometric noise, cadence, and
โ ingress/egress duration. This is the dominant uncertainty for transits.
โ
โโ[OUTPUT] T_mid in BJD_TDB with uncertainty ฯ_Tmid
Classification of contributions¶
| Step | Magnitude | Type | Reducible? |
|---|---|---|---|
| [A] Shutter/trigger latency | 5โ50 ms | Random | Yes: hardware trigger |
| [B] Driver timestamp | 0โ50 ms | Quasi-random | Yes: use camera-reported time |
| [C] OS clock (NTP) | 5โ50 ms | Random | Yes: GPS-PPS |
| [C] OS clock (GPS-PPS) | 0.001โ0.05 ms | Random | Near floor |
| [D] ASCOM Alpaca latency | 5โ20 ms | Random | Yes: local timestamp |
| [E] FITS header ambiguity | 0 or t_exp | Systematic if wrong | Yes: validate format |
| [H] UTC โ TDB | 69.184 s | Systematic (known) | Apply correction |
| [I] Barycentric correction | ยฑ8.3 min | Systematic (known) | Apply correction |
| [J] Exposure mid-point | t_exp/2 | Deterministic | Apply formula |
| [L] Model fit | 30โ120 s (transit) | Random | More data, better SNR |
| [L] Model fit | 2โ50 ms (occultation) | Random | Higher frame rate, better SNR |
2. Hardware Clock Sources โ Detailed Comparison¶
2.1 NTP (Network Time Protocol)¶
Achievable accuracy on consumer hardware:
| Condition | Offset from UTC (1ฯ) | Source |
|---|---|---|
| Windows PC, default W32Time service, Stratum 2 | ยฑ50โ200 ms | Microsoft documentation |
| Windows PC, Meinberg NTP client, Stratum 2 | ยฑ10โ50 ms | Meinberg NTP docs |
| Linux, chrony, Stratum 2 over broadband | ยฑ5โ30 ms | chrony documentation |
| Linux, chrony, Stratum 1 on same LAN | ยฑ1โ5 ms | Mills RFC 5905 |
| Any OS, WiFi connection | ยฑ20โ100 ms | Variable; WiFi adds 1โ50 ms jitter |
References: Mills, D.L. (1991), RFC 1305; updated RFC 5905 (NTPv4). Meinberg NTP documentation (meinbergglobal.com).
Sources of NTP degradation:
-
Asymmetric routing: NTP assumes symmetric network delay. If outbound latency differs from return latency (common on residential connections with asymmetric upload/download), the offset estimate is biased by half the asymmetry. A 20 ms asymmetry produces a 10 ms systematic bias.
-
OS scheduler jitter:
- Windows: The default system timer resolution is 15.625 ms (1/64 s). This means the OS can only service NTP interrupts with ~16 ms granularity. The
timeBeginPeriod(1)API call or high-resolution multimedia timer reduces this to ~1 ms, but many astronomy applications do not invoke it. The W32Time service is particularly poor โ it syncs infrequently and has no sub-second granularity. -
Linux: The kernel timer resolution is typically 1 ms (HZ=1000) or 4 ms (HZ=250). chrony achieves better performance than ntpd because it uses kernel timestamping and adaptive polling.
-
Network latency variation (jitter): On residential broadband, round-trip times fluctuate by 5โ50 ms due to buffer bloat, routing changes, and congestion. NTP filters this with the clock filter algorithm, but cannot eliminate it entirely.
-
Clock drift between polls: Between NTP synchronizations (typically every 64โ1024 s), the local quartz oscillator drifts at 10โ100 ppm. Over a 5-minute poll interval: 50 ppm ร 300 s = 15 ms maximum drift. chrony compensates with frequency tracking (it learns the oscillator drift rate), but the residual after correction is still ~1โ5 ms.
When is NTP sufficient?
The criterion: NTP is adequate when the science timing requirement is at least 5ร the NTP uncertainty. This provides a comfortable margin where the clock error is negligible in quadrature with other error sources.
| Science case | Required ฯ_t | NTP uncertainty (1ฯ) | Ratio | NTP sufficient? |
|---|---|---|---|---|
| TTV transit mid-times | 30 s | 50 ms | 600ร | Yes โ overwhelmingly |
| Variable star periods | 10 s | 50 ms | 200ร | Yes |
| GRB classification | 60 s | 50 ms | 1200ร | Yes |
| GRB afterglow light curve | 1 s | 50 ms | 20ร | Yes |
| Eclipsing binary O-C | 1โ60 s | 50 ms | 20โ1200ร | Yes |
| Microlensing caustic | 1 min | 50 ms | 1200ร | Yes |
| Stellar occultation (KBO) | 100 ms | 50 ms | 2ร | Marginal โ GPS-PPS recommended |
| Stellar occultation (main-belt) | 10โ30 ms | 50 ms | 0.2โ0.6ร | No โ GPS-PPS required |
| FRB optical counterpart | 1โ10 ms | 50 ms | 0.02โ0.2ร | No โ GPS-PPS mandatory |
Conclusion: NTP is sufficient for all OpenAstro science cases except stellar occultations of main-belt asteroids and FRB optical counterpart searches. For these, GPS-PPS is mandatory.
2.2 GPS with PPS (Pulse Per Second)¶
Achievable accuracy:
| Component | Accuracy |
|---|---|
| GPS PPS signal (1PPS output) | ยฑ50โ100 ns relative to UTC(USNO) |
| PPS signal to kernel (interrupt latency) | ยฑ1โ10 ยตs |
| chrony disciplined to PPS | ยฑ1โ50 ยตs system clock offset |
| gpsd parsing NMEA sentences | ยฑ1โ10 ms (for coarse time only; PPS provides fine correction) |
Hardware options:
| Module | Price (approx.) | Interface | PPS output | Notes |
|---|---|---|---|---|
| u-blox NEO-M8T | $40โ60 | UART/USB | Yes (dedicated pin) | Timing-grade module, raw measurements |
| u-blox NEO-M9N | $25โ40 | UART/USB | Yes | Multi-band, good for general use |
| u-blox ZED-F9T | $80โ120 | UART/USB | Yes (dual) | High-precision timing module |
| Adafruit Ultimate GPS (MTK3339) | $30 | UART | Yes | Budget option, adequate PPS |
| Raspberry Pi GPS HAT (various) | $30โ50 | GPIO | Yes (GPIO pin) | Plug-and-play with RPi |
Software stack: gpsd โ chrony โ OS clock
The PPS disciplining chain works as follows:
- gpsd receives two data streams from the GPS module:
- NMEA sentences (GGA, RMC) providing coarse time (accurate to ยฑ1โ10 ms) plus position
-
PPS pulse on a dedicated pin (accurate to ยฑ100 ns)
-
gpsd makes both available as NTP reference clocks:
- SHM(0): coarse NMEA time (refclock type 28 in ntpd, or
refclock SHM 0in chrony) -
SHM(1) or PPS: the PPS pulse (refclock type 22 in ntpd, or
refclock PPS /dev/pps0in chrony) -
chrony (preferred over ntpd) uses the PPS signal to discipline the system clock:
- The NMEA time resolves the integer-second ambiguity (PPS only provides the fractional-second edge)
- The PPS signal provides sub-microsecond fractional-second accuracy
-
chrony adjusts the system clock frequency to track the PPS, achieving ยฑ1โ50 ยตs steady-state offset
-
Configuration example (chrony.conf):
refclock SHM 0 offset 0.5 delay 0.2 refid NMEA noselect refclock PPS /dev/pps0 lock NMEA refid PPS prefer
The lock NMEA directive tells chrony to use the NMEA source only for second numbering, and the PPS for precise edge timing. The prefer directive gives PPS priority over any network NTP sources.
ASCOM Alpaca timing: camera driver vs OS clock
This is a critical distinction. When an ASCOM camera driver reports LastExposureStartTime (an ASCOM standard property), the timestamp may come from one of two sources:
-
Camera hardware clock: Some cameras (e.g., SBIG, QHY with GPS option, FLI) have onboard clocks or GPS receivers. The driver reports the hardware-measured start time. This is the most accurate option (ยฑ1 ms or better).
-
OS system clock at the moment the driver initiates the exposure: This is the common case for most consumer CMOS cameras (ZWO ASI, QHY without GPS, Atik, etc.). The driver reads
DateTime.UtcNow(or equivalent) when it sends the "start exposure" command to the camera. The actual integration start occurs some variable time later (USB transfer of command, camera firmware processing). This latency is typically 5โ50 ms and is not accounted for in the timestamp.
The ASCOM LastExposureStartTime property documentation states it returns "the actual exposure start in the FITS-standard CCYY-MM-DDThh:mm:ss[.sss...] format" โ but "actual" is ambiguous. Most drivers return the time the software command was issued.
For OpenAstro: The pipeline must record which timing source the camera driver uses. This should be stored in the FITS header as TIMESRC and in the observation metadata.
2.3 Dedicated GPS-PPS to FITS Header Solutions¶
For demanding timing applications (occultations, FRBs), hardware-level timestamping bypasses the OS clock entirely:
IOTA Video Time Inserter (VTI) / VideoTimerII: - Overlays GPS time (from an integrated GPS receiver) directly onto the analog or digital video stream as text characters - Each video frame carries its own GPS timestamp, visible in the image - Accuracy: ยฑ1 ms (limited by the VTI's internal processing, not the OS) - Used extensively by IOTA occultation observers - Limitation: designed for video cameras (analog or NTSC/PAL), not modern CMOS science cameras
Kiwi OSD (On-Screen Display): - Similar to VTI but with enhanced features for digital video - GPS-disciplined, ยฑ1 ms accuracy per frame - Works with video-rate cameras
For modern CMOS cameras without hardware trigger:
The shutter latency problem: When software commands a CMOS camera to start an exposure, the actual start of photon integration occurs ฮt after the command, where ฮt is: - USB command transfer time: 1โ5 ms - Camera firmware processing: 1โ10 ms - Total ฮt: 2โ15 ms, variable and uncalibrated
This ฮt varies from exposure to exposure because USB is not a real-time bus โ other USB traffic, OS scheduler interrupts, and hub contention all contribute jitter.
Mitigation strategies: 1. Camera-side timestamping: Some cameras (ZWO ASI with latest SDK) report the actual frame start time from an internal counter. Use this instead of the OS clock if available. 2. External hardware trigger: A GPS-PPS signal triggers the camera via an external trigger input (available on some scientific CMOS cameras). The exposure start is synchronized to the PPS edge, giving ยฑ1 ยตs accuracy. Requires cameras with an external trigger port (e.g., QHY cameras with GPS option, Andor, PCO). 3. Post-hoc calibration: Measure the systematic delay ฮt for a specific camera + computer combination using a pulsed LED with known timing, then apply the correction. The random jitter component (~5 ms) cannot be removed this way.
3. The ASCOM Alpaca Timing Uncertainty¶
3.1 The Exposure Initiation Sequence¶
When an OpenAstro client initiates an exposure via ASCOM Alpaca:
[1] Python client: t_command = time.time()
[2] Python client: POST http://localhost:11111/api/v1/camera/0/startexposure
Body: {"Duration": 30.0, "Light": true}
[3] HTTP transport (localhost): 0.5โ5 ms
[4] Alpaca server receives request: parses JSON, validates
[5] Alpaca server calls ASCOM driver: ICameraV3.StartExposure(30.0, true)
[6] ASCOM driver sends USB command to camera hardware
[7] Camera firmware processes command and begins photon integration
โ t_actual_start (unknown to software)
[8] Camera driver notes start time: t_driver = DateTime.UtcNow
โ This is what appears in LastExposureStartTime
The total latency from [1] to [7] is:
| Component | Typical latency | Variability |
|---|---|---|
| HTTP round-trip (localhost) | 1โ5 ms | ยฑ2 ms |
| Alpaca server processing | 1โ3 ms | ยฑ1 ms |
| ASCOM COM interop | 0.5โ2 ms | ยฑ1 ms |
| Driver โ USB โ camera | 2โ15 ms | ยฑ5 ms |
| Total | 5โ25 ms | ยฑ10 ms (1ฯ) |
If the software timestamps the exposure at step [1] (the POST request), then DATE-OBS is early by 5โ25 ms relative to the actual exposure start. If it timestamps at step [8] (the driver's reading), the offset is smaller (2โ15 ms from USB latency only) but still present.
3.2 Over a network (not localhost)¶
If the Alpaca device is on a different machine (e.g., a Raspberry Pi controlling the camera, with the scheduler on a separate PC):
| Component | Typical latency | Variability |
|---|---|---|
| HTTP round-trip (LAN) | 5โ50 ms | ยฑ10 ms |
| HTTP round-trip (WAN) | 50โ200 ms | ยฑ50 ms |
Recommendation: Always run the Alpaca server on the same machine as the camera driver. Never initiate exposures over WAN โ the client software must be local.
3.3 Impact on Transit Mid-Time¶
For a transit with: - Total duration: T_dur = 2 hours - Ingress/egress duration: ฯ_ing = 20 minutes - Exposure cadence: ฮt = 1 minute (60 s exposures) - Number of in-transit points: N_transit = 120 - Number of ingress/egress points: N_ing = 20 per limb
The transit mid-time uncertainty from the model fit is dominated by photometric noise, not timestamp noise. But we can derive the contribution of timestamp jitter to ฯ(T_mid):
Each timestamp has an independent random error of ฯ_ts = 10โ50 ms. The transit model fit uses all N points, and the mid-time is determined primarily by the ingress and egress shapes. The timestamp jitter propagates to the mid-time as:
$$\sigma_{T_\text{mid, timestamp}} \approx \frac{\sigma_\text{ts}}{\sqrt{N_\text{ing}}}$$
For ฯ_ts = 50 ms and N_ing = 20 points in each ingress:
$$\sigma_{T_\text{mid, timestamp}} \approx \frac{50\,\text{ms}}{\sqrt{20}} \approx 11\,\text{ms}$$
This 11 ms contribution is completely negligible compared to the photometric noise contribution of 30โ120 seconds (from [[Timing Precision Budget]] Section 3).
Quantitative conclusion: For transit timing (TTV science), ASCOM Alpaca timestamp jitter contributes ~11 ms to the fitted mid-time โ a factor of 3000ร below the photometric noise floor. It is irrelevant.
For occultation timing, the 10โ50 ms jitter from ASCOM Alpaca is significant and comparable to the science requirement. This is why occultation observers use hardware triggers or video time inserters rather than software-initiated exposures.
4. BJD_TDB Conversion โ The Dominant Systematic¶
4.1 The Two Components¶
Converting a topocentric UTC timestamp to Barycentric Julian Date in Barycentric Dynamical Time (BJD_TDB) involves two distinct corrections:
Component 1: UTC โ TDB (time standard conversion)
The chain of time standards:
UTC โ TAI โ TT โ TDB
- UTC โ TAI: add current leap seconds. As of 2026, TAI = UTC + 37 s.
- TAI โ TT (Terrestrial Time): TT = TAI + 32.184 s (fixed by definition).
- TT โ TDB (Barycentric Dynamical Time): TDB differs from TT by a small periodic term (amplitude ~1.7 ms, period 1 year) due to relativistic time dilation from Earth's orbital motion. For most purposes TDB โ TT to within 2 ms.
Total UTC โ TDB offset: 37 + 32.184 = 69.184 s (as of 2026). This is a known, deterministic correction โ not an uncertainty. It changes only when a new leap second is announced (last one was December 2016).
Uncertainty: < 1 ยตs. The UTC-TAI offset is defined by the IERS. The TT-TAI offset is exact by definition. The TDB-TT correction is computed to sub-microsecond accuracy from solar system ephemerides (JPL DE440).
Component 2: Barycentric correction (light travel time)
Light from a distant star arrives at the Earth at a time that depends on the Earth's position relative to the solar system barycentre (SSB). The correction is:
$$\Delta t_\text{bary} = -\frac{\vec{r}_\text{obs} \cdot \hat{n}}{c}$$
where $\vec{r}_\text{obs}$ is the vector from the SSB to the observer and $\hat{n}$ is the unit vector toward the target star.
- Maximum amplitude: The Earth-Sun distance is ~1 AU = 499 light-seconds. The projection $\vec{r}_\text{obs} \cdot \hat{n}$ has maximum magnitude ~499 s โ 8.3 minutes. The actual correction varies sinusoidally over the year as the Earth orbits.
- Uncertainty: ~1 ms, dominated by the observer's position accuracy (Earth ephemeris from DE440 is accurate to ~1 m, which is ~3 ns in light travel time; the dominant uncertainty is the observer's geodetic coordinates โ a 300 m error in position contributes ~1 ยตs).
4.2 Critical Error Mode 1: HJD vs BJD¶
- HJD (Heliocentric Julian Date): Corrects light travel time to the centre of the Sun.
- BJD (Barycentric Julian Date): Corrects light travel time to the solar system barycentre (SSB).
The SSB is offset from the Sun's centre by up to ~1.5 solar radii (~0.01 AU), primarily due to Jupiter's gravitational influence. This offset projects to a maximum timing difference of:
$$\Delta t_\text{HJD-BJD} \leq \frac{0.01\,\text{AU}}{c} \approx 5\,\text{s}$$
Typical values are 0โ4 seconds, varying with the relative geometry of Jupiter and the target.
Why this matters: A 4-second systematic error is detectable in TTV analysis (where TTV amplitudes are 1โ10 minutes and measurement precision is 30โ120 s). If one observer reports HJD and another reports BJD, the combined dataset will show a spurious ~4 s offset that could be misinterpreted as a TTV signal or corrupt a period determination.
OpenAstro policy: All times MUST be reported in BJD_TDB. HJD is never acceptable. The pipeline must validate this.
4.3 Critical Error Mode 2: JD_UTC vs JD_TDB¶
If a timestamp is recorded in UTC but stored or reported as if it were TDB (or vice versa) without applying the 69.184-second correction:
- The error is up to 69.184 seconds โ a fixed systematic.
- For TTV science with amplitudes of 1โ10 minutes, a 69 s error completely swamps the signal.
- For occultation work, 69 s ร 15 km/s = 1037 km position error โ rendering the chord useless.
- This error is insidious because it is constant: it does not produce scatter in the data, just a systematic offset. If all observations from one site have this error, the O-C diagram will show a constant offset that could be absorbed into the fitted ephemeris, corrupting the period.
OpenAstro policy: The observation metadata MUST explicitly state the time system (TIMESYS = 'UTC' in the FITS header for raw data, BJD_TDB for processed times). The pipeline must apply the UTC โ TDB conversion and log that it was applied.
4.4 Python Code: Correct UTC to BJD_TDB Conversion¶
The following code uses astropy.time and astropy.coordinates to correctly convert an observation timestamp to BJD_TDB. This is the reference implementation for the OpenAstro pipeline.
"""
Convert DATE-OBS (UTC) to BJD_TDB for a given observer location and target.
Requirements: astropy >= 5.0
Reference: Eastman, Siverd & Gaudi (2010), PASP 122, 935
This code computes:
BJD_TDB = JD_TDB(mid-exposure) + light_travel_time_to_barycentre
"""
from astropy.time import Time, TimeDelta
from astropy.coordinates import SkyCoord, EarthLocation
import astropy.units as u
def utc_to_bjd_tdb(
date_obs: str,
exptime: float,
ra_deg: float,
dec_deg: float,
lat_deg: float,
lon_deg: float,
elevation_m: float,
) -> tuple[float, float]:
"""
Convert a DATE-OBS (ISO 8601 UTC) to BJD_TDB at exposure mid-point.
Parameters
----------
date_obs : str
UTC timestamp of exposure start, ISO 8601 format.
Example: '2026-06-15T02:34:17.456'
exptime : float
Exposure duration in seconds.
ra_deg : float
Target Right Ascension in degrees (J2000 / ICRS).
dec_deg : float
Target Declination in degrees (J2000 / ICRS).
lat_deg : float
Observer geodetic latitude in degrees (north positive).
lon_deg : float
Observer geodetic longitude in degrees (east positive).
elevation_m : float
Observer elevation above WGS84 ellipsoid in metres.
Returns
-------
bjd_tdb : float
Barycentric Julian Date in TDB at exposure mid-point.
ltt_seconds : float
The applied light travel time correction in seconds
(for diagnostic logging).
"""
# Step 1: Parse the UTC timestamp of exposure start
t_start_utc = Time(date_obs, format='isot', scale='utc')
# Step 2: Compute exposure mid-point in UTC
dt_half = TimeDelta(exptime / 2.0, format='sec')
t_mid_utc = t_start_utc + dt_half
# Step 3: Convert UTC mid-point to TDB
# This applies the UTC โ TAI โ TT โ TDB chain automatically.
# astropy handles leap seconds internally from its built-in tables.
t_mid_tdb = t_mid_utc.tdb
# Step 4: Define observer location and target coordinates
observer = EarthLocation.from_geodetic(
lon=lon_deg * u.deg,
lat=lat_deg * u.deg,
height=elevation_m * u.m,
)
target = SkyCoord(ra=ra_deg * u.deg, dec=dec_deg * u.deg, frame='icrs')
# Step 5: Compute the light travel time from observer to SSB
# This is the barycentric correction: the time it takes light to
# travel from the solar system barycentre to the observer, projected
# along the direction to the target.
# kind='barycentric' gives BJD; kind='heliocentric' would give HJD.
ltt = t_mid_tdb.light_travel_time(
target,
kind='barycentric',
location=observer,
ephemeris='builtin', # uses JPL DE440 or DE432s
)
# Step 6: Apply the correction
# BJD_TDB = JD_TDB(mid-exposure) + light_travel_time
bjd_tdb = t_mid_tdb + ltt
return bjd_tdb.jd, ltt.to(u.s).value
# โโ Example usage โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
if __name__ == '__main__':
# Example: observing WASP-12 b transit from a site in Arizona
bjd, ltt = utc_to_bjd_tdb(
date_obs='2026-06-15T02:34:17.456',
exptime=60.0,
ra_deg=97.6364, # WASP-12, RA = 06h30m32.8s
dec_deg=29.6723, # WASP-12, Dec = +29d40m20s
lat_deg=32.2217, # Tucson, AZ
lon_deg=-110.9265,
elevation_m=728.0,
)
print(f"BJD_TDB = {bjd:.8f}")
print(f"Light travel time correction = {ltt:.3f} s")
print(f"Light travel time correction = {ltt / 60:.4f} min")
Validation: Cross-check the output against the Ohio State BJD calculator (https://astroutils.astronomy.osu.edu/time/utc2bjd.html) or the barycorrpy package. Agreement should be within 1 ms.
Important implementation notes:
-
The
ephemeris='builtin'parameter uses astropy's bundled JPL ephemeris (DE432s). For higher accuracy (<1 ms), download and use DE440:ephemeris='jpl'withastropy.coordinates.solar_system_ephemeris.set('de440'). -
astropy handles leap seconds automatically via its built-in IERS tables. Ensure the tables are up to date:
from astropy.utils.iers import IERS_Auto; IERS_Auto.open()or setastropy.utils.iers.conf.auto_download = True. -
The observer elevation matters: a 1 km elevation error changes the barycentric correction by ~3 ยตs. GPS-derived elevation (typically ยฑ10 m) is adequate.
-
The
light_travel_time()method returns a positive value when the barycentre is closer to the target than the observer (light arrives at the observer after the barycentre), and negative when the barycentre is farther.
5. Exposure Mid-Point¶
5.1 Standard Science Camera Exposures¶
For a CCD or CMOS camera taking a single exposure of duration $t_\text{exp}$:
$$T_\text{mid} = T_\text{start} + \frac{t_\text{exp}}{2}$$
where $T_\text{start}$ is the moment the detector begins integrating photons (not the moment the software command was sent).
The uncertainty in $T_\text{mid}$ from the exposure duration:
$$\sigma_{T_\text{mid}} = \frac{\sigma_{t_\text{exp}}}{2}$$
For cameras that report exposure duration to 1 ms precision: $\sigma_{T_\text{mid}} = 0.5$ ms โ negligible.
For cameras that report exposure duration to 1 s precision (rare, but some older CCDs): $\sigma_{T_\text{mid}} = 0.5$ s. This is significant for occultation work but still negligible for TTV.
5.2 Fast-Cadence Video for Occultations¶
For a video camera running at frame rate $f_r$ with frame interval $\Delta t_\text{frame} = 1/f_r$:
$$T_\text{mid,frame} = T_\text{frame_start} + \frac{\Delta t_\text{frame}}{2}$$
If the camera has a dead time $t_\text{dead}$ between frames (readout time):
$$T_\text{mid,frame} = T_\text{frame_start} + \frac{t_\text{exp}}{2}$$
where $t_\text{exp} = \Delta t_\text{frame} - t_\text{dead}$.
5.3 Edge Case: Partial-Frame Occultation Events¶
Consider an occultation where the star disappears at time $t_D$ during a single exposure that runs from $T_\text{start}$ to $T_\text{start} + t_\text{exp}$. The exposure captures flux from two intervals:
- Star visible: $T_\text{start}$ to $t_D$ โ duration $(t_D - T_\text{start})$, flux $F_\star + F_\text{sky}$
- Star occulted: $t_D$ to $T_\text{start} + t_\text{exp}$ โ duration $(T_\text{start} + t_\text{exp} - t_D)$, flux $F_\text{sky}$ only
The measured total flux in the aperture is:
$$F_\text{measured} = F_\star \cdot (t_D - T_\text{start}) + F_\text{sky} \cdot t_\text{exp}$$
The photon-weighted temporal mid-point (the effective time of the measurement for the stellar flux) is:
For the unocculted portion (where the star contributes flux):
$$T_\text{photon-weighted} = \frac{\int_{T_\text{start}}^{t_D} t \cdot F_\star \, dt}{\int_{T_\text{start}}^{t_D} F_\star \, dt} = \frac{T_\text{start} + t_D}{2}$$
This is simply the midpoint of the unocculted interval โ not the geometric midpoint of the full exposure.
The geometric midpoint of the full exposure is $T_\text{start} + t_\text{exp}/2$. The difference is:
$$\Delta T = \left(\frac{T_\text{start} + t_D}{2}\right) - \left(T_\text{start} + \frac{t_\text{exp}}{2}\right) = \frac{t_D - T_\text{start}}{2} - \frac{t_\text{exp}}{2} = -\frac{T_\text{start} + t_\text{exp} - t_D}{2}$$
If the disappearance occurs at the midpoint of the exposure ($t_D = T_\text{start} + t_\text{exp}/2$), then $\Delta T = -t_\text{exp}/4$. The photon-weighted midpoint is $t_\text{exp}/4$ before the geometric midpoint.
For occultation fitting: The correct approach is to fit a step-function model to the light curve, where each frame's expected flux is integrated over the exposure duration. This naturally handles the partial-frame case without needing to compute photon-weighted midpoints manually. The edge time $t_D$ is a free parameter in the fit. Software such as PyOTE and Occult4 implements this correctly.
For reappearance events: The same analysis applies with the unocculted portion being $[t_R, T_\text{start} + t_\text{exp}]$ instead of $[T_\text{start}, t_D]$.
6. Complete Error Budget Table¶
All values assume a typical OpenAstro amateur setup: 20โ30 cm telescope, CMOS camera (ZWO ASI or similar), ASCOM Alpaca control, Linux or Windows PC.
6.1 Transit Timing (TTV Science)¶
| Pipeline step | Typical offset | Uncertainty (1ฯ) | Systematic or random? | Mitigation |
|---|---|---|---|---|
| OS clock โ NTP (broadband) | 0 (mean) | 20 ms | Random | Use chrony on Ethernet |
| OS clock โ GPS-PPS | 0 (mean) | 0.01 ms | Random | Recommended for occultations only |
| ASCOM Alpaca shutter command latency | +10 ms (late) | ยฑ10 ms | Quasi-random | Use camera driver timestamp, not HTTP request time |
| Camera USB trigger jitter | +5 ms (late) | ยฑ5 ms | Random | Hardware trigger (not needed for TTV) |
| DATE-OBS format ambiguity | 0 if correct; up to t_exp if wrong | 0 if validated | Systematic if wrong | Pipeline validates DATE-OBS = exposure start |
| Exposure mid-point calculation | +t_exp/2 (deterministic) | <1 ms | Deterministic | Apply T_mid = T_start + t_exp/2 |
| UTC โ TDB offset | +69.184 s (deterministic) | <0.001 ms | Systematic (known) | Apply astropy conversion โ mandatory |
| HJD vs BJD confusion | 0 if BJD used; up to 4 s if HJD | 0 if correct | Systematic if wrong | Enforce BJD_TDB in all submissions |
| Barycentric light travel time | up to ยฑ499 s (deterministic) | ~1 ms | Systematic (known) | Apply with astropy.time.light_travel_time() |
| Clock drift during observation (NTP) | 0 (mean, if NTP active) | 5โ15 ms per 5-min poll | Random | Monitor with chronyc tracking |
| Photometric noise on T_mid | 0 (mean) | 30โ120 s | Random | Dominant term. More data, better SNR, deeper transits |
| Detrending systematics | 0 (mean) | 10โ60 s | Quasi-systematic | Careful baseline selection, GP detrending |
| Total random (NTP setup) | โ | ~30โ120 s | โ | Photometry-dominated; clock is negligible |
| Total random (GPS-PPS setup) | โ | ~30โ120 s | โ | Same: photometry-dominated |
Key insight for TTV: The hardware clock uncertainty (~20 ms with NTP) is 1500ร smaller than the photometric noise floor (~30 s). GPS-PPS provides no benefit for transit timing. Invest in aperture and comparison star selection, not clocks.
6.2 Occultation Timing (Main-Belt Asteroid, 25 fps Camera)¶
| Pipeline step | GPS-PPS uncertainty (1ฯ) | NTP-only uncertainty (1ฯ) | Systematic or random? | Mitigation |
|---|---|---|---|---|
| OS clock | 0.01 ms | 20โ50 ms | Random | GPS-PPS mandatory |
| Camera trigger jitter | 1 ms (hw trigger) or 10 ms (sw) | 10 ms | Random | Hardware trigger if available |
| Frame timing ($t_\text{exp}/2\sqrt{3}$ at 25 fps) | 11.5 ms | 11.5 ms | Random | Higher frame rate |
| DATE-OBS / frame timestamp | <1 ms (GPS-stamped video) | <1 ms (if camera reports correctly) | Systematic if wrong | Use VTI or validated driver |
| UTC โ TDB | <0.001 ms | <0.001 ms | Known | Apply correction |
| Barycentric correction | ~1 ms | ~1 ms | Known | Apply with astropy |
| Light curve edge fit | 2โ10 ms (SNR-dependent) | 2โ10 ms | Random | Brighter stars, larger aperture |
| Fresnel diffraction floor (main-belt) | ~14 ms (physical) | ~14 ms (physical) | Physical limit | Cannot reduce |
| Total (quadrature, GPS-PPS, hw trigger) | ~19 ms | โ | Mix | |
| Total (quadrature, GPS-PPS, sw trigger) | ~21 ms | โ | Mix | |
| Total (quadrature, NTP-only) | โ | ~35โ60 ms | Mix | Marginal for main-belt |
6.3 Occultation Timing (KBO/TNO, 8 fps Camera)¶
| Pipeline step | GPS-PPS uncertainty (1ฯ) | NTP-only uncertainty (1ฯ) |
|---|---|---|
| OS clock | 0.01 ms | 20โ50 ms |
| Camera trigger jitter | 1โ10 ms | 10 ms |
| Frame timing ($t_\text{exp}/2\sqrt{3}$ at 8 fps) | 36 ms | 36 ms |
| Light curve edge fit | 5โ20 ms | 5โ20 ms |
| Fresnel floor (KBO at 40 AU) | ~120 ms | ~120 ms |
| Total (quadrature) | ~127 ms | ~133 ms |
Key insight for KBO occultations: The Fresnel diffraction floor dominates. NTP is nearly as good as GPS-PPS for this case because the physical limit (~120 ms) dwarfs the clock uncertainty. GPS-PPS is still recommended for the absolute timing needed for orbit refinement.
7. Science Case Requirements vs Achieved Precision¶
Summary Table¶
| Science case | Required ฯ_t | Achieved with NTP | Achieved with GPS-PPS | NTP sufficient? | Notes |
|---|---|---|---|---|---|
| Stellar occultations (main-belt) | โค30 ms | 35โ60 ms | ~19 ms | No | GPS-PPS required; frame rate is the secondary bottleneck |
| Stellar occultations (KBO/TNO) | โค100 ms | ~133 ms | ~127 ms | Marginal | Fresnel floor dominates; GPS-PPS helps with absolute timing for orbit refinement |
| TTV transit mid-times | โค30 s | ~30โ120 s (photometry limited) | ~30โ120 s | Yes | Clock is negligible; invest in aperture and cadence |
| GRB optical follow-up (classification) | โค60 s | ~50 ms (clock) + response time | ~0.01 ms (clock) + response time | Yes | The bottleneck is slew/response time (~30โ120 s), not the clock |
| GRB afterglow light curve | โค1 s | ~50 ms | ~0.01 ms | Yes | NTP is 20ร better than requirement |
| Variable star period measurement | โค10 s | ~50 ms | ~0.01 ms | Yes | NTP is 200ร better than requirement |
| Eclipsing binary O-C | โค1โ10 s | ~50 ms | ~0.01 ms | Yes | NTP is adequate |
| FRB optical counterpart | โค1โ10 ms | 20โ50 ms | ~1 ms (with hw trigger) | No | GPS-PPS + hardware trigger + fast camera mandatory |
Detailed Assessment¶
Stellar occultations (main-belt): - Requirement: โค30 ms for sub-km chord precision at $v_s$ = 15 km/s (30 ms ร 15 km/s = 450 m) - NTP-only delivers 35โ60 ms โ 525โ900 m limb uncertainty โ insufficient for shape modelling - GPS-PPS delivers ~19 ms โ 285 m limb uncertainty โ meets requirement - Verdict: GPS-PPS required. NTP fails.
TTV transit mid-times: - Requirement: โค30 s for detecting TTV amplitudes of 1โ10 minutes - Both NTP and GPS-PPS deliver 30โ120 s, dominated entirely by photometric noise - The 20 ms NTP clock error is 0.07% of the 30 s requirement - Verdict: NTP is overwhelmingly sufficient. GPS-PPS provides zero benefit.
GRB optical follow-up: - Requirement: โค60 s for classification (report detection to GCN within minutes) - The bottleneck is never the clock โ it is the alert latency (GCN propagation: 1โ30 s), telescope slew time (30โ120 s), and first-image readout - Verdict: NTP is sufficient. The clock is irrelevant compared to mechanical response time.
FRB optical counterpart: - Requirement: โค1โ10 ms to match with radio trigger timestamp - NTP delivers 20โ50 ms โ timing mismatch too large for confident association - GPS-PPS with hardware trigger delivers ~1 ms โ sufficient for association - This is the most demanding timing case in the OpenAstro science portfolio - Verdict: GPS-PPS with hardware trigger and fast camera (โฅ100 fps) required.
8. Validation Recipe¶
8.1 End-to-End Pipeline Verification¶
Method: Observe a well-characterised eclipsing binary with a published mid-eclipse time in BJD_TDB, process through the full OpenAstro pipeline, and compare the output mid-eclipse time with the published value.
Recommended target: CM Draconis (CM Dra)
- Type: Detached eclipsing binary (dM4.5 + dM4.5)
- V magnitude: 12.9
- Period: 1.268389985 days (extremely well determined)
- Eclipse depth: ~0.45 mag (primary) and ~0.40 mag (secondary) โ deep, easy to detect
- Eclipse duration: ~53 minutes โ well-suited to amateur apertures with 1-min cadence
- Ingress/egress: ~4 minutes
- Published ephemeris: Deeg et al. (2008), A&A 480, 563, and updated by Latham et al.
- Mid-eclipse times have been measured to ยฑ3โ10 s precision by multiple professional and amateur groups
- The O-C diagram is well-characterized, with no significant TTVs larger than ~20 s
Why CM Dra: 1. Deep eclipses โ high SNR even with small apertures 2. Short period โ observable every 1.27 days, frequent opportunities 3. Well-published BJD_TDB ephemeris โ direct comparison possible 4. Extensively observed by ETD (Exoplanet Transit Database) and AAVSO โ independent cross-checks available 5. V = 12.9 โ reachable with 20 cm aperture at โค5 mmag precision with 60 s exposures
Alternative targets: - NSVS 01031772 (V = 11.6, P = 0.368 d, depth 0.6 mag) โ very deep, very short period - V1143 Cyg (V = 5.9, P = 7.64 d) โ bright, but long period limits observation opportunities
8.2 Procedure¶
-
Observe: Capture a full primary eclipse of CM Dra with โฅ1-min cadence, V or R filter, using the standard OpenAstro client and ASCOM Alpaca control.
-
Record metadata: Ensure FITS headers contain DATE-OBS (UTC), EXPTIME, TIMESYS='UTC', site coordinates.
-
Run pipeline: Process through the OpenAstro pipeline:
- Extract differential photometry (target minus comparison star)
- Convert timestamps to BJD_TDB using the code in Section 4.4
-
Fit a transit/eclipse model (Mandel & Agol 2002, or simple trapezoidal model) to determine the mid-eclipse time $T_\text{mid}$ and its uncertainty $\sigma_{T_\text{mid}}$
-
Compare with published ephemeris:
- Compute the predicted mid-eclipse time from the published ephemeris: $T_\text{predicted} = T_0 + N \times P$ where $N$ is the cycle number
-
Compute $\text{O-C} = T_\text{measured} - T_\text{predicted}$
-
Expected agreement:
- The O-C value should be consistent with zero (within the CM Dra's known O-C scatter of ~10โ20 s)
- Specifically: $|\text{O-C}| < 3\sigma_{T_\text{mid}}$ where $\sigma_{T_\text{mid}}$ is the pipeline's reported uncertainty
- For a 20 cm telescope with 1-min cadence and 5 mmag photometric precision: $\sigma_{T_\text{mid}} \approx 30$โ60 s
-
Therefore: the pipeline output should agree with the published value to within ~2 minutes at 3ฯ
-
Failure modes this test catches:
- UTC vs TDB confusion: would produce O-C โ ยฑ69 s (clearly detectable at 1โ2ฯ for a single eclipse, unambiguously detectable from 2+ eclipses)
- HJD vs BJD confusion: would produce O-C โ 0โ4 s (not detectable from a single eclipse at 30 s precision, but detectable from observations at different times of year when the HJD-BJD difference changes sign)
- DATE-OBS = exposure end instead of start: would produce O-C โ t_exp/2 = 30 s (detectable if t_exp is large)
- Barycentric correction not applied: would produce O-C up to ยฑ499 s (immediately obvious)
- Sign error in barycentric correction: would produce O-C up to ยฑ998 s (immediately obvious)
8.3 Ongoing Monitoring¶
Once validated, the pipeline should be periodically re-tested:
- Leap second updates: When a new leap second is announced, verify that the UTC-TAI offset in astropy is updated. Outdated leap second tables produce a 1 s systematic.
- IERS table freshness: astropy's Earth orientation parameters (for precise barycentric correction) need periodic updates. Set
astropy.utils.iers.conf.auto_download = Trueor manually update. - Cross-observer consistency: When multiple OpenAstro sites observe the same transit, their fitted mid-times should agree to within their individual uncertainties. A systematic offset between sites indicates a calibration problem at one site.
9. Summary of Recommendations for OpenAstro¶
For the MVP (Phase 1)¶
-
Require NTP synchronization at all sites. Validate that
TIMESYS = 'UTC'and that the NTP offset is < 1 s. Flag observations from unsynchronized clocks. -
Implement the BJD_TDB conversion (Section 4.4 code) in the server-side pipeline. Never store or analyse times in JD_UTC or HJD. The conversion must be applied server-side, not left to individual observers.
-
Record timing metadata in the observation record:
TIMESRC(NTP or GPS-PPS),NTPOFF(NTP offset at observation time),EXPTIME,DATE-OBS. -
Apply exposure mid-point correction automatically: $T_\text{mid} = T_\text{start} + t_\text{exp}/2$.
-
Validate with CM Dra or equivalent eclipsing binary before declaring the pipeline operational.
For Occultation Campaigns¶
-
Require GPS-PPS for main-belt asteroid occultation observers. Provide a recommended hardware list (Section 2.2) and setup guide.
-
Encourage 25+ fps frame rates with high-sensitivity CMOS cameras (IMX462, IMX585).
-
Support IOTA VTI timestamps as an alternative to OS-clock timestamps for video-rate observations.
For FRB Optical Counterpart Work¶
-
Require GPS-PPS + hardware trigger + โฅ100 fps camera. This is the only OpenAstro science case that demands sub-millisecond timing.
-
This capability is aspirational for the MVP โ it requires specialized hardware that most amateurs do not have. Defer to Phase 2 or later.
10. References¶
- Mills, D.L. (2010), RFC 5905 โ NTPv4 specification
- Eastman, Siverd & Gaudi (2010), PASP, 122, 935 โ "Achieving Better Than 1 Minute Accuracy in the Heliocentric and Barycentric Julian Dates" (essential reference for BJD_TDB conversion)
- Eastman, J. (2010), Ohio State BJD Calculator โ http://astroutils.astronomy.osu.edu/time/utc2bjd.html
- IOTA (2020), Video Timing Standards for Occultation Observers
- Herald et al. (2020), MNRAS, 499, 4570 โ timing methods for stellar occultations
- Deeg et al. (2008), A&A, 480, 563 โ CM Draconis eclipsing binary ephemeris
- Mandel & Agol (2002), ApJ, 580, L171 โ analytic transit light curve models
- Kipping, D.M. (2010), MNRAS, 408, 1758 โ binning and timing in transit photometry
- Wright & Eastman (2014), PASP, 126, 838 โ barycentric corrections at 1 cm/s level
- ASCOM Standards Committee, ASCOM Alpaca API Reference โ https://ascom-standards.org/api/
- chrony documentation โ https://chrony-project.org/documentation.html
- Meinberg NTP documentation โ https://www.meinbergglobal.com/english/info/ntp.htm