This brief covers how each overflight is measured. For how those measurements become the per-home noise comparison on the sensitivity map, see the peak-dBA model methodology.
Aircraft Noise Tracker is an iOS application designed to produce community-grade acoustic measurements of aircraft overflights that are defensible, reproducible, and linked to specific flight operations. The core thesis is that aviation-noise regulation depends almost entirely on modeled, averaged Leq metrics (DNL, CNEL) that systematically undercount event exposure. The app addresses this by generating per-event, per-aircraft observational records correlated with ADS-B flight data.
The specific objectives are:
The app is written in Swift using the SwiftUI framework for iOS. It follows an ObservableObject architecture with six principal components that communicate through shared state:
| Component | File | Role |
|---|---|---|
AudioManager | ContentView.swift | Audio session, signal processing, A/C weighting, psychoacoustics |
AircraftService | AircraftService.swift | ADS-B polling, geometry computation, aircraft identification |
NoiseEventLogger | NoiseEventLogger.swift | Event correlation, persistence, CSV/JSON export, baseline statistics |
PsychoacousticAnalyzer | PsychoacousticAnalyzer.swift | FFT, 1/3-octave band decomposition, Zwicker loudness, sharpness |
SeatLogger | SeatLogger.swift | Subjective Effects Assessment Tool — annoyance taps and survey |
UploadService | UploadService.swift | Session and SEAT event upload to the truenoise.org backend |
AudioManager produces SPL readings every 2 s → AircraftService produces aircraft position fixes every 10 s → NoiseEventLogger correlates them and writes structured observations → UploadService posts data to the backend.
The app uses AVAudioEngine with a tap installed on the audio input node. The tap delivers 1024-frame PCM buffers continuously at the device's native sample rate (typically 44,100 Hz or 48,000 Hz). The signal is processed in real time, with peak values accumulated over 2-second windows before being recorded as a single SPL sample.
A-weighting is implemented as three cascaded biquad IIR filter sections, derived from the analog IEC 61672 prototype via bilinear transform. The poles correspond to the four standard A-weighting characteristic frequencies (f₁ = 20.6 Hz, f₂ = 107.7 Hz, f₃ = 737.9 Hz, f₄ = 12,194 Hz). The cascade is normalized so the gain at 1 kHz equals 0 dB — the digital equivalent of a hardware A-weighting network, computed sample-by-sample in the audio callback.
C-weighting uses the same architecture but with only two biquad sections (the f₁ and f₄ poles, omitting the mid-band section), giving the characteristic flat response with low- and high-frequency rolloff.
For each buffer, the RMS amplitude is computed across the frame:
The 2-second peak window captures the maximum instantaneous reading across all buffers within the window. This is conservative — it represents the highest sound level heard during the window rather than an energy average. The C–A delta (difference between C-weighted and A-weighted readings) is tracked simultaneously as a wind-contamination indicator.
Independently of the SPL chain, raw PCM samples accumulate in a 4096-sample buffer. When full, the buffer is dispatched to a background analysis queue running PsychoacousticAnalyzer:
The app is organized into four tabs plus settings:
The app applies a single SPL offset (dBA) to all readings, converting raw ADC-scaled dB to approximate absolute SPL. The offset is stored per microphone profile in UserDefaults and applied throughout the signal chain.
The offset is set by comparing the app reading against a known source (calibrated tone, reference meter, or known aircraft). The user enters the target SPL and the app computes the correction. An initial +96 dBA offset was established for the Pop lavalier microphone, derived from known-level test signals and validated against overflights.
Auto-calibration uses the iPhone's built-in microphone as a stable transfer reference to characterize an external microphone's offset relative to it. Phase 1 (90 s) captures the internal mic's LA50 in ambient conditions; Phase 2 (60 s, after switching to the external mic in the same acoustic environment) captures the external mic's LA50. The difference determines the offset correction. This procedure needs no calibration source; it assumes the internal mic's response is consistent across sessions, confirmed across multiple test sessions.
Three windshield types are supported — none, foam ball, and fur windscreen — each applying an additive correction to logged values, compensating for the acoustic insertion loss of the material. This is logged to every CSV row for traceability.
The C–A delta (dBC − dBA) is computed in real time alongside the A-weighted reading. High C–A values indicate disproportionate low-frequency energy — the acoustic signature of wind turbulence at the diaphragm rather than aircraft noise. The app flags observations as "possible" or "likely" wind-contaminated when dBA ≥ 55 and C–A ≥ 15 or ≥ 25 respectively. Flags are written to the CSV, but values are not auto-excluded; the observer makes the final call.
Aircraft altitude drives the slant-range geometry, so its vertical datum matters. As of 2026-10-20 the app resolves altitude to height above mean sea level: GNSS altitude from the position feed is corrected to MSL using the geoid offset the iPhone measures at the observer's location (removing a roughly 100 ft error near BWI), and where only barometric altitude is available it is corrected with the local air pressure (QNH) from Open-Meteo. A new Altitude Source field records the method per row — GNSS, Baro+QNH, Baro (uncorrected), or GNSS (no geoid corr.) when the device lacks a good altitude fix.
Every session is tagged with a measurement type from a five-category framework:
| Type | Description |
|---|---|
| Standardized Receptor | 1.5 m microphone height, ≥ 1 m from reflective surfaces |
| Community Receptor | Fixed residential location, labeled position |
| Façade Receptor | Within 1 m of building face |
| Field Receptor | Field setup with documented geometry |
| Hand-held | Free-hand measurement, highest uncertainty |
The type and a free-text position description are logged to every CSV row, allowing downstream analysis to group or weight observations by receptor methodology.
Multiple validation sessions against a calibrated AZ8930 Type 2 sound-level meter:
±1.76 dB SD, zero mean bias for departure overflights. Approach phase pending additional validation data. Honest uncertainty label: ±5 dB for all displayed estimates.
Observations are stored in two formats simultaneously:
aircraft_observations.json): structured array with the full field set, used for in-app display and reimport.aircraft_log_YYYY-MM-DD.csv): 41-column flat file, one row per observation, plus an appended summary-statistics section.The CSV includes: timestamp, observation type (entry/track), dBA level, all psychoacoustic metrics with plain-language health labels, complete aircraft geometry (callsign, ICAO24, type code, type name, registration, operator, flight phase, ground distance, slant range, altitude, bearing, elevation angle, speed, vertical rate), observer GPS coordinates, windshield configuration and correction, measurement type, position description, C–A delta, wind speed and direction, temperature, relative humidity, altitude source, and an exclusion flag.
A companion reference file (aircraft_noise_reference.txt) is generated alongside the CSV with column definitions, health-scale descriptions, and source citations — suitable for submission alongside data to regulators or researchers.
At near-field sites within about 1.5 mi of the airport, taxiing and parked aircraft are logged separately to aircraft_ground_log_YYYY-MM-DD.csv — one row per second while an airborne aircraft is being tracked, each carrying the measured dBA at that instant, so a ground-source peak (a taxiing jet) can be told apart from an overflight peak. It is isolated: it is not uploaded to truenoise.org, and it does not affect the on-screen aircraft list, SEAT prompts, the N65/N70/N80 counts, the charts, or the website data. At receptors farther from the field (such as the porch monitor) the file is normally not created. It is included in Export when present and removed by Clear Log along with the main log.
The user initiates upload from the app. UploadService packages the current day's CSV as a multipart/form-data POST to the truenoise.org API (/api/v1/upload-session), authenticated with an API key. Before upload, a preprocessing step:
Excluded=Yes.The backend responds with a summary: session ID, observation count inserted, N65/N70/N80 event counts, recovery-deficit count, and unique aircraft count. Failed uploads are queued locally and retried on the next attempt.
When a user completes a subjective-effects survey, SeatLogger passes the completed event to UploadService.uploadSeatEvent(), which POSTs a JSON payload to /api/v1/seat/assessment. The payload includes source identifier (ios_app), timestamp, annoyance level, callsign, observer GPS coordinates, and the three survey responses. Upload is fire-and-forget — a failure is logged but does not surface to the user, since the primary record is already in the local SEAT CSV.
/states/all bounding box around the observer, OAuth2 client-credentials auth, ~10–15 s poll, state vectors as positional metric arrays converted on device. Migrated from airplanes.live in August 2026 after that service closed its free API.| Metric | Standard | Status |
|---|---|---|
| A-weighted SPL | IEC 61672 | Implemented; validated |
| C-weighted SPL | IEC 61672 | Implemented |
| Zwicker Loudness | ISO 532-1 | Implemented (simplified) |
| Sharpness | DIN 45692 | Implemented |
| Psychoacoustic Annoyance | Zwicker & Fastl | Implemented |
| N65 / N70 / N80 event counts | FAA standard | Implemented |
| LA10 / LA50 / LA90 / LA95 baselines | UK standard | Implemented |
| LAeq approximation | IEC / ISO | Implemented |
| ADS-B flight correlation | — | Implemented |
| ISO 15666-aligned annoyance survey | Informative | Implemented |
| Absolute accuracy (validated) | — | ±1.76 dB SD (departure); ±5 dB stated |