Audio Sample Rate
Short answer. Sample rate is the number of amplitude measurements per second, and it sets the highest frequency a recording can represent: half the sample rate, called the Nyquist limit. Speech is intelligible with energy up to about 4 kHz, which is why the telephone band is 8 kHz, but fricatives carry energy up to 8 to 10 kHz, which is why 16 kHz is the default for ASR training data. Downsampling without a low-pass filter first folds high frequencies back into the audible band as aliasing, and no later processing can undo it.
How to do it
The Nyquist rule, and where the speech band actually ends
A signal sampled at SR can represent frequencies from 0 to SR/2 and nothing above it. Content above SR/2 does not disappear when you record — it folds back down to SR minus its own frequency and lands in the audible band as a false component. A 6 kHz tone recorded at 8 kHz becomes a 2 kHz tone, indistinguishable from a real one.
Voiced sounds put most of their energy below 1 kHz, so a narrowband signal is still intelligible. Fricatives are the exception: /s/ and /ʃ/ have most of their energy above 4 kHz, and they are exactly the phones that distinguish "sip" from "ship" and that carry the plural and possessive endings in English. That is why 16 kHz is the working default for ASR and why a model trained on 8 kHz telephone audio loses accuracy on a 16 kHz test set even when nothing else changes.
The ladder, and what each step costs
Storage scales linearly with sample rate, so every step up the ladder is a straight multiplier on the size of the corpus. The rates below are the ones you will actually encounter in speech work.
- 8 kHz: the G.711 telephone standard. 32 kB/s at 16-bit mono, 115 MB per hour of the 8 kHz variant.
- 16 kHz: the ASR default and the rate of most public speech corpora. 115 MB per hour at 16-bit mono.
- 24 kHz: a common TTS output rate, and the rate the Opus codec uses for wideband speech.
- 48 kHz: Opus's internal rate, video production, and anything that will be re-processed or pitch-shifted. 345 MB per hour at 16-bit mono.
- 44.1 kHz: CD audio. For speech training data it buys nothing over 48 kHz and costs a resampling step.
Resample with a filter, never by slicing
Decimation by taking every Nth sample is the single most destructive shortcut in audio preprocessing, because the damage is irreversible and invisible. A 16 kHz recording containing a 6 kHz component, decimated to 8 kHz by slicing, now contains a 2 kHz component. A low-pass filter applied afterward passes that 2 kHz component through untouched, because as far as the filter is concerned it is genuine in-band content. There is no way to recover the original.
The correct order is filter then decimate: apply a low-pass at 0.45 times the target rate — 3.6 kHz for a target of 8 kHz — and then take every Nth sample. Use a library function that does both: librosa.resample, scipy.signal.resample_poly, or scipy.signal.decimate. Every one of them applies the anti-aliasing filter internally, which is the entire reason to use them instead of a slice.
Watch for double resampling in the pipeline
A common pipeline resamples on ingest to a canonical rate, then the feature extractor resamples again to its own expected rate, and the two rates differ. Each pass is a filter, and two cascaded filters with slightly different cutoffs remove more of the high band than either alone. The audible result is a dull recording; the measurable result is a few percent of WER on fricative-heavy test sets.
Pick one rate for the corpus, convert once at ingest, record the original rate in the metadata, and configure the feature extractor to expect that rate so it does not resample at all. The metadata matters for the same reason: if you later discover that the ingest step had a bug, you need to know what the original was.
Match the training rate to the deployment rate
If the product runs on 8 kHz telephone audio and the training data is 16 kHz, the model sees a bandwidth it will never see in production. Fine-tuning on a small amount of matched-rate data usually recovers more accuracy than any architectural change, and it is often the cheapest single improvement available in a speech pipeline.
The reverse also holds. Training on 8 kHz data and deploying on 48 kHz wideband audio wastes the extra bandwidth and gives up the fricative information the microphone is providing. Bandwidth is not a quality knob you can set independently of the model; it is part of the input distribution.
Code
A 6 kHz tone at 16 kHz, downsampled to 8 kHz twice — once by slicing, once after an anti-aliasing filter — and the aliased signal filtered afterward to show the damage is permanent.
import numpy as np
from scipy.signal import butter, sosfiltfilt
SR = 16000
TONE = 6000.0
t = np.arange(SR) / SR
x = np.sin(2 * np.pi * TONE * t)
def peak_freq(sig, sr):
spec = np.abs(np.fft.rfft(sig * np.hanning(len(sig))))
return float(np.fft.rfftfreq(len(sig), 1.0 / sr)[int(np.argmax(spec))])
def level_db(sig, ref):
return 20.0 * np.log10(np.max(np.abs(sig)) / np.max(np.abs(ref)) + 1e-12)
sos = butter(6, 0.45, btype='low', output='sos') # 0.45 x 8 kHz = 3.6 kHz cutoff
naive = x[::2] # decimate with no filter
correct = sosfiltfilt(sos, x)[::2] # filter first, then decimate
print('original %5d samples at %d Hz, strongest component %.0f Hz'
% (len(x), SR, peak_freq(x, SR)))
print('slice only %5d samples at 8000 Hz, strongest component %.0f Hz at %+.1f dB'
% (len(naive), peak_freq(naive, 8000), level_db(naive, x)))
print('filter + slice %5d samples at 8000 Hz, strongest component %.0f Hz at %+.1f dB'
% (len(correct), peak_freq(correct, 8000), level_db(correct, x)))
repaired = sosfiltfilt(sos, naive)
print('slice, then filter afterward: strongest component %.0f Hz at %+.1f dB'
% (peak_freq(repaired, 8000), level_db(repaired, x)))
print('the 2000 Hz component is now genuine in-band content and cannot be removed') - pip install numpy scipy. No audio files; the signal is a single tone.
- Expected output: the original peaks at 6000 Hz. The sliced version peaks at 2000 Hz at 0.0 dB — the alias is as loud as the original tone, because it is the original tone, just mislabeled by the lower sample rate.
- The filtered version peaks at 6000 Hz but at roughly -40 dB or lower, depending on the filter order. That residual is what an anti-aliasing filter leaves behind, and it is the reason to use a steep enough filter rather than a two-tap average.
- The last two lines are the point of the page: filtering after the fact leaves the 2000 Hz component at 0.0 dB. The information was destroyed at the moment of decimation.
Where this goes wrong
Decimating by slicing the array
Taking every Nth sample is not downsampling, it is aliasing with extra steps. Everything above the new Nyquist folds into the audible band at full amplitude and becomes indistinguishable from real content, so no filter, model, or post-processing step can remove it. This mistake is common because it sounds fine on speech that has little high-frequency energy, and shows up as unexplained accuracy loss on fricative-heavy test sets.
Resampling twice with different cutoffs
Ingest resamples to 16 kHz, the feature extractor resamples to 8 kHz for its filterbank, and the two filters cascade. Each pass removes high-band energy, and the second cutoff was never chosen with the first in mind. Configure the feature extractor to the corpus rate so the second pass is a no-op, and check the pipeline for hidden resampling inside libraries that accept a sample rate parameter.
Upsampling to a higher rate and calling it an upgrade
Interpolating 8 kHz audio to 16 kHz produces a 16 kHz file with no content above 4 kHz. It costs twice the storage, it does not restore any information, and it breaks any assumption that the sample rate tells you the bandwidth. If you must mix rates in one corpus, record the original rate in the metadata so the model can be told, or train with rate-agnostic features.
Assuming the corpus sample rate is the corpus bandwidth
Files labeled 16 kHz are routinely band-limited to 4 kHz or lower by an upstream codec, a low-quality microphone, or a resampling step that was applied before the file was saved. The sample rate records what the samples are spaced at, not what frequencies survived. Check the spectrum of a sample of files rather than trusting the header, especially in corpora assembled from multiple sources.
Publishing a WER number without the sample rate
The same model and the same utterances at 8 kHz and at 16 kHz differ by several WER points, mostly on fricatives. A benchmark result quoted without the sample rate and the bandwidth is not reproducible, and a vendor comparison across different rates is not a comparison. State the rate, and state whether the audio was genuinely wideband or upsampled.
When to buy the data instead of building the pipeline
Buy when you need the bandwidth your product actually uses, because no amount of processing adds frequencies that were never recorded. Buy when you need matched-rate data for a specific channel — 8 kHz telephone audio with the codec and the channel characteristics of real calls, not a downsampled studio recording — since the degradation is part of the distribution the model has to learn. Buy when the corpus has to be consistent, with one rate and one documented provenance, so the pipeline does not have to guess. If you are recording your own audio on equipment you control, record at 48 kHz and keep the original: downsampling is cheap and reversible in the sense that you can always go lower, while going higher later is impossible.
More technical reference
-
WAV vs MP3 for Training Data
wav vs mp3
-
Opus Audio Codec
opus audio codec
-
Beamforming Microphone Array
beamforming microphone array
-
Neural Speech Codec
neural speech codec
-
Word Error Rate (WER)
word error rate
-
Character Error Rate (CER)
character error rate
Need data for Audio Sample Rate?
Tell us the language, the hours, and what the data needs to look like. You will get a real number and a real timeline — not a range. If we cannot source it well, we will tell you that instead.
- Pilot batch before the full run, so problems surface early.
- Consent documentation delivered with the data.
- No medical or clinical data. No recorded telephone calls.