PPG Models (v1.0)¶
PPG release artifacts and comparison lanes at 64 Hz. The published HuggingFace bundles are RVQ neural codecs; the local golden registry also includes SPIHT DSP and hybrid AI+DSP lanes for standardized comparison.
Per-experiment reproduction pages
Each entry below has a dedicated experiment page with the
one-command lifecycle (compressionkit golden run <id>), dataset details, and deploy
artifact layout: ppg-rvq-2x ·
ppg-rvq-4x ·
ppg-rvq-8x ·
ppg-rvq-16x ·
ppg-rvq-32x.
Two-stage variants: ppg-rvq-4x-prior ·
ppg-rvq-8x-prior.
Published RVQ results¶
The table below summarizes the published RVQ bundles. These are the v1 packages available through HuggingFace and the runtime loader.
| Model | Config | CR | PRD (%) | MSE | Cosine | HR MAE (bpm) | SDNN MAE (ms) |
|---|---|---|---|---|---|---|---|
ppg-rvq-02x |
ppg_rvq_64hz_02x_golden.yaml |
2.00x | 0.80 | 0.000063 | 0.99997 | 0.06 | 9.6 |
ppg-rvq-04x |
ppg_rvq_64hz_04x_golden.yaml |
4.00x | 1.29 | 0.000165 | 0.99992 | 0.05 | 12.9 |
ppg-rvq-08x |
ppg_rvq_64hz_08x_golden.yaml |
8.00x | 2.76 | 0.000756 | 0.99963 | 0.10 | 32.4 |
ppg-rvq-16x |
ppg_rvq_64hz_16x_golden.yaml |
16.00x | 5.90 | 0.003457 | 0.99831 | 0.19 | 58.2 |
ppg-rvq-32x |
ppg_rvq_64hz_32x_golden.yaml |
32.00x | 12.62 | 0.015843 | 0.99220 | 0.36 | 110.2 |
All metrics are on the validation set. HR/HRV metrics are from long-recording overlap-add evaluation (60 s windows, 50% hop).



Codec tradeoffs under noise and artifacts¶
PPG has three release-facing comparison lanes:
| Lane | Role | Current publication status |
|---|---|---|
| SPIHT | DSP faithfulness baseline; preserves clean/noisy inputs with minimal learned behavior | Registered and reproducible locally; not in v1 HuggingFace bundles |
| RVQ | Published neural codec bundles; compact learned representation with physiological scorecards | Published for 2x, 4x, 8x, 16x, and 32x |
| Hybrid | Learned denoising front end with a SPIHT backend; designed for wearable-noise regimes | Registered and reproducible locally; not in v1 HuggingFace bundles |
The robustness sweep scores each lane against a filtered clean-truth proxy after injecting empirical noise or additive artifacts. Lower PRD is better. This is a different question from faithful reconstruction of a clean validation frame: it asks which codec best preserves the recoverable pulse waveform when the input is already corrupted.
| Condition family | Current PPG crossover pattern |
|---|---|
| Clean input | SPIHT wins at 2x-8x, while RVQ wins at 16x-32x in the current robustness fixture. |
| Native / empirical SNR ladder | Hybrid wins most injected-noise cells from native through -12 dB. At 32x, RVQ remains strongest for native, 12 dB, and 8 dB before hybrid takes over at heavier noise. |
| Motion artifacts | RVQ is the current winner across the measured CR ladder. |
| Baseline wander | Hybrid is the current winner across the measured CR ladder. |


The practical read is that SPIHT is a strong low-noise baseline, RVQ is the published neural operating surface, and hybrid approaches become important when the input looks more like a wrist-worn signal with empirical noise or drift. See PPG CR vs fidelity and Validation Scorecard for the detailed scorecard definitions and noise-aware metrics.
Model Details¶
Architecture¶
All PPG models share the same architecture:
- Encoder: Strided Conv2D blocks (stride 2 per stage) with depthwise-separable convolutions, followed by a 1x1 projection to
embedding_dim=16 - RVQ bottleneck: EMA-updated codebooks with 256 entries, 8 bits/index
- Decoder: UpSampling2D + Conv2D mirror of the encoder
- Training: EMA decay 0.99, base filters 48, filter multiplier 1.25, 200 epochs
Compression Ratio Breakdown¶
| Model | Encoder Stages | Downsample | Latent Positions | RVQ Levels | Bits/Frame | CR |
|---|---|---|---|---|---|---|
| 02x | 1 | 2x | 160 | 2 | 2560 | 2.00x |
| 04x | 2 | 4x | 80 | 2 | 1280 | 4.00x |
| 08x | 3 | 8x | 40 | 2 | 640 | 8.00x |
| 16x | 4 | 16x | 20 | 2 | 320 | 16.00x |
| 32x | 4 | 16x | 20 | 1 | 160 | 32.00x |
Frame size = 320 samples (5 s at 64 Hz). Raw frame = 5120 bits (16-bit). Codebook size K = 256 (8 bits/index).

