Multiscale signal analysis on a normalized scale space
Project description
SignalForge
Multiscale signal analysis on a normalized scale space. Give it any ordered sequence and explore its structure across scales — no labels, no training, no domain-specific code.
Table of Contents
- Install
- Quick Start
- Explore Your Data
- Python API
- What Makes This Different
- Demonstrated Results
- Documentation
- License
Install
pip install adelic-signalforge
Or from source:
git clone https://github.com/adelic-ai/signalforge
cd signalforge
uv sync
Quick Start
# Download VIX volatility data (2005-2012)
curl -o vix.csv "https://fred.stlouisfed.org/graph/fredgraph.csv?id=VIXCLS&cosd=2005-01-01&coed=2012-12-31"
# See the structure
sf surface vix.csv -hm --max-window 360
The 2008 financial crisis appears as a vertical band of red — visible across every analysis scale simultaneously. No configuration, no parameters to tune. SignalForge derives the measurement space from your data.
Explore Your Data
Load and inspect
sf load vix.csv
SignalForge vix.csv
────────────────────────────────────────
records 2,013
channels value
span 0 .. 2,085 (2,085)
grain 2 (estimated)
basis 2^2 x 3^2 x 5
scales 18 [2 .. 360]
────────────────────────────────────────
Next:
sf surface vix.csv -hm
Add a baseline
What's anomalous relative to a moving average?
sf surface vix.csv -hm --max-window 360 --baseline ewma --residual z
The residual shows how many standard deviations each point is from the baseline, at every scale. sf inspect ewma explains the method, its formula, and when to use it.
Zoom in
Spotted something? The CLI suggests a zoom command centered on the peak anomaly:
sf surface vix.csv -hm --start-date 2007-06-01 --end-date 2009-06-01
Zoomed regions get finer resolution automatically — more scales, smaller grain. Coarse-to-fine exploration is the natural workflow.
Learn the system
sf inspect
Baselines
ewma Exponentially Weighted Moving Average
median Rolling Median Filter
rolling_mean Rolling Mean
Residuals
difference Difference Residual
ratio Ratio Residual
z Z-Score Residual
Concepts
horizon Horizon
grain Grain
surface Surface
lattice Lattice
sf inspect <name> shows the formula, parameters, when to use it, and an example command. The CLI teaches the system by letting you use it.
Set up a workspace
For sustained exploration, initialize a workspace:
sf init my_project --csv vix.csv --max-window 360
cd my_project
sf surface -hm # picks up workspace config
sf surface -hm --baseline ewma --residual z --name crisis_ewma # saves the run
sf status # see what you've done
Python API
Chaining — quick exploration
import signalforge as sf
surfaces = (
sf.load("vix.csv")
.measure(windows=[10, 60, 360])
.baseline("ewma", alpha=0.1)
.residual("z")
.surfaces()
)
Each step returns a new chain. Nothing executes until .surfaces() or .run(). See the Python API guide for details.
DAG — full composition
When you need branching and merging — multiple baselines, Hilbert transform, stacked features for ML:
from signalforge.graph import Input, Measure, Baseline, Residual, Hilbert, Stack, Pipeline
x = Input()
m = Measure()(x)
bl = Baseline(method="ewma", alpha=0.1)(m)
resid = Residual(mode="z")(m, bl)
hilbert = Hilbert()(m)
features = Stack()([m, resid, hilbert])
pipe = Pipeline(x, features)
result = pipe.run(records, windows=[10, 60, 360])
The graph API composes operators into a lazy DAG. Use the chaining API to figure out what works, then lock it into a DAG for production or ML pipelines.
Signals and surfaces
Everything in SignalForge is a LatticeSignal — including surfaces. A surface IS a signal, so you can measure surfaces of surfaces, compute baselines of baselines, or feed any intermediate back through the pipeline.
from signalforge.signal import RealSignal, ComplexSignal
sig = RealSignal(index, values, channel="my_signal")
surface = sf.from_signal(sig).measure(windows=[10, 30, 90]).surfaces()[0]
Values are complex-native (complex128). Real signals are the common case (imag=0). The Hilbert transform promotes a real signal to its analytic (complex) form — amplitude + phase at every point.
Custom aggregations
Each surface cell is a window reduced to a number — by default a mean. SignalForge ships with 20+ aggregations (mean, std, percentiles, spectral energy, dominant frequency, Shannon entropy, ...) and you can register your own:
from signalforge.pipeline.aggregation import register_aggregation
@register_aggregation("iqr")
def iqr(values):
return float(np.percentile(values, 75) - np.percentile(values, 25))
Any function that takes an array and returns a float works. See docs/python-api.md for the full list.
What Makes This Different
Standard multiscale analysis (STFT, wavelets) requires the analyst to choose window sizes. SignalForge derives the measurement space from the arithmetic of your declared windows and grain. The valid scales are the divisors of the horizon — a structure from number theory that guarantees:
- Artifact-free tiling — windows nest perfectly, no boundary effects
- Structural invariance — same plan = same grid. Surfaces from different signals are directly comparable
- Scale coherence — every scale is a divisor of every larger scale. The lattice IS the multiscale structure
Two signals with the same sampling plan produce identically shaped surfaces. This is what makes ML on surfaces meaningful — features at each scale occupy the same structural position.
For a detailed comparison with wavelets, STFT, and EMD: docs/comparison.md
Demonstrated Results
EEG seizure detection
SignalForge detected a clinical epileptic seizure at 13.96σ on CHB-MIT EEG data — the windowed mean during the seizure deviated nearly 14 standard deviations from the scale baseline. No training data, no labels, no EEG-specific code.
The same pipeline processes VIX market data, INTERMAGNET geomagnetic observatory data, and generic CSV time series unchanged.
See docs/examples.md for full walkthroughs with each dataset.
Documentation
| Doc | What it covers |
|---|---|
| Concepts | Lattice, horizon, grain, surface, signals, structural invariance |
| CLI Guide | All commands: load, surface, inspect, init, status, zoom |
| Python API | Chaining API, DAG composition, Hilbert, signals |
| Examples | VIX, EEG, INTERMAGNET walkthroughs |
| Comparison | STFT, wavelets, EMD vs SignalForge |
| Architecture | Signal module, graph, pipeline internals |
License
Business Source License 1.1. See LICENSE.
Free for non-commercial use (research, personal projects, evaluation). Commercial use requires a license from Adelic — contact shun.honda@adelic.org.
Converts to Apache 2.0 on 2029-03-22.
Citation
If you use SignalForge in published work, a citation entry will be available once the arXiv preprint is posted.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file adelic_signalforge-0.3.1.tar.gz.
File metadata
- Download URL: adelic_signalforge-0.3.1.tar.gz
- Upload date:
- Size: 14.3 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dd096cee24030720e01f4cd0a30fb51a55fd05e3c8785280b6d3146e22b3c960
|
|
| MD5 |
7c7be8e0744d7fbf3c25e200db27e00d
|
|
| BLAKE2b-256 |
8e8c9df72c66b5a2cb536b3bf4ca057b92c8285e87c1769ab3513c04c72d0657
|
File details
Details for the file adelic_signalforge-0.3.1-py3-none-any.whl.
File metadata
- Download URL: adelic_signalforge-0.3.1-py3-none-any.whl
- Upload date:
- Size: 90.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.11
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
58f5fc157a77a8b459cc5d33d7e27eea18e002abbe4dd42b203eb33d31453f63
|
|
| MD5 |
0839e587f73a9cbbc605650f7f5e0539
|
|
| BLAKE2b-256 |
d0e9265151c2c782b103ed695dc64949ec2cf7f51096437c2b9900bd0d0cb8bc
|