Skip to main content

Comprehensive signal feature extraction with decomposition, batch processing, and sklearn integration

Project description

SigFeatX

A comprehensive Python library for extracting statistical features from 1D signals using advanced decomposition techniques and signal processing metrics.

Features

Signal Preprocessing

  • Denoising: Wavelet, median filter, lowpass, bandpass, notch
  • Normalization: Z-score, min-max, robust (MAD-based)
  • Detrending: Linear, constant, and ALS baseline detrending
  • Resampling: Linear and Fourier-based resampling

Workflow Utilities

  • Batch Extraction: Feature tables for multiple signals with optional parallelism
  • Sliding-Window Extraction: Per-window features with sample/time metadata
  • Multi-Channel Extraction: Channel-prefixed features plus coherence, PLV, and cross-correlation

Decomposition Methods

  • Fourier Transform (FT): Classical frequency domain decomposition
  • Short-Time Fourier Transform (STFT): Time-frequency analysis
  • Discrete Wavelet Transform (DWT): Multi-resolution analysis
  • Wavelet Packet Decomposition (WPD): Full wavelet tree decomposition
  • Empirical Mode Decomposition (EMD): Data-driven decomposition
  • Variational Mode Decomposition (VMD): Optimization-based decomposition
  • Successive VMD (SVMD): Sequential mode extraction
  • Empirical Fourier Decomposition (EFD): Adaptive frequency bands

Statistical Features (100+)

Time Domain

  • Basic: Mean, Std, Variance, Median, Mode, Min, Max, Range
  • Energy: RMS, Energy, Power, Mean Absolute Value
  • Shape: Crest Factor, Shape Factor, Impulse Factor, Clearance Factor
  • Distribution: Skewness, Kurtosis, Percentiles, IQR
  • Signal Characteristics: Zero Crossings, Peak-to-Peak

Frequency Domain

  • Spectral: Centroid, Bandwidth, Rolloff, Flatness, Flux
  • Energy Distribution: Energy in frequency bands (very low, low, medium, high, very high)
  • Statistical: Spectral Entropy, Skewness, Kurtosis
  • Dominant Frequency and Maximum Magnitude

Entropy Measures

  • Shannon Entropy
  • Sample Entropy
  • Permutation Entropy
  • Approximate Entropy
  • Spectral Entropy

Nonlinear Dynamics

  • Hjorth Parameters: Activity, Mobility, Complexity
  • Fractal Dimensions: Higuchi, Petrosian
  • Hurst Exponent (R/S analysis)
  • Lyapunov Exponent
  • Detrended Fluctuation Analysis (DFA)

Decomposition-Based Features

  • Energy per level/component
  • RMS per level
  • Entropy per level
  • Correlations between components
  • Energy ratios between components
  • Relative entropy (KL divergence) between components

Installation

pip install SigFeatX

Optional extras pull in heavier, feature-specific dependencies:

pip install "SigFeatX[sklearn]"   # scikit-learn transformer
pip install "SigFeatX[all]"       # sklearn + tqdm + parquet + hdf5 + viz

Or install from source for development:

git clone https://github.com/diptiman-mohanta/SigFeatX.git
cd SigFeatX
pip install -e ".[dev,all]"

Requirements

numpy>=1.24.0
scipy>=1.10.0
PyWavelets>=1.4.0
pandas>=1.5.0

Quick Start

import numpy as np
from SigFeatX import FeatureAggregator

# Generate sample signal
t = np.linspace(0, 1, 1000)
signal = np.sin(2 * np.pi * 5 * t) + 0.5 * np.sin(2 * np.pi * 10 * t)

# Initialize feature extractor
extractor = FeatureAggregator(fs=1000)

# Extract features
features = extractor.extract_all_features(
    signal,
    decomposition_methods=['fourier', 'dwt', 'emd'],
    preprocess_signal=True,
    denoise=True,
    normalize=True,
    detrend=True
)

print(f"Extracted {len(features)} features")
print(f"Mean: {features['raw_mean']:.4f}")
print(f"RMS: {features['raw_rms']:.4f}")
print(f"Dominant Frequency: {features['raw_dominant_frequency']:.2f} Hz")

Usage Examples

Basic Feature Extraction

from SigFeatX import FeatureAggregator, SignalIO

