EMD / HHT
Empirical Mode Decomposition and the Hilbert-Huang Transform.
EMD adaptively decomposes a signal into Intrinsic Mode Functions (IMFs) without any a-priori basis. Each IMF satisfies:
- The number of extrema and zero-crossings differ by at most one.
- The mean of the upper and lower envelopes is everywhere near zero.
The HHT applies the Hilbert transform to each IMF to produce a fully adaptive time-frequency representation free of cross-term artifacts.
Reference: Huang et al. (1998), Proc. R. Soc. London A, 454, 903–995.
Workflow
import dspkit as dsp
# 1. Decompose
imfs, residue = dsp.emd(x, max_imfs=8)
# 2. Hilbert-Huang Transform
envs, inst_freqs = dsp.hht(imfs, fs)
# 3. Marginal spectrum
freq_bins, marginal = dsp.hht_marginal_spectrum(envs, inst_freqs, fs, n_bins=512)
Reconstruction is exact: imfs.sum(axis=0) + residue == x (within floating-point tolerance).


dspkit.emd.emd(x, max_imfs=None, max_sifting=10, sd_threshold=0.2)
Empirical Mode Decomposition.
Iteratively extracts Intrinsic Mode Functions (IMFs) from x using the sifting process. Each IMF satisfies:
- The number of extrema and zero-crossings differ by at most one.
- The mean of the upper and lower envelopes is everywhere near zero.
IMFs are ordered from highest to lowest instantaneous frequency. Their sum plus the residue exactly reconstructs the original signal.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
x
|
(array_like, shape(N))
|
Input signal. Should be detrended beforehand if it has a strong polynomial trend (EMD handles mild trends via the residue). |
required |
max_imfs
|
int or None
|
Maximum number of IMFs to extract. |
None
|
max_sifting
|
int
|
Maximum sifting iterations per IMF (default 10). Higher values enforce stricter IMF symmetry at the cost of computation. |
10
|
sd_threshold
|
float
|
Sifting stops when the normalised squared difference between successive iterates falls below this threshold (default 0.2). |
0.2
|
Returns:
| Name | Type | Description |
|---|---|---|
imfs |
(ndarray, shape(n_imfs, N))
|
Extracted IMFs, ordered highest to lowest frequency. |
residue |
(ndarray, shape(N))
|
Monotone (or near-monotone) residue. Represents the overall trend. |
Notes
Reconstruction is exact: imfs.sum(axis=0) + residue ≈ x.
Source code in dspkit/emd.py
dspkit.emd.hht(imfs, fs)
Hilbert-Huang Transform: apply the Hilbert transform to each IMF.
Each IMF is a narrow-band AM-FM signal, so the Hilbert transform gives physically meaningful instantaneous amplitude and frequency.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
imfs
|
(array_like, shape(n_imfs, N))
|
IMFs returned by |
required |
fs
|
float
|
Sampling frequency [Hz]. |
required |
Returns:
| Name | Type | Description |
|---|---|---|
envelopes |
(ndarray, shape(n_imfs, N))
|
Instantaneous amplitude of each IMF. |
inst_freqs |
(ndarray, shape(n_imfs, N))
|
Instantaneous frequency of each IMF [Hz]. |
Source code in dspkit/emd.py
dspkit.emd.hht_marginal_spectrum(envelopes, inst_freqs, fs, n_bins=512)
Marginal Hilbert spectrum.
Accumulates instantaneous energy (amplitude²) at each instantaneous frequency across all IMFs and all time samples:
H(f) = (1/N) Σ_{imfs} Σ_{t: f_i(t)≈f} A²(t)
This is an adaptive analogue of the PSD — it does not assume stationarity and its frequency axis is not fixed by a window length.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
envelopes
|
(ndarray, shape(n_imfs, N))
|
Instantaneous amplitudes from |
required |
inst_freqs
|
(ndarray, shape(n_imfs, N))
|
Instantaneous frequencies from |
required |
fs
|
float
|
Sampling frequency [Hz]. Used to set the Nyquist limit. |
required |
n_bins
|
int
|
Number of frequency bins (default 512). |
512
|
Returns:
| Name | Type | Description |
|---|---|---|
freq_bins |
(ndarray, shape(n_bins))
|
Frequency axis [Hz], from 0 to fs / 2. |
spectrum |
(ndarray, shape(n_bins))
|
Marginal Hilbert spectrum [amplitude² per Hz equivalent]. |