<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Simulation on Sebastian Spicker</title>
    <link>https://sebastianspicker.github.io/tags/simulation/</link>
    <description>Recent content in Simulation on Sebastian Spicker</description>
    <image>
      <title>Sebastian Spicker</title>
      <url>https://sebastianspicker.github.io/og-image.png</url>
      <link>https://sebastianspicker.github.io/og-image.png</link>
    </image>
    <generator>Hugo -- 0.160.0</generator>
    <language>en</language>
    <lastBuildDate>Thu, 25 Dec 2025 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://sebastianspicker.github.io/tags/simulation/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>A Christmas Star (Minus the Star, Plus a Moon Nobody Asked For)</title>
      <link>https://sebastianspicker.github.io/posts/the-gift-of-transits/</link>
      <pubDate>Thu, 25 Dec 2025 00:00:00 +0000</pubDate>
      <guid>https://sebastianspicker.github.io/posts/the-gift-of-transits/</guid>
      <description>A browser-based simulator for exoplanet transit photometry, binary eclipses, and exomoon scenarios — built with Kepler integrators, limb darkening, and N-body dynamics. I spent Christmas on this. You&amp;rsquo;re welcome, science.</description>
      <content:encoded><![CDATA[<h2 id="summary">Summary</h2>
<p>&lsquo;Tis the season to stare at light curves. While most people were unwrapping
presents on December 25th, I was staring at synthetic flux drop-offs and
debugging a limb-darkening model. The result is a browser-based simulator for
exoplanet transit photometry, including binary eclipses and exomoon scenarios.
It does not detect any real exomoons. It does, however, correctly model why
detecting them is comically hard.</p>
<p>Source: <a href="https://github.com/sebastianspicker/exoplanet-exomoon-simulation">sebastianspicker/exoplanet-exomoon-simulation</a></p>
<hr>
<h2 id="background">Background</h2>
<h3 id="the-gift-of-transits">The gift of transits</h3>
<p>When a planet crosses in front of its host star, the observed stellar flux
drops by a fraction proportional to the ratio of their projected areas:</p>
\[
  \delta = \left(\frac{R_p}{R_\star}\right)^2
\]<p>For Jupiter transiting the Sun, \( \delta \approx 1\% \). For Earth, about
84 ppm. For an exomoon orbiting a Jupiter-sized planet — well, unwrap that
calculation yourself:</p>
\[
  \delta_m = \left(\frac{R_m}{R_\star}\right)^2
\]<p>A Moon-sized exomoon around a Sun-like star contributes roughly 7 ppm of flux
variation. The <em>Kepler</em> space telescope&rsquo;s photometric precision was on the order
of 20–30 ppm per 6-hour cadence for bright targets. Ho ho hold on — that signal
is buried.</p>
<h3 id="why-stars-are-not-uniformly-bright-and-why-that-ruins-everything">Why stars are not uniformly bright (and why that ruins everything)</h3>
<p>A star is not a flat disk of uniform intensity. It is darker at the limb than
at the centre — an effect called limb darkening — because the line of sight
through the stellar atmosphere is shallower at the edges, sampling cooler,
less emissive layers. The quadratic limb-darkening law is:</p>
\[
  I(\mu) = I_0 \left[1 - u_1(1 - \mu) - u_2(1 - \mu)^2\right]
\]<p>where \( \mu = \cos\theta \) is the cosine of the angle from disk centre, and \( u_1, u_2 \)
are stellar-type-dependent coefficients. This matters for transit modelling
because the depth of the light curve dip changes as the planet traverses from
limb to centre to limb — the transit is not a flat-bottomed box, it is a
rounded trough. Fitting it incorrectly biases \( R_p / R_\star \) and, more
critically for exomoon searches, generates false residuals that look
suspiciously like a secondary dip.</p>
<h3 id="exomoon-detection-the-indirect-approach">Exomoon detection: the indirect approach</h3>
<p>No exomoon has been unambiguously confirmed as of the time of writing this post
(Christmas Day, 2025 — yes, really). The most promising indirect signatures are:</p>
<p><strong>Transit Timing Variations (TTV).</strong> The planet–moon system orbits their
common barycentre. This causes the planet&rsquo;s transit to arrive slightly early
or late relative to a pure Keplerian ephemeris. The timing offset scales as:</p>
\[
  \delta t \approx \frac{m_m}{m_p} \cdot \frac{a_m}{v_p}
\]<p>where \( m_m / m_p \) is the moon-to-planet mass ratio, \( a_m \) is the
moon&rsquo;s semi-major axis around the planet, and \( v_p \) is the planet&rsquo;s
orbital velocity. For an Earth-mass moon at 10 planetary radii around a
Jupiter-mass planet at 1 AU, this is on the order of minutes — measurable, in
principle, with long baselines.</p>
<p><strong>Transit Duration Variations (TDV).</strong> The same barycentre wobble modulates
the planet&rsquo;s velocity along the line of sight at transit ingress, changing
transit duration. TDV and TTV are 90° out of phase, which lets you solve for
both moon mass and orbital radius given enough transits.</p>
<p>Neither signal is clean in practice. Stellar activity, instrument systematics,
and other planets in the system all contribute correlated noise at similar
timescales. The residuals of the best exomoon candidate to date — Kepler-1625b-i
(Teachey &amp; Kipping, 2018) — remain contested. <em>Season&rsquo;s readings: disputed.</em></p>
<hr>
<h2 id="the-simulation">The Simulation</h2>
<h3 id="what-it-actually-does">What it actually does</h3>
<p>The simulator is a TypeScript application (Vite build, runs in-browser) built
around a deterministic, SI-unit physics core. The main pipeline:</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-fallback" data-lang="fallback"><span class="line"><span class="cl">UI parameters
</span></span><span class="line"><span class="cl">  → V4 normalisation
</span></span><span class="line"><span class="cl">  → runtime creation  (realtime | reference)
</span></span><span class="line"><span class="cl">  → orbital integrator (Kepler + N-body)
</span></span><span class="line"><span class="cl">  → geometry &amp; photometry
</span></span><span class="line"><span class="cl">  → flux decomposition
</span></span><span class="line"><span class="cl">  → canvas render + plots
</span></span></code></pre></div><p>Two runtime modes:</p>
<ul>
<li><strong>Realtime</strong> — fast integrator, interactive rendering, good for exploration</li>
<li><strong>Reference</strong> — high-fidelity integrator, deterministic export, good for
sanity-checking against known systems</li>
</ul>
<p>The photometry layer computes quadratic limb-darkened transit flux, handles
binary eclipse geometry (for eclipsing binary configurations), and exposes
hooks for phase curves and instrument noise.</p>
<p>The <strong>diagnostics layer</strong> is the part I find most useful: energy conservation
checks across the integration, radial velocity time series, astrometry, and
transit timing outputs. If your N-body integrator is drifting, the energy
plot tells you immediately.</p>
<p>The repo ships a <code>real-systems.snapshot.json</code> with versioned data from the
NASA Exoplanet Archive — so you can load, e.g., TRAPPIST-1 or HD 209458
as a starting configuration.</p>
<h3 id="what-it-deliberately-does-not-do">What it deliberately does not do</h3>
<p>The relativistic corrections are approximations. This is not a GR integrator.
For the systems it is designed for (short-period planets around Sun-like stars),
the relativistic perihelion precession is tiny — Mercury&rsquo;s 43 arcseconds per
century is the canonical example and that is already a demanding target — but
for millisecond pulsars or extremely compact binaries, do not trust it.</p>
<p>The atmospheric module exposes hooks but is not a radiative-transfer solver.
If you want realistic transmission spectra, point yourself at something like
petitRADTRANS and use this for the orbital geometry only.</p>
<hr>
<h2 id="discussion">Discussion</h2>
<p>The simulation is educational in intent — hence the built-in didactic mode
(black-box exploration → hypothesis → reveal → A/B comparison → rubric
scoring). But the physics is not dumbed down: the limb darkening is real, the
N-body integrator tracks multi-body gravitational interactions, and the TTV
outputs are computed from first principles rather than parameterised fits.</p>
<p>The thing I kept running into while building this is how much of exomoon
detection reduces to a residuals-hunting problem. You fit the best planet-only
model you can, examine the timing and duration residuals, and look for a
coherent signal. The simulator lets you inject a synthetic exomoon of specified
mass and orbital radius, generate synthetic light curves with configurable
noise, and see what the residuals look like — which is exactly the kind of
intuition-building exercise that is tedious to set up from scratch with, say,
a raw BATMAN lightcurve model and a custom integrator.</p>
<p><strong>Limitations worth being honest about.</strong> The performance budget is real:
some effects are profile-gated to keep the interactive mode responsive, which
means the reference mode exists specifically for cases where you want the full
physics at the cost of speed. For a publication-quality simulation you would
want a dedicated N-body code (REBOUND is the obvious choice), not a browser
runtime. This is a tool for understanding the problem, not for writing papers
about it — which, fitting for a Christmas project, is exactly what I have time
for right now.</p>
<hr>
<h2 id="references">References</h2>
<ul>
<li>
<p>Teachey, A. &amp; Kipping, D. M. (2018). <strong>Evidence for a large exomoon orbiting
Kepler-1625b.</strong> <em>Science Advances</em>, 4(10).
<a href="https://arxiv.org/abs/1810.02362">https://arxiv.org/abs/1810.02362</a></p>
</li>
<li>
<p>Kipping, D. M. (2009). <strong>Transit timing effects due to an exomoon.</strong>
<em>MNRAS</em>, 392(1), 181–189.
<a href="https://arxiv.org/abs/0810.2243">https://arxiv.org/abs/0810.2243</a></p>
</li>
<li>
<p>Mandel, K. &amp; Agol, E. (2002). <strong>Analytic light curves for planetary transit
searches.</strong> <em>ApJL</em>, 580, L171.
<a href="https://arxiv.org/abs/astro-ph/0210099">https://arxiv.org/abs/astro-ph/0210099</a></p>
</li>
<li>
<p>Claret, A. (2000). <strong>A new non-linear limb-darkening law for LTE stellar
atmosphere models.</strong> <em>A&amp;A</em>, 363, 1081–1190.</p>
</li>
</ul>
<hr>
<p><em>Merry Christmas. If you came here expecting warmth and cheer, I offer instead
a synthetic light curve with a 7 ppm exomoon signal buried in 30 ppm of
photon noise. Practically the same thing.</em></p>
<hr>
<p><em>For the physical version of this — a lamp, a ball, and a smartphone measuring
real transit light curves in a classroom — see
<a href="/posts/exoplanet-hunting-smartphones/">Hunting Exoplanets with Your Phone</a>.
For context on where those experiments came from, see
<a href="/posts/astro-lab-at-home/">The Lab Goes Home</a>.</em></p>
<hr>
<h2 id="changelog">Changelog</h2>
<ul>
<li><strong>2026-03-05</strong>: Corrected the description of the limb-darkening variable from &ldquo;$\mu = \cos\theta$ is the angle from disk centre&rdquo; to &ldquo;$\mu = \cos\theta$ is the cosine of the angle from disk centre.&rdquo; $\theta$ is the angle; $\mu$ is its cosine.</li>
<li><strong>2026-03-05</strong>: Corrected Claret (2000) page range from 1081–1090 to 1081–1190. The paper contains extensive tables of limb-darkening coefficients spanning 109 pages.</li>
</ul>
]]></content:encoded>
    </item>
  </channel>
</rss>