# Load signal
io = SignalIO()
signal = io.load_signal('signal.npy')

# Extract features
extractor = FeatureAggregator(fs=1000)
features = extractor.extract_all_features(signal)

# Save features
io.save_features(features, 'features.json')

Custom Preprocessing

from SigFeatX.preprocess import SignalPreprocessor

preprocessor = SignalPreprocessor()

# Denoise with wavelet
clean_signal = preprocessor.denoise(signal, method='wavelet', 
                                   wavelet='db6', level=3)

# Normalize
normalized = preprocessor.normalize(clean_signal, method='robust')

# Detrend
detrended = preprocessor.detrend(normalized, method='linear')

Individual Decomposition Methods

from SigFeatX.decompose import WaveletDecomposer, EMD, VMD

# Wavelet decomposition
wavelet = WaveletDecomposer(wavelet='db4')
coeffs = wavelet.dwt(signal, level=4)

# EMD
emd = EMD(max_imf=10)
imfs = emd.decompose(signal)

# VMD
vmd = VMD(K=5, alpha=2000)
modes = vmd.decompose(signal)

Specific Feature Categories

from SigFeatX.features.features import (
    TimeDomainFeatures,
    FrequencyDomainFeatures,
    EntropyFeatures,
    NonlinearFeatures
)

# Extract specific feature categories
time_features = TimeDomainFeatures.extract(signal)
freq_features = FrequencyDomainFeatures.extract(signal, fs=1000)
entropy_features = EntropyFeatures.extract(signal)
nonlinear_features = NonlinearFeatures.extract(signal)

Batch Processing

signals = [signal1, signal2, signal3]

result = extractor.extract_batch(
    signals,
    decomposition_methods=['fourier', 'dwt'],
    preprocess_signal=False,
    n_jobs=2,
)

df = result.dataframe
df.to_csv('features.csv', index=False)

Sliding-Window Processing

windowed = extractor.extract_windowed(
    signal,
    window_size=256,
    step_size=128,
    decomposition_methods=['fourier'],
    preprocess_signal=False,
)

# Includes window_idx, start_sample, end_sample, start_time_s, end_time_s
window_df = windowed.dataframe

Multi-Channel Processing

multichannel = np.vstack([signal_ch1, signal_ch2, signal_ch3])

features = extractor.extract_multichannel(
    multichannel,
    channel_names=['Fz', 'Cz', 'Pz'],
    decomposition_methods=['fourier'],
    include_cross=True,
)

Using Utility Functions

from SigFeatX.utils import SignalUtils

# Create sliding windows
windows = SignalUtils.sliding_window(signal, window_size=256, step_size=128)

# Segment signal
segments = SignalUtils.segment_signal(signal, n_segments=5)

# Detect peaks
peaks, properties = SignalUtils.detect_peaks(signal, height=0.5)

# Compute envelope
envelope = SignalUtils.compute_envelope(signal)

# Add noise
noisy_signal = SignalUtils.add_noise(signal, snr_db=10)

API Reference

FeatureAggregator

Main class for feature extraction pipeline.

FeatureAggregator(fs=1.0)

Parameters:

  • fs: Sampling frequency (default: 1.0)

Methods:

extract_all_features(signal, decomposition_methods=None, preprocess_signal=True, extract_raw=True, **preprocess_kwargs)

Extract all features from signal.

Parameters:

  • signal: Input 1D numpy array
  • decomposition_methods: List of decomposition methods to apply
    • Options: ['fourier', 'stft', 'dwt', 'wpd', 'emd', 'vmd', 'svmd', 'efd']
  • preprocess_signal: Whether to preprocess signal (default: True)
  • extract_raw: Extract features from raw signal (default: True)
  • **preprocess_kwargs: Preprocessing parameters
    • denoise: Apply denoising (default: True)
    • normalize: Apply normalization (default: True)
    • detrend: Apply detrending (default: True)
    • denoise_method: Denoising method ('wavelet', 'median', 'lowpass', 'bandpass', 'notch')
    • normalize_method: Normalization method ('zscore', 'minmax', 'robust')
    • detrend_method: Detrending method ('linear', 'constant', 'als')
    • detrend_params: Extra ALS parameters such as lam, p, and n_iter

Returns:

  • Dictionary of feature names and values

extract_batch(signals, ..., n_jobs=1, on_error='warn')

