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.
Install
pip install adelic-signalforge
Or from source:
git clone https://github.com/adelic-ai/signalforge
cd signalforge
uv sync
Explore your data
SignalForge works on CSV data — from a simple two-column time series to multi-channel, multi-entity datasets. Each channel gets its own surface; channels can be combined to derive new ones. Start with something simple:
# Grab 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"
# What's in it?
sf load vix.csv
file : vix.csv
records : 2,013
channels : ['value']
range : 0 → 2,085 (span: 2,085)
est grain : 2
Build a surface
A surface is a 2D grid — time on one axis, analysis scale on the other. One command:
sf surface vix.csv -hm --max-window 360
This produces a multiscale heatmap showing z-score deviations across all scales. The 2008 financial crisis appears as a vertical band of red — visible across every scale simultaneously.
--max-window 360 means "analyze at scales up to 360 bins." The bin size is estimated from the data, and the full set of valid analysis scales is derived from the bins and your window choice — every scale nests cleanly into the others with no boundary artifacts.
Try different baselines
What's the deviation relative to? That's the baseline. Swap it:
sf surface vix.csv -hm --baseline ewma --alpha 0.1
sf surface vix.csv -hm --baseline median --window 20
Don't know what EWMA does? Ask:
sf inspect ewma
Exponentially Weighted Moving Average
=====================================
Formula: s_t = α · x_t + (1 - α) · s_{t-1}
Params: α (alpha): smoothing factor in (0, 1]. Higher = more responsive.
...
Available methods: ewma, median, rolling_mean. See sf inspect <name> for any of them.
Score the residual
Remove the baseline and look at what's left:
sf surface vix.csv -hm --baseline ewma --residual ratio
sf surface vix.csv -hm --baseline median --residual z
Residual modes: difference (absolute), ratio (multiplicative), z (normalized by baseline variability). See sf inspect ratio, sf inspect z.
Zoom in
Spotted something interesting? Zoom:
sf surface vix.csv -hm --start-date 2008-01-01 --end-date 2009-12-31
sf surface vix.csv -hm --start 800 --end 1200
The surface is recomputed over the zoomed region — the lattice geometry applies fresh to the subset.
Set up a workspace
When you're doing serious exploration, initialize a workspace:
sf init my_analysis --csv vix.csv --max-window 360
cd my_analysis
sf surface -hm
sf surface -hm --baseline ewma --residual ratio --save output/ratio.png
The workspace stores your config, so you don't repeat flags. Outputs go to output/. You can version your experiments with git.
View the lattice geometry
sf plan equities-daily
Shows the sampling plan — every window, hop, and p-adic coordinate in the lattice. This is the measurement space your surfaces live in.
Compose pipelines in Python
For more control, compose pipelines programmatically using the graph API:
from signalforge.graph import Input, Bin, Measure, Baseline, Residual, Pipeline
from signalforge.domains import timeseries
records = timeseries.ingest("vix.csv")
x = Input() # data bound at run time
b = Bin()(x) # default: agg="mean". also: "count", "max"
m = Measure()(b) # default: profile="continuous"
bl = Baseline("ewma", alpha=0.1)(m) # also: "median", "rolling_mean"
r = Residual("ratio")(m, bl) # also: "difference", "z"
pipe = Pipeline(x, r)
result = pipe.run(records)
Pipelines are lazy DAGs — define the graph, run it. Branch and merge freely: two baselines, two residuals, stack them into one surface.
What makes this different
Standard multiscale analysis (STFT, wavelets) requires the analyst to choose window sizes. SignalForge derives the measurement space from your declared windows and grain. The valid scales are the divisors of the horizon — a structure from number theory that guarantees artifact-free tiling, perfect nesting, and structural invariance across recordings.
Two signals with the same sampling plan produce surfaces that are directly comparable — no post-hoc normalization needed. This is what makes ML on surfaces meaningful: features at each scale occupy the same structural position in the lattice.
For a detailed comparison with wavelets, STFT, and EMD: docs/comparison.md
What counts as a signal
Anything ordered. Time-stamped sensor data, sequential event logs, daily market prices, clinical recordings, genomic positions. If it has an order and a value, SignalForge can surface its multiscale structure.
Time is not required — event-ordered sequences work with grain=1, where each event is one bin and scales are measured in events rather than time.
docs/domain_guide.md — how to bring your own data
Demonstrated results
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 INTERMAGNET geomagnetic observatory data unchanged.
docs/empirical_results.md — full results and reproducibility
Documentation
| Doc | What it covers |
|---|---|
| Sampling domain | The lattice, horizon, grain, why divisors |
| Scale space | Surfaces, coordinates, the geometry of scale |
| Structural invariance | Why surfaces are directly comparable |
| Comparison | STFT, wavelets, EMD vs SignalForge |
| Pipeline overview | Stages, architecture, the graph API |
| Domain guide | Bring your own data |
| Data guide | Downloading datasets, running examples |
| Operators | Transform operators and derived channels |
| Grain estimation | Automatic grain selection |
| Grain & horizon design | Internal design decisions |
| EEG discovery | The seizure detection case study |
| Empirical results | Cross-domain validation |
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.2.1.tar.gz.
File metadata
- Download URL: adelic_signalforge-0.2.1.tar.gz
- Upload date:
- Size: 12.8 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c5d4b2a65f96cb88becd69135e7495ba9a3f4a209a952a10231f4439a72af97b
|
|
| MD5 |
85965deedab171679b768873aced9d77
|
|
| BLAKE2b-256 |
6e6d3373ae5d60128ce8ff1f827e1b4eccbb31abc3b05d1f99fab376981ef3ff
|
File details
Details for the file adelic_signalforge-0.2.1-py3-none-any.whl.
File metadata
- Download URL: adelic_signalforge-0.2.1-py3-none-any.whl
- Upload date:
- Size: 78.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.8.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cc1a77c66acc7af8fb15b05bf27faba1e7b6f6cf7a4309f5b7f1670b5d028546
|
|
| MD5 |
8396bba3373987c31ef226198c71a940
|
|
| BLAKE2b-256 |
7ffda5d96e4cedb079f86e8a3e14432f9f7e22ee8c9ace65bbbd439490ba4057
|