Breathing Sonar (Remote)
Put the phone where ApneaApp put it — on the nightstand, a metre from a chest — and keep the laptop as the screen. The phone becomes the sonar: it emits the inaudible signal, records its own echoes, and runs the whole pipeline on board, streaming only the results here over WebRTC. The physics is explained on the single-device page; this one is the same code with the front end moved.
Pair your phone
Generating session…
On the phone, open sensingstudio.org/breathing-sonar-remote and enter this code. Both devices need to be online; the audio never leaves the phone.
Method
A single inaudible tone. The complex baseband echo is one vector; the room pins it in place and your chest rotates it. Most sensitive, but blind to distance.
Parameters · CW phase
Carrier frequency, 1–22 kHz. Higher → shorter wavelength → more phase per millimetre of chest movement (38°/mm at 18 kHz, 2°/mm at 1 kHz), but laptop tweeters and microphones both roll off hard above 20 kHz. If the echo looks dead in the signal panel, come down — and keep coming down. Below about 17 kHz you will hear it, which is unpleasant but diagnostic: an audible tone proves the speaker is actually emitting, and the 8–14 kHz region is where cheap hardware is happiest. Below ~2 kHz the wavelength is longer than a room feature and clutter cancellation has little left to separate.
Time constant of the running average that estimates the static part of the echo — walls, desk, the direct speaker-to-mic leak. Subtracting it re-centres the constellation on the origin so the breathing arc is what is left. Too short and it starts eating slow breaths.
Low-pass on the complex echo before the phase is taken. Breathing lives below 1 Hz, so heavy smoothing costs nothing and keeps the phase from random-walking when the echo is weak.
Run
Echo cancellation, noise suppression, and AGC are all switched off so the microphone reports the sonar honestly. Headphones will not work — the sound has to reach your chest through the air. Hold reasonably still: the same physics that sees a 1 mm breath sees a 1 cm fidget far more loudly. The Signal check panel below shows the raw microphone waveform and spectrum — start there if the results look like nonsense.
Why the phone does the maths
The obvious split — phone streams its microphone, laptop does the signal processing — cannot work here, and it is worth knowing why. A WebRTC audio track is Opus-coded and resampled through a jitter buffer. Opus is a perceptual codec: it preserves what you hear and discards phase relationships you do not, and the jitter buffer stretches and shrinks the stream by fractions of a sample to keep the clocks aligned. Both are harmless for speech and fatal here, because the entire measurement is the phase of an 18 kHz carrier, and 1 mm of chest movement is 38° of it.
So the phone keeps the samples. It plays the tone or the sweep, captures its own microphone at the native rate, and runs the identical sonar-core.js that the single-device page runs. What crosses the network is the finished picture: a few hundred numbers per packet — the motion trace, the breathing spectrum, the range profile, the envelope, and enough of the raw waveform and spectrum to fill the signal-check panel. About 40 kB/s, four packets a second.
The capture-rate readout in the signal panel is the phone's, not the laptop's: it counts the samples the phone's DSP actually consumed. If it sags below the sample rate, the phone is the bottleneck — close its other apps, or drop the chirps-per-frame.
The controls above are commands, not settings: change a parameter here and the phone re-initialises its DSP and answers with new packets. That is also why the layout is identical to the single-device page — both pages call the same drawing code over the same render buffers, so what you see here is what the phone computed, not an approximation of it.
Placing the phone
- Speaker and microphone both face the chest. Flat on a nightstand pointing up is worse than propped against something at torso height.
- Thirty to eighty centimetres. ApneaApp claims a metre; past that the echo is buried, and with a 512-sample sweep the far half of each chirp is wrapped anyway.
- Plug the phone in. Half an hour of continuous 19 kHz output and full-rate DSP is not a light load.
- Check the signal panel before trusting anything. Phone speakers vary enormously above 18 kHz; if the hump is missing from the received spectrum, drop the band.
- A phone screen that sleeps may throttle its audio thread. Keep the screen awake for a long run.
Sonar endpoint
Enter the code shown on the laptop to turn this phone into the sonar.