Extract features for a list or 2D array of signals and return a BatchResult containing a pandas DataFrame plus success/error metadata.

extract_windowed(signal, window_size, step_size, ...)

Run the normal extraction pipeline over sliding windows and return a BatchResult with per-window metadata columns.

extract_multichannel(signals_2d, channel_names=None, include_cross=True, ...)

Extract per-channel features from a (n_channels, n_samples) array and, optionally, pairwise coherence, cross-correlation, and PLV summaries.

SignalPreprocessor

Preprocessing operations for signals.

SignalPreprocessor()

Methods:

denoise(sig, method='wavelet', **kwargs)

Denoise signal using various methods.

normalize(sig, method='zscore')

Normalize signal.

detrend(sig, method='linear', **kwargs)

Remove trend from signal. For method='als', pass lam, p, and n_iter through **kwargs.

resample(sig, target_length, method='linear')

Resample signal to target length.

Decomposition Classes

FourierTransform

FourierTransform(fs=1.0)
  • transform(signal): Compute FFT
  • get_power_spectrum(signal): Get power spectrum
  • get_phase_spectrum(signal): Get phase spectrum

WaveletDecomposer

WaveletDecomposer(wavelet='db4')
  • dwt(signal, level=None): Discrete Wavelet Transform
  • wpd(signal, level=3): Wavelet Packet Decomposition
  • cwt(signal, scales=None): Continuous Wavelet Transform
    • If the configured wavelet is discrete-only (for example db4), CWT falls back to morl
  • swt(signal, level=1): Stationary Wavelet Transform

EMD

EMD(max_imf=10, max_iter=100)
  • decompose(signal): Decompose into IMFs
  • reconstruct(imfs): Reconstruct signal from IMFs

VMD

VMD(alpha=2000, K=3, tau=0.0, DC=False, init=1, tol=1e-7, max_iter=500)
  • decompose(signal): Decompose into modes
  • reconstruct(modes): Reconstruct signal from modes

SVMD

SVMD(alpha=2000, K_max=10, tol=1e-7, max_iter=500)
  • decompose(signal): Successive decomposition

EFD

EFD(n_modes=5)
  • decompose(signal): Empirical Fourier decomposition

Feature Extraction Classes

TimeDomainFeatures

TimeDomainFeatures.extract(signal)

Returns dictionary with 25+ time domain features.

FrequencyDomainFeatures

FrequencyDomainFeatures.extract(signal, fs=1.0)

Returns dictionary with 20+ frequency domain features.

EntropyFeatures

EntropyFeatures.extract(signal)

Returns dictionary with 4 entropy measures.

NonlinearFeatures

NonlinearFeatures.extract(signal)

Returns dictionary with 9+ nonlinear features.

DecompositionFeatures

DecompositionFeatures.extract_from_components(components, prefix='comp')

Extract features from decomposition components.

SignalIO

Handle signal data I/O operations.

SignalIO()

Methods:

  • load_signal(filepath, file_format='auto'): Load signal from file
  • save_signal(signal, filepath, file_format='auto'): Save signal to file
  • save_features(features, filepath, file_format='auto'): Save features
  • load_features(filepath, file_format='auto'): Load features

SignalUtils

Utility functions for signal processing.

SignalUtils()

Static Methods:

  • sliding_window(sig, window_size, step_size): Create sliding windows
  • pad_signal(sig, target_length, mode='constant'): Pad signal
  • segment_signal(sig, n_segments): Segment signal
  • compute_snr(sig, noise): Compute SNR
  • detect_peaks(sig, height=None, distance=None): Detect peaks
  • compute_envelope(sig): Compute signal envelope
  • compute_instantaneous_frequency(sig, fs=1.0): Compute inst. frequency
  • remove_outliers(sig, n_std=3.0): Remove outliers
  • add_noise(sig, snr_db, noise_type='gaussian'): Add noise

Feature List

Time Domain (25 features)

  • mean, std, variance, median, mode
  • max, min, range, peak_to_peak
  • skewness, kurtosis
  • rms, energy, power
  • mean_absolute, sum_absolute
  • zero_crossings, zero_crossing_rate
  • crest_factor, shape_factor, impulse_factor, clearance_factor
  • q25, q75, iqr, coeff_variation

