Convex signal decomposition for scalar time series — decompose a 1-D signal into interpretable components (a residual plus a trend, periodic terms, sparse spikes, exogenous responses, …) by solving one convex problem or a specified deterministic sequence of convex problems modeled in CVXPY.
⚠️ Work in progress. The core library is implemented and tested. The agent-facing skill has a complete entry point and a growing reference set, but several deep dives and examples remain. Interfaces and prose may change.
This repo pairs a thin, verifiable mathematical substrate with an agent-facing methodology for under-specified model design. Two things live here, and they're meant to work together:
-
A small, tested Python library (
signaldecomp) that builds and solves masked signal-decomposition problems. Unavailable data is native — the consistency constraint is imposed where the signal is observed and every component input is valid, so the same mechanism handles gaps, holdouts, offset boundaries, missing drivers, and imputation. -
An agent skill (
SKILL.md+reference/) that teaches a capable language model to formulate signal decompositions well: to translate a domain problem into convex components, generate correct CVXPY, and wire the results back to interpretable outputs.
The design bet is that a capable model already knows convex optimization; what it lacks is consistency, footgun-immunity, and a verifiable target. The library is a correct substrate to build on; DCP (disciplined convex programming) is the type system that catches malformed models before they produce meaningless answers. Components are a composable vocabulary, not a fixed menu — when a structure isn't in the catalog, you write the few lines of CVXPY that express it. A Tier 1/2/3 specification hierarchy then separates insensitive knobs, reconstruction-tunable knobs, and structural decisions that must be judged on the component itself.
It builds on the signal-decomposition framework of Meyers & Boyd (2023), Signal Decomposition Using Masked Proximal Operators, recast around CVXPY as the modeling language and scoped (for now) to convex, scalar-valued problems.
import numpy as np
from signaldecomp import (
make_problem, solve, components_to_frame,
smooth_trend, multiperiodic, period_samples,
SECONDS_PER_DAY, SECONDS_PER_YEAR,
)
y = ... # 1-D array on a regular grid, NaN where missing
delta = SECONDS_PER_DAY
built = make_problem(y, components=[
smooth_trend(1e2, role="trend"),
multiperiodic(period_samples(SECONDS_PER_YEAR, delta),
num_harmonics=4, role="seasonal"),
])
out = solve(built)
df = components_to_frame(out, y=y) # labeled components, gaps imputedThe code above is the library. The point of the skill is what a capable agent can do with it — which is the part that answers "why an agent skill, not just a package?" Here is a fresh context, cold: the user drops in a CSV and the skill, nothing else.
User: hi, i'm trying to work on
@synthetic_hourly.csv. I would like to use@skills/cvx-sd-skill/SKILL.md
The agent reads the skill, standardizes the time axis, and explores the signal numerically — periodogram for candidate periods, variance-explained to rank sources, folding to read the daily shape — with no plot it can see:
It arrives at a reasoned report of the likely components and their nature — a trend, the dominant cycles, sparse spikes — and closes not with a verdict but with an offer: build an interactive marimo notebook so the user can classify the knobs by feel. The user takes it:
No model was specified up front. The agent used the skill's substrate, diagnostics, and tuning hierarchy to formulate one from the data and hand back a specification — which is the thing a package alone does not give you.
This is a simple example, with data generated explicitly to match the components in the code base. It is a proof of concept, not a guarantee.
examples/pvdaq4_degradation.pystudies degradation in daily normalized PV energy while keeping PV-domain preparation and rate extraction outside the general decomposition layer.examples/gasoline_price_trends.pycompares linear, smooth, piecewise-linear, and piecewise-constant trends in weekly gasoline prices using holdout and structural evidence.examples/lagged_exogenous_response.pydemonstrates ordered exogenous offsets, exact training-mask construction, penalty-preserving spline whitening, and held-out scoring.
Run the exogenous example with
uv run python examples/lagged_exogenous_response.py. Open either interactive
marimo notebook from the repository root with
uv run python -m marimo edit <path>.
Install the agent skill:
npx skills add cvxgrp/cvx-sd-skillFor local library development:
uv sync # or: pip install -e .
uv run python -m pytestRequires Python ≥ 3.12. Core dependencies: CVXPY, NumPy, SciPy, pandas, Matplotlib. Interactive exploration is best done in marimo. The repository's default uv development environment includes marimo, but the published core library does not depend on it.
- Core library: masked problem builder, convex component catalog, data-fidelity losses
- Time-axis standardization and the sub-daily heat-map diagnostic
- Validation & downstream: holdout selection, bootstrap CIs, expanding-window stability, reporting / pandas round-trip
- Offset exogenous responses with support/rank diagnostics and opt-in, penalty-preserving basis whitening
- Explicit grouped/block trend and sparse components
- Tensor-product exogenous interactions and exact composed-block whitening
- Test suite
-
SKILL.md— concise agent-facing entry point and workflow router - Core references: formulation, component catalog, diagnostics, marimo, model specification, implementation, and philosophy
- Remaining references: periodic & time, time-axis preparation, downstream, recontextualization, and gotchas
- PV degradation worked example
- Hourly electrical-load worked example
- Broader contributor and usage documentation
This is early and the direction matters more than the details right now. If the framing resonates, or if you see a problem it should (or shouldn't) tackle, please open an issue — that's exactly the kind of feedback this early post is for.
Meyers, B. E., & Boyd, S. P. (2023). Signal Decomposition Using Masked Proximal Operators. Foundations and Trends in Signal Processing, 17(1), 1–78. https://doi.org/10.1561/2000000122
Apache License 2.0 — see LICENSE and NOTICE. The natural cubic spline basis, grouped components, and interaction design include BSD-3-Clause-derived work; see THIRD_PARTY_NOTICES.md. Copyright 2025 Bennet Meyers and the Alliance for Sustainable Energy, LLC.

