Empirical Mode Decomposition (EMD) and Ensemble Empirical Mode Decomposition (EEMD)

Empirical Mode Decomposition (EMD) and Ensemble Empirical Mode Decomposition (EEMD)#

EMD (Empirical Mode Decomposition) is an adaptive time-space analysis method suitable for processing series that are non-stationary and non-linear. EMD performs operations that partition a series into ‘modes’ (IMFs; Intrinsic Mode Functions) without leaving the time domain. It can be compared to other time-space analysis methods like Fourier Transforms and wavelet decomposition. Like these methods, EMD is not based on physics. However, the modes may provide insight into various signals contained within the data. In particular, the method is useful for analyzing natural signals, which are most often non-linear and non-stationary. Some common examples would include the Southern Oscillation Index (SOI), Niño 3.4 Index, etc.

EEMD (Ensemble EMD) is a noise assisted data analysis method. EEMD consists of “sifting” an ensemble of white noise-added signal. EEMD can separate scales naturally without any a priori subjective criterion selection as in the intermittence test for the original EMD algorithm.

Wu and Huang (2009) state: “White noise is necessary to force the ensemble to exhaust all possible solutions in the sifting process, thus making the different scale signals to collate in the proper intrinsic mode functions (IMF) dictated by the dyadic filter banks. As the EMD is a time space analysis method, the white noise is averaged out with sufficient number of trials; the only persistent part that survives the averaging process is the signal, which is then treated as the true and more physical meaningful answer.” Further, they state: “EEMD represents a substantial improvement over the original EMD and is a truly noise assisted data analysis (NADA) method.”

See also

Before proceeding with all the steps, first import some necessary libraries and packages

import xarray as xr
import matplotlib.pyplot as plt
import easyclimate as ecl

Load and inspect Niño 3 SST anomaly data The dataset contains monthly sea surface temperature anomalies in the Niño 3 region, a key indicator for ENSO monitoring and analysis

data = xr.open_dataset("test_input_nino3_wavelet.nc")["nino3"]
data
<xarray.DataArray 'nino3' (time: 504)> Size: 4kB
[504 values with dtype=float64]
Coordinates:
  * time     (time) datetime64[ns] 4kB 1871-01-31 1871-04-30 ... 1996-10-31


Perform Empirical Mode Decomposition (EMD) on the time series EMD decomposes the nonlinear, non-stationary signal into intrinsic mode functions (IMFs) representing oscillatory modes embedded in the data at different timescales The time_step=”M” parameter indicates monthly resolution of the input data

<xarray.Dataset> Size: 36kB
Dimensions:  (time: 504)
Coordinates:
  * time     (time) datetime64[ns] 4kB 1871-01-31 1871-04-30 ... 1996-10-31
Data variables:
    input    (time) float64 4kB -0.15 -0.3 -0.14 -0.41 ... -0.08 -0.18 -0.06
    imf0     (time) float64 4kB 0.0756 -0.09539 0.0829 ... -0.169 -0.03726
    imf1     (time) float64 4kB 0.1577 0.1695 0.1588 ... 0.009739 0.1157 0.09504
    imf2     (time) float64 4kB 0.4274 0.4314 0.4123 ... -0.5048 -0.5273 -0.514
    imf3     (time) float64 4kB -0.4811 -0.4838 -0.4807 ... 0.1399 0.1341 0.1286
    imf4     (time) float64 4kB -0.152 -0.1461 -0.1396 ... -0.08033 -0.07906
    imf5     (time) float64 4kB -0.1279 -0.1265 -0.125 ... 0.1428 0.1425 0.1421
    imf6     (time) float64 4kB -0.04962 -0.04913 -0.04864 ... 0.2044 0.2046


Perform Ensemble Empirical Mode Decomposition (EEMD) on the time series EEMD improves upon EMD by adding white noise ensembles to overcome mode mixing The method performs multiple EMD trials (default=100) with different noise realizations and averages the results to obtain more stable IMF components

<xarray.Dataset> Size: 40kB
Dimensions:  (time: 504)
Coordinates:
  * time     (time) datetime64[ns] 4kB 1871-01-31 1871-04-30 ... 1996-10-31
Data variables:
    input    (time) float64 4kB -0.15 -0.3 -0.14 -0.41 ... -0.08 -0.18 -0.06
    eimf0    (time) float64 4kB 0.05829 -0.08755 0.09716 ... -0.06855 0.04122
    eimf1    (time) float64 4kB 0.1072 0.102 0.08247 ... -0.06476 -0.07157
    eimf2    (time) float64 4kB 0.345 0.3404 0.3095 ... -0.2401 -0.2458 -0.2311
    eimf3    (time) float64 4kB -0.3854 -0.3892 -0.3943 ... -0.1382 -0.1406
    eimf4    (time) float64 4kB -0.1862 -0.1844 -0.1818 ... -0.03224 -0.0304
    eimf5    (time) float64 4kB -0.06284 -0.0619 -0.0609 ... 0.2048 0.203 0.2011
    eimf6    (time) float64 4kB -0.00776 -0.007561 -0.007364 ... 0.1275 0.1275
    eimf7    (time) float64 4kB -0.05633 -0.05631 -0.05628 ... 0.04835 0.04849


Visualize the first three IMF components from standard EMD IMFs are ordered from highest frequency (IMF0) to lowest frequency (IMF2) Each IMF must satisfy two conditions:

  • Number of extrema and zero crossings differs by at most one

  • Mean of upper and lower envelopes is zero at any point

fig, ax = plt.subplots(4, 1, figsize = (8, 8), sharex=True)
fig.subplots_adjust(hspace=0.2)

axi = ax[0]
imf_result["input"].plot(ax = axi, color = "r")
axi.set_xlabel("")
axi.set_ylabel("Input")
axi.set_title("Input Signal: Niño 3")

axi = ax[1]
imf_result["imf0"].plot(ax = axi)
axi.set_xlabel("")
axi.set_ylabel("IMF 0")

axi = ax[2]
imf_result["imf1"].plot(ax = axi)
axi.set_xlabel("")
axi.set_ylabel("IMF 1")

axi = ax[3]
imf_result["imf2"].plot(ax = axi)
axi.set_xlabel("Time")
axi.set_ylabel("IMF 2")
Input Signal: Niño 3
Text(51.222222222222214, 0.5, 'IMF 2')

Visualize the first three eIMF components from EEMD Ensemble IMFs show improved mode separation compared to standard EMD The noise-assisted approach helps distinguish:

  • High-frequency noise/oscillations (eIMF0)

  • Seasonal-to-interannual variability (eIMF1)

  • Lower frequency trends (eIMF2)

fig, ax = plt.subplots(4, 1, figsize = (8, 8), sharex=True)
fig.subplots_adjust(hspace=0.2)

axi = ax[0]
eimf_result["input"].plot(ax = axi, color = "r")
axi.set_xlabel("")
axi.set_ylabel("Input")
axi.set_title("Input Signal: Niño 3")

axi = ax[1]
eimf_result["eimf0"].plot(ax = axi)
axi.set_xlabel("")
axi.set_ylabel("eIMF 0")

axi = ax[2]
eimf_result["eimf1"].plot(ax = axi)
axi.set_xlabel("")
axi.set_ylabel("eIMF 1")

axi = ax[3]
eimf_result["eimf2"].plot(ax = axi)
axi.set_xlabel("Time")
axi.set_ylabel("eIMF 2")
Input Signal: Niño 3
Text(64.22222222222221, 0.5, 'eIMF 2')

Total running time of the script: (0 minutes 6.407 seconds)