Frequency Domain (20+ features)

  • spectral_centroid, spectral_spread, spectral_bandwidth
  • spectral_rolloff, dominant_frequency, max_magnitude
  • spectral_flatness, spectral_entropy, spectral_flux
  • spectral_kurtosis, spectral_skewness
  • energy_very_low, energy_low, energy_medium, energy_high, energy_very_high
  • energy_ratio_very_low, energy_ratio_low, energy_ratio_medium, energy_ratio_high, energy_ratio_very_high

Entropy Features (4 features)

  • shannon_entropy
  • sample_entropy
  • permutation_entropy
  • approximate_entropy

Nonlinear Features (9 features)

  • hjorth_activity, hjorth_mobility, hjorth_complexity
  • higuchi_fractal_dimension, petrosian_fractal_dimension
  • hurst_exponent
  • lyapunov_exponent
  • dfa_alpha

Decomposition Features (per component)

  • energy, rms, mean, std, max, entropy
  • energy_ratio
  • correlations between components
  • energy ratios between components
  • kl_divergence between components

Choosing Methods

Which Decomposition Should I Use?

  • Use fourier when the signal is roughly stationary and you mainly care about dominant frequencies, spectral spread, or band energy.
  • Use stft when frequencies change over time and you need a compact time-frequency summary without the full cost of adaptive methods.
  • Use dwt when you want a fast, robust default for denoising or multiscale structure. It is usually the best first choice for production pipelines.
  • Use wpd when you want a denser wavelet tree than DWT and are willing to trade speed and simplicity for extra sub-band detail.
  • Use emd when the signal is nonlinear or non-stationary and you want data-driven intrinsic mode functions instead of fixed basis functions.
  • Use vmd when you want cleaner, more stable band-limited modes than EMD and can afford tuning K and alpha.
  • Use svmd when you want VMD-like behavior but prefer sequential mode discovery over specifying a fixed mode count up front.
  • Use efd when you want adaptive frequency-band decomposition with explicit frequency segmentation behavior.

Preprocessing Defaults

  • Use detrend_method='linear', denoise_method='wavelet', and normalize_method='zscore' as general-purpose defaults.
  • Use detrend_method='als' when the signal has a curved baseline or slow drift under mostly positive peaks, such as spectroscopy or biomedical traces.
  • Use denoise_method='bandpass' when you know the band of interest ahead of time.
  • Use denoise_method='notch' to remove narrow interference such as 50/60 Hz line noise.
  • Use normalize_method='robust' when spikes or outliers make z-score scaling unstable.

Practical Heuristics

  • Start with raw features plus fourier and dwt if you want a fast, stable baseline.
  • Add stft, emd, or vmd only when the problem really depends on non-stationary structure.
  • Prefer extract_windowed(...) when labels or events vary over time inside a long recording.
  • Prefer extract_multichannel(...) when relationships between channels matter, since it adds coherence, cross-correlation, and PLV summaries.

Advanced Topics

Custom Wavelet Selection

# Available wavelets: db1-db20, sym2-sym20, coif1-coif17, bior, rbio, dmey
wavelet = WaveletDecomposer(wavelet='sym8')
coeffs = wavelet.dwt(signal, level=5)

Optimizing VMD Parameters

# For signals with known number of modes
vmd = VMD(K=3, alpha=2000)  # K = number of modes

# For noisy signals, increase alpha
vmd = VMD(K=3, alpha=5000)

# For signals with closely spaced frequencies
vmd = VMD(K=3, alpha=1000, init=2)  # Random initialization

Memory-Efficient Batch Processing

def extract_features_generator(signals, extractor):
    for sig in signals:
        yield extractor.extract_all_features(sig)

# Process large datasets
features_gen = extract_features_generator(large_signal_list, extractor)
for i, features in enumerate(features_gen):
    # Process or save features incrementally
    io.save_features(features, f'features_{i}.json')

Parallel Processing

from multiprocessing import Pool

def extract_wrapper(sig):
    extractor = FeatureAggregator(fs=1000)
    return extractor.extract_all_features(sig)

# Process signals in parallel
with Pool(processes=4) as pool:
    all_features = pool.map(extract_wrapper, signals)

