Portfolio implementation aligned with a Machine Learning Engineer — Physiological Signal Foundation Models role: self-supervised pretraining on PPG/BCG windows, signal-quality assessment, and a downstream vital (heart rate), with subject-independent evaluation.
Synthetic paired PPG+BCG is the default so the repo trains offline. Swap in public corpora through ppgfm.data.real when you have licensed files.
| Role requirement | Where it lives |
|---|---|
| Foundation / representation learning | Contrastive SimCLR on fused embeddings (ppgfm.models.ssl) |
| Signal processing + time-series | Bandpass, windowing, SQI, cardiac-band PSD (ppgfm.signal) |
| Computer vision + multimodal | Log-STFT CNN fused with 1D PPG and 1D BCG encoders |
| Quality assessment | Morphological/spectral SQI + linear probe (QualityHead) |
| Downstream health task | Heart-rate regression from the frozen SSL backbone |
| Robust pipelines | Subject-wise splits, config-driven train/eval, NPZ export |
PPG waveform ──► 1D Conv / Patch Transformer ─┐
BCG waveform ──► 1D Conv / Patch Transformer ─┼─► fuse ─► embedding
PPG STFT ──► 2D CNN (spectrogram) ─┘
├─► SimCLR projector (pretrain)
├─► quality classifier (poor / acceptable / good)
└─► HR regressor (bpm)
SSL views use gain, Gaussian noise, respiratory-like baseline wander, and random time crop-and-resize. Spectrograms are recomputed on each view so the vision branch sees the same augmentation.
Python 3.10+ recommended. CPU is enough for configs/demo.yaml (a few minutes). If pytest stalls on import, GPU driver init is usually the cause; the test config already forces CPU.
cd "C:\Users\Ebi-Mhdl\Desktop\PPG Machin Learning"
python -m pip install -e ".[dev]"
python scripts/demo.py --config configs/demo.yaml
python -m pytest -qscripts/demo.py generates a synthetic cohort, pretrains the backbone, linear-probes quality and HR, and writes:
outputs/demo/ssl_backbone.ptoutputs/demo/metrics.jsonoutputs/demo/example_windows.pngoutputs/demo/synthetic_windows.npz
On a CPU demo run: SSL loss 2.74 → 1.86; held-out quality accuracy ~0.96 / macro-F1 ~0.94; HR MAE ~6.4 bpm. These numbers are synthetic and subject-split; they are a pipeline check, not a clinical claim.
Longer training (still synthetic):
python scripts/train_ssl.py --config configs/default.yaml
python scripts/train_downstream.py --config configs/default.yaml --ckpt outputs/default/ssl_backbone.pt --task quality
python scripts/train_downstream.py --config configs/default.yaml --ckpt outputs/default/ssl_backbone.pt --task hrSet model.encoder_type: patch in a config to use a patch-time Transformer instead of the 1D CNN.
Windows from the same subject never cross train/val/test. Random window splits leak identity (pulse morphology, sensor coupling) and overstate foundation-model quality. tests/test_splits.py locks this in.
Why PPG and BCG together. PPG is an optical peripheral pulse; BCG is mechanical cardiac motion. They share a cardiac timeline but fail differently (motion vs contact vs perfusion). A foundation model that still works when one modality is noisy is the product story.
Why spectrograms. A log-STFT is a 2D image of the same physiology. The CNN branch is the computer-vision / multimodal bullet: time-frequency structure (HR harmonic, motion bands) that a 1D net can underuse.
Quality before vitals. Downstream HR/AF/sleep models must know when a window is unusable. SQI features (perfusion, relative cardiac power, template correlation) are the classical baseline; the SSL embedding is the learned replacement.
Foundation-model protocol. Unlabeled (or weakly labeled) pretrain → freeze encoder → linear probe. If the probe works, the embedding is the asset. Fine-tune only after the probe is honest.
What a hiring manager may ask next. Device shift, missing-modality tokens, longer context, masked modeling vs contrastive, leakage via overlapping windows, and how you would attach AF or BP heads without retraining the backbone.
ppgfm.data.real.records_from_arrays accepts already-windowed [N, T] PPG (and optional BCG) plus subject_id. Natural next corpora: PPG-DaLiA, PulseDB/MIMIC-PPG, BUT PPG (quality labels). Keep licenses and subject splits intact.
configs/ demo.yaml (fast) and default.yaml (larger)
src/ppgfm/ signal, data, models, training, eval
scripts/ demo.py, train_ssl.py, train_downstream.py
tests/ SQI sanity + subject-split leakage checks