Zero-Crossing Rate (ZCR)
01
Captures: noisiness & rough frequency content
zcr = librosa.feature.zero_crossing_rate(y)[0]
Definition
How often the signal changes sign — i.e. crosses zero — per frame.
ZCR = (1 / (N−1)) · Σ 𝟙[ sign(xₙ) ≠ sign(xₙ₋₁) ]
summed over n = 1 … N−1; 𝟙 is the indicator function
Intuition
Picture the waveform. Low-frequency sounds wander across zero slowly; high-frequency and noisy sounds cross constantly.
Low frequency High frequency / noise
~~~ ~~~ ~ ~ ~ ~ ~ ~ ~
~~~~~~ (many crossings)
(few crossings)
What it captures
- Noisiness and rough frequency content
- Voiced vs unvoiced speech — vowels (
aaa, ooo) have low ZCR; fricatives (sss, fff) have high ZCR
- White noise sits very high
When to use it
- Quick voiced/unvoiced gating in speech
- Separating percussion from harmonic instruments in music
- As a cheap noisiness signal alongside richer features
Limitation: extremely crude. Two signals with identical ZCR can have completely different spectra — it sees crossing count, not shape.
Captures: loudness / signal strength
rms = librosa.feature.rms(y=y)[0]
Definition
The root-mean-square amplitude of each frame — a robust measure of loudness.
RMS = √( (1 / N) · Σ xᵢ² )
Intuition
Big swings in the waveform mean high energy; a flat, small waveform means low energy. It measures strength, and nothing about frequency.
High RMS Low RMS
^^^^^^^^^^ -- -- --
When to use it
- Voice-activity detection: speech vs silence
- Beat tracking and dynamics analysis in music
- Event onset detection in environmental audio
Limitation: energy only. A loud dog bark and a loud car horn can have nearly identical RMS — it can't tell them apart.
Captures: peak loudness outline / transients
import numpy as np
def amplitude_envelope(y, frame_length=2048, hop_length=512):
return np.array([
np.max(np.abs(y[i:i + frame_length]))
for i in range(0, len(y), hop_length)
])
ae = amplitude_envelope(y) # librosa has no built-in for this
Definition
The maximum absolute amplitude within each frame — the outer "shape" traced over the waveform's peaks.
AEₜ = max |x(n)|
maximum taken over all samples n in frame t
Intuition
Where RMS averages energy across a frame, the amplitude envelope keeps only the loudest sample. That makes it trace the silhouette of the signal and react sharply to sudden attacks — a drum hit, a consonant burst, a door slam.
waveform ╱╲ ╱╲╲
envelope ───► ╱ ╲___╱ ╲___ (follows the peaks)
Amplitude Envelope vs RMS
Amplitude Envelope → peak per frame (spiky, reacts to onsets)
RMS Energy → energy per frame (smoother, more robust)
When to use it
- Onset and transient detection — sharp attacks stand out
- Segmenting music or audio into events / notes
- A quick loudness outline when you care about peaks more than average level
Limitation: a single loud sample sets the whole frame, so it is sensitive to outliers and noise spikes. For steady loudness, RMS is the more robust choice.