Learning how to compute time derivatives

Differentiation methods

This notebook explores various choices of differentiation methods that can be used with PyKoopman’s KoopmanContinuous class.

The optional parameter differentiator of the KoopmanContinuous class allows one to pass in custom time differentiation methods. differentiator should be callable with the call signature differentiator(x, t) where x is a 2D numpy ndarray with each example occupying a row and t is a 1D numpy ndarray containing the points in time for each row in x.

Two common options for differentiator are 1) Methods from the derivative package, called via the pykoopman.differentiation.Derivative wrapper. 2) Entirely custom methods.

[1]:
import sys
sys.path.append('../src')

from platform import python_version
python_version()
[1]:
'3.10.11'
[2]:
from derivative import dxdt
import matplotlib.pyplot as plt
import numpy as np

import pykoopman as pk
from pydmd import DMD
[3]:
t = np.linspace(0, 2, 50)
x = np.sin(np.pi * t) + 0.1 * np.random.standard_normal(t.shape)
x_dot = np.pi * np.cos(np.pi *  t)

plt.plot(t, x, '.')
plt.xlabel('t')
plt.title('Noisy sine');
_images/tutorial_compute_differentiation_5_0.png

Derivative package

All of the robust differentiation methods in the derivative package are available with the pykoopman.differentiation.Derivative wrapper class. One need only pass in the same keyword arguments to Derivative that one would pass to derivative.dxdt.

For example, we’ll compute the derivative of a noisy sine function with dxdt and Derivative using spline-based numerical differentiation and compare the results.

[4]:
kws = dict(kind='spline', s=0.7, periodic=True)
x_dot_dxdt = dxdt(x, t, **kws)
x_dot_derivative = pk.differentiation.Derivative(**kws)(x, t)

plot_kws = dict(alpha=0.7, linewidth=3)
plt.plot(t, x_dot, label='Exact', **plot_kws)
plt.plot(t, x_dot_dxdt, '--', label='dxdt', **plot_kws)
plt.plot(t, x_dot_derivative, ':', label='derivative', **plot_kws)
plt.xlabel('t')
plt.title('Equivalence of methods')
plt.legend();
_images/tutorial_compute_differentiation_7_0.png

Custom differentiation method

We also have the option of defining a fully custom differentiation function. Here we’ll wrap numpy’s gradient method. We can pass this method into the differentiator argument of a KoopmanContinuous object.

[5]:
from numpy import gradient

def diff(x, t):
    return gradient(x, axis=0)
[6]:
dmd = DMD(svd_rank=2)
model = pk.KoopmanContinuous(differentiator=diff, regressor=dmd)
model.fit(x, dt=t[1]-t[0])
[6]:
KoopmanContinuous(differentiator=<function diff at 0x000001F2B61B2D40>,
                  observables=Identity(),
                  regressor=PyDMDRegressor(regressor=<pydmd.dmd.DMD object at 0x000001F29514A410>))
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.