Loss Function¶
- Primary: MSE
- Auxiliary: Derivative loss (weight 0.1) — preserves waveform first-derivative (morphology)
HR/HRV Preservation¶
Long-recording evaluation uses overlap-add reconstruction on 60 s continuous segments, then computes physiological metrics with physioKit:



| Model | HR MAE (bpm) | HR Median AE | HR Bias | SDNN MAE (ms) | RMSSD MAE (ms) |
|---|---|---|---|---|---|
| 02x | 0.06 | 0.000 | +0.046 | 9.6 | 13.8 |
| 04x | 0.05 | 0.000 | +0.021 | 12.9 | 18.7 |
| 08x | 0.10 | 0.018 | +0.041 | 32.4 | 48.5 |
| 16x | 0.19 | 0.032 | +0.016 | 58.2 | 90.8 |
| 32x | 0.36 | 0.076 | +0.180 | 110.2 | 171.3 |
Dataset: Open unified PPG v1¶
The published v1 PPG goldens use ppg-unified-strict-sanitize-v1: a unified
mixture of BIDMC, BUT PPG, PPG-DaLiA, and WESAD. The release-facing PPG goldens
are MESA-free so users can reproduce the published artifacts without restricted
NSRR data.
MESA remains a supported restricted source for internal or custom experiments, but it is not used in the published v1 PPG goldens. See Dataset Setup for source-specific licensing and cache-building commands.
Build the cache¶
# Build the open sources used by the v1 PPG goldens.
uv run python scripts/build_ppg_cache.py \
--sources bidmc butppg ppg_dalia wesad
Training¶
# Reproduce a specific published operating point.
uv run compressionkit golden run ppg-rvq-8x
# Reproduce all PPG RVQ goldens.
uv run compressionkit golden run-all --modality ppg --method rvq
Output Structure¶
results/ppg_rvq_64hz_08x_golden/
├── best_model.weights.h5 # Best checkpoint
├── config.json # Frozen config
├── summary.json # Training metrics
├── long_recording_eval.json # HR/HRV preservation metrics
├── training_history_*.csv # Epoch-by-epoch metrics
├── tensorboard/ # TensorBoard logs
├── plots/ # Reconstruction plots
└── deploy/ # Deployment artifacts
├── encoder.tflite # INT8 quantized encoder
├── encoder.h # C header for encoder
├── encoder.keras # Keras encoder model
├── decoder.keras # Keras decoder model
├── decoder_float32.tflite # Float32 LiteRT decoder for host-side decode
├── decoder.tflite # Optional INT8 decoder for on-device decode
├── decoder.h # Optional C header for INT8 decoder
├── codebook.npz # RVQ codebook weights
├── codebook.h # C header for codebook
├── sample_data.npz # 50 validation samples
├── model_card.json # Metadata used for publishing
└── deploy_manifest.json # Artifact manifest
Deployment¶
For the full runtime guide, see Deployment Guide.
Runtime Profile¶
- Frame shape:
(1, 1, 320, 1)float32 - Sample rate:
64 Hz - Default HuggingFace repo pattern:
Ambiq/compressionkit-ppg-{cr}x-v1.0
Quickstart¶
import numpy as np
from compressionkit.runtime import RVQCodec
t = np.arange(320, dtype=np.float32) / 64.0
signal = (0.6 * np.sin(2.0 * np.pi * 1.2 * t) + 0.1 * np.sin(2.0 * np.pi * 2.4 * t)).reshape(1, 1, 320, 1)
codec = RVQCodec.from_pretrained("Ambiq/compressionkit-ppg-4x-v1.0")
indices = codec.encode(signal.astype(np.float32))
reconstruction = codec.decode(indices)
Deployment Notes¶
- Use
encoder.tflitepluscodebook.hfor the lowest-footprint embedded path. - Use
decoder_float32.tflitewhen reconstruction runs on a host or cloud service. - Add the two-stage prior only when bitrate is more constrained than compute or memory.
Extending¶
To create a new PPG model variant:
- Copy an existing golden config:
cp configs/ppg_rvq_64hz_08x_golden.yaml configs/ppg_rvq_64hz_08x_v2.yaml - Modify parameters (e.g.
base_filters,num_levels,learning_rate) - Train:
uv run train-ppg-rvq --config configs/ppg_rvq_64hz_08x_v2.yaml - Compare results against the golden baseline