← All work

Sensing

SnoreLog

I wanted to know how badly I snore. A recorded night turns out to be full of other noise, and pulling the snoring back out of it was the whole problem.

Year
2026
Role
Solo — concept, audio pipeline, app
Status
In development
SnoreLog: a night summary scoring 67 with 2h 13m of snoring, beside a minute of audio where eleven snores are accepted on their 3.4-second rhythm and a door, television, cough and a partner turning over are rejected
A night, and one minute of it. The door is louder than every snore in that minute and is still rejected.

The problem

My wife told me I snore badly. I had gone my whole life assuming I did not, so I decided to settle it the only way I know how — record myself sleeping and look at the data.

SnoreLog records a full night and answers three questions: when did I snore, for how long, and how loudly. Recording was never the hard part. The hard part is deciding which sounds inside an eight-hour file are snoring at all — because a bedroom is never silent. There is an air conditioner, a fan, a road outside, a partner breathing.

The project became a study of that one question, and the answer I ended up with is not the one I set out to build.

How it changed

Each version below exists because the one before it was wrong about something specific.

  1. v1

    A loudness threshold and a state machine

    Why
    I needed to segment events out of a full-night recording on-device, without shipping a model to a phone.
    Change
    Sample amplitude every 200ms, run a four-state event lifecycle (idle → rising → sustained → cooldown), and group anything above a fixed dB threshold into a single snore event.
    Result
    In a quiet room it is genuinely good, and it costs almost nothing to run. But a threshold has no idea what a snore sounds like. Switch the fan on and the entire night fills with events. The number it reported was really a measure of how loud the room was.
  2. v2retired

    Train a classifier so it knows what a snore is

    Why
    If loudness cannot separate snoring from noise, the model has to learn the sound itself.
    Change
    I took a public snoring dataset from Kaggle, explored the waveforms, converted clips to mel spectrograms, augmented them, and trained a CNN to classify snore versus non-snore.
    Result
    The metrics were excellent — 99.3% on the held-out test set, one misclassification out of 150. On my own recordings it fell apart. The dataset is clean: clipped tight around the event, centred, recorded close. Mine is a phone on a nightstand in a room with its own noise floor. The model was not wrong about the data it was given; the data was wrong about my bedroom.
    Mel spectrograms of snoring and non-snoring audio side by side
    Snoring and not-snoring as the model saw them. Clean and separable here; much less so at 3am in a real bedroom.
    Exploratory plots of the Kaggle snoring dataset
    Exploring the public dataset before training.
    Training and validation accuracy and loss curves over 30 epochs
    Accuracy and loss over 30 epochs. Validation tracks training almost perfectly — which should have been the first clue about how easy this dataset is.
    Confusion matrix on the test set: 75 non-snoring correct, 74 of 75 snoring correct
    149 of 150 correct on the test set, and still wrong about my bedroom.
  3. v3

    Calibrate the room instead of the model

    Why
    Both earlier versions assumed that 'loud' means the same thing every night. It does not — it depends entirely on the room you are in tonight.
    Change
    Before sleeping, the user records about thirty seconds of the room. That becomes the night's baseline: its noise floor and spectral shape. Everything recorded afterwards is measured against that baseline rather than against a constant, so the steady hum of a fan is subtracted out instead of counted in.
    Result
    The detector now moves with the room. The same fan on two different nights produces two different baselines and the same correct answer. Thirty seconds of the user's attention did more than a model trained on someone else's bedroom.

What I actually learned

I went looking for a better classifier and the answer turned out to be a better reference point. Snoring is not an absolute sound — it is a departure from the room you are in. Once the baseline is per-night rather than per-app, a very cheap detector becomes accurate, and it stays accurate in rooms I have never tested.

The v2 experiment was not wasted. It is the reason I trust the v3 result: I know the failure was domain mismatch and not a threshold I had not tuned hard enough, because I had already tried the version that knows what a snore sounds like.

Built with

  • Flutter
  • Python
  • TensorFlow / Keras
  • Audio DSP

Deep dives

Individual pieces of this project, written up on their own.