How it's wired GanglioR
← the -Dex suite · synthetic corpus generator

🧬SynthGen

SynthGen builds a synthetic overnight corpus with known ground truth. One virtual subject, five nights, every device recording the same nights on the same floating wall-clock — a single master event timeline rendered into each node’s native file format, so every app loads it unchanged and the Integrator can fuse across them.

Subject
Subject A45M · BMI 31 · moderate OSA
Span
5 consecutive nightsone shared timeline each
Determinism
seeded mulberry32seed → byte-reproducible
Emits
every device format+ ground-truth JSON
01 — WHAT IT’S FOR

Known ground truth for every node

You cannot validate a detector against data whose truth you don’t know. SynthGen plants the events — apneas, desaturations, arousals, ectopic beats — then renders them into real file formats, so a node’s output can be scored against exactly what was planted.

🕒
One floating timeline, every device. Because all nodes are rendered from the same master timeline on the same floating tMs, two synthetic devices that “recorded” the same minute land on the same timestamp — so cross-node fusion in the Integrator is exercised on data engineered to align.
02 — THE WIRING

The file stack

SynthGen is pure, deterministic JS plus a thin UI. The single source of truth (SYNTH) is reused unchanged by the cohort sampler that generalizes one subject into thousands.

Engine
synth-gen.jsSYNTH engine
The deterministic generator: builds a night’s master event timeline and renders it into each device’s native format (OxyDex 1 Hz CSV, RR text, CGM CSV, Welltory HRV rows). Seeded mulberry32, no deps. Exposes window.SYNTH.
Render · UI
synth-gen.htmlThe tool
The browser UI over SYNTH — pick parameters, preview, generate and download the file-set. Inherits the dark suite chrome from ans-design.css.
App · glue
cohort-gen.jsCohort sampler
Generalizes the single subject into N physiologically-coherent patients — a seeded draw over age×sex×BMI×severity×event-mix×CPAP×glycemia×artifact×arc — by REUSING the SYNTH renderers unchanged.
Harness · gate
cohort-full.jsFULL lane
Adds the heavy waveform renderers (176 Hz PPG, int16 µV ECG) on one representative window per patient — the ≤500 certification lane where the real morphology pipelines actually run.
03 — HOW IT’S ACHIEVED

From config to a loadable corpus

Every output of a night descends from one event timeline, so the files are internally consistent by construction — a desaturation in the oximeter CSV is the same event as the autonomic surge in the RR text.

Define the night

A seeded config fixes the subject and the night’s severity, event mix, artifact and missingness. The same seed always produces the same night.

mulberry32(seed) → night cfg

Build the master timeline

One timeline of physiological events — apneas, desats, arousals, beat-to-beat RR — is generated on floating tMs. This is the single source of truth for every device.

SYNTH.buildRR / event timeline

Render per device

The timeline is rendered into each node’s native format: OxyDex 1 Hz CSV, PulseDex RR text, GlucoDex CGM CSV, HRVDex Welltory rows — and in the FULL lane, PPG + ECG waveforms.

SYNTH.render* (reused everywhere)

Emit ground truth

Alongside the device files, a ground_truth_nightN.json records what was actually planted — the answer key the test, cohort and regression gates score against.

→ uploads/synthetic/ground_truth_nightN.json
04 — ONE NIGHT, EVERY FORMAT

What a single timeline becomes

The same planted night, eight ways — each in the exact format the corresponding node ingests in production.

OxyDex — 1 Hz SpO₂/HR/motion CSV

The O2Ring-format overnight trace. Drives the real oxydex-dsp ODI-4 / T90 / hypoxic-burden detectors.

PulseDex — RR text

Beat-to-beat RR intervals from the master timeline — the genuine HRV input, identical beats the other nodes share.

GlucoDex — CGM CSV

A continuous glucose stream spanning all the subject’s nights, co-generated so glycemia and autonomic state are coherent.

HRVDex — Welltory summary rows

Pre-computed daily HRV summary rows, the format HRVDex ingests.

PpgDex — 176 Hz PPG (FULL lane)

An optical waveform on one representative window, so the real PPG beat detection + morphology run, not just intervals.

ECGDex — int16 µV ECG (FULL lane)

A raw µV ECG rendered from the same RR beats, so Pan–Tompkins and morphology execute on real samples.

ground_truth_nightN.json

The planted-event answer key — what every gate diffs the detectors against.

05 — LIMITATIONS & CONSIDERATIONS

Where synthetic stops

SynthGen is engineered to be useful, not to be reality. Its own perspective paper names exactly where the synthetic frontier lies.

Synthetic ≠ real physiologycaution

The corpus is coherent and deterministic, not drawn from real patients. Real-data validation needs user-supplied PSG (NSRR/PhysioNet under DUA) — the synthetic lane is the scalable pre-check.

FAST omits waveformsnote

The default 10k lane emits CSV + RR + CGM + HRV rows only. The 176 Hz PPG and int16 ECG live in the ≤500 FULL lane because the waveform pipelines are the runtime cost.

ECG µV is rendered in the harnesslimitation

The shipped ECGDSP couples its RR→PQRST renderer inside genSynthetic; rather than edit shipped DSP (which would trip the gates), cohort-full renders the µV waveform from the same master RR beats.

Deterministic by seedby design

seed = patient index → byte-reproducible. The same corpus regenerates identically on any machine, which is what makes it a stable answer key for the gates.