Paul Pukite's climate and geosciences sites
This example demonstrates a PySINDy (Sparse Identification of Nonlinear Dynamics) model that uses:
t → s(t)Traditional dynamical systems are modeled as:
dx/dt = f(x, t)
In this example, we model dynamics driven by a slow oscillating latent variable:
dx/dt = f(x, s(t))
where s(t) is a slow oscillating latent variable that evolves in time. This is useful when:
The slow oscillating latent variable s(t) is generated as:
s(t) = 1 + 0.5 × sin(ω₁t) + 0.15 × cos(ω₂t)
where ω₁ = 0.2 and ω₂ = 0.15 are slow frequencies. This creates an oscillating “environmental” or “forcing” variable that represents cyclic processes like:
The observable x is generated through a nonlinear transformation of the latent variable:
x = a × s² + b × sin(2πs) + c × s
This represents the hidden latent layer connecting s to the observed signal x.
PySINDy discovers the governing equation dx/dt = f(x, s(t)) from data by:
dx/dtThe key insight is that even though s oscillates, the model captures how x responds to the periodic forcing from s.
pip install pysindy numpy matplotlib scipy
python latent_layer_example.py
The script produces:
latent_layer_example.png with four subplots:
The discovered equations show how x changes in response to the oscillating latent variable s:
s show explicit dependence on the periodic forcingx show self-interaction (feedback)x × s show coupling between state and forcings(t) provides periodic forcing that drives the observable xs(t) as an explicit variable, we capture how slow oscillations influence fast dynamicsThis approach is particularly useful for:
Possible extensions of this example:
s(t) = [s₁(t), s₂(t), ...]x(t) = [x₁(t), x₂(t), ...]dx/ds = f(x, s, u)latent_layer_example.py
├── generate_latent_variable() # Creates slow s(t)
├── generate_hidden_dynamics() # Maps s → x through hidden layer
├── compute_derivative_wrt_latent() # Computes dx/ds numerically
├── main() # Orchestrates the analysis
└── create_visualization() # Generates comprehensive plots
This example is part of the pukpr.github.io repository and follows the same license.
Two additional examples have been added that integrate the model_step_algorithm from the GIST template with PySINDy:
pysindy_with_model_step.pyPurpose: Demonstrates integration of the model_step_algorithm for generating latent hidden layers.
Key Features:
.p JSON files (Aliased, AliasedAmp, AliasedPhase)model_step_algorithm to generate latent layer via harmonic sumAlgorithm: model_step_algorithm
The core algorithm computes model values by summing harmonic components:
model_val = Σ(A_i * sin(ω_i * t + φ_i))
where:
ω_i = 2π / Period_i (angular frequency)
A_i = Amplitude_i
φ_i = Phase_i
Usage:
python pysindy_with_model_step.py
run_pysindy_on_data.pyPurpose: Command-line tool for running PySINDy analysis on real or synthetic data.
Usage:
Demo mode (synthetic data):
python run_pysindy_on_data.py --demo
With CSV data (automatically looks for data.csv.p):
python run_pysindy_on_data.py path/to/data.csv
With custom parameter file:
python run_pysindy_on_data.py data.csv --p-file path/to/params.p
Note: If no --p-file is specified, the script automatically looks for a parameter file named <csv_file>.p in the same directory as the CSV file. For example, if you provide data.csv, it will look for data.csv.p.
Arguments:
csv: Input CSV file (two-column format: time, value)--p-file: Parameter .p JSON file (default: <csv_file>.p if it exists)--output: Output plot filename (default: pysindy_result.png)--demo: Force demo mode with synthetic dataCSV Format:
time1,value1
time2,value2
...
Parameter File Format (.p JSON):
{
"Aliased": [18.6, 9.3, 6.2, ...],
"AliasedAmp": [0.5, 0.3, 0.2, ...],
"AliasedPhase": [0.0, 1.5, 3.0, ...]
}
Output:
The new examples implement a novel approach combining:
.p JSON filesmodel_step_algorithm to compute hidden featuresParameter files (.p JSON) are located in:
../../results/python_1930_1960/p/
These contain fitted harmonic parameters from tidal gauge data and climate records.