Performance Considerations

  • Signal Length: Most methods work efficiently for signals up to 10,000 samples
  • Decomposition Methods: EMD and VMD are computationally expensive; use DWT for faster processing
  • Feature Count: Extracting all features with all decomposition methods can yield 200+ features
  • Memory: VMD and SVMD require more memory for long signals
  • MODWT: uses an FFT-based pyramid algorithm (not a direct loop), so it scales well even at long signal lengths and many decomposition levels.
  • CEEMDAN: pass n_jobs=-1 to parallelize the (embarrassingly parallel) trial ensemble across CPU cores; output is identical to n_jobs=1 for the same rng seed.

Documentation

The docs/ directory has a Sphinx setup (quickstart + full API reference). Build it locally with:

pip install -e ".[docs]"
sphinx-build -b html docs docs/_build/html
# open docs/_build/html/index.html

For a live, runnable tour instead, see examples/playground.ipynb: one synthetic signal, decomposed and perfectly reconstructed by every decomposition method in the library side by side (with the reconstruction error printed, not just claimed), every feature family run on it, and a mini experiment checking that well-known features (Hurst exponent, DFA) land where signal-processing theory says they should.

Benchmarking

Run the local benchmark script to compare common extraction workflows on your machine:

python benchmarks/benchmark_feature_extraction.py

Useful options:

  • --repeats 10 for a more stable timing estimate
  • --include-slow to include an EMD benchmark
  • --json to emit machine-readable benchmark output

The script reports median/mean/best runtime, standard deviation, peak traced memory, and any runtime notes such as thread fallback when process-based parallelism is unavailable.

Troubleshooting

Common Issues

Issue: Features contain NaN or Inf values

# Solution: Check signal quality and preprocessing
features = {k: v for k, v in features.items() if not (np.isnan(v) or np.isinf(v))}

Issue: EMD fails to converge

# Solution: Reduce max_imf or smooth signal first
emd = EMD(max_imf=5, max_iter=50)

Issue: Memory error with large signals

# Solution: Use sliding windows
windows = SignalUtils.sliding_window(signal, window_size=1000, step_size=500)
for window in windows:
    features = extractor.extract_all_features(window)

Citation

If you use SigFeatX in your research, please cite:

@software{sigfeatx2024,
  title={SigFeatX: Signal Feature Extraction Library},
  author={Diptiman Mohanta},
  year={2024},
  url={https://github.com/diptiman-mohanta/SigFeatX}
}

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

License

This project is licensed under the MIT License - see the LICENSE file for details.

Acknowledgments

  • PyWavelets for wavelet transforms
  • SciPy for signal processing functions
  • NumPy for numerical computations

Contact

For questions and support, please open an issue on GitHub.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

sigfeatx-0.4.0.tar.gz (92.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

sigfeatx-0.4.0-py3-none-any.whl (92.6 kB view details)

Uploaded Python 3

File details

Details for the file sigfeatx-0.4.0.tar.gz.

File metadata

  • Download URL: sigfeatx-0.4.0.tar.gz
  • Upload date:
  • Size: 92.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for sigfeatx-0.4.0.tar.gz
Algorithm Hash digest
SHA256 f0d9fc2dd431337cc2ede1d1196250be2193996df8e206248050e8b8ad889b63
MD5 ca6d3ce500f66210599f55544dec90e4
BLAKE2b-256 2fd0a56ae5c3970cb4b8885ef96da41d9b8b77ed8f083891c507fc34bd40d90d

See more details on using hashes here.

Provenance

The following attestation bundles were made for sigfeatx-0.4.0.tar.gz:

Publisher: release.yml on diptiman-mohanta/SigFeatX

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file sigfeatx-0.4.0-py3-none-any.whl.

File metadata

  • Download URL: sigfeatx-0.4.0-py3-none-any.whl
  • Upload date:
  • Size: 92.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for sigfeatx-0.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 af2ef1387fbf57030662c52e7dd4cdb71eae18034b0d3c53338a1eebda32be64
MD5 1fbaeb8f9b97abe40b8047620a5e518b
BLAKE2b-256 b3a1fe425bf68efaa070c13d066ba0f5574ae55159577c1fcfaaed00cb34c414

See more details on using hashes here.

Provenance

The following attestation bundles were made for sigfeatx-0.4.0-py3-none-any.whl:

Publisher: release.yml on diptiman-mohanta/SigFeatX

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page