当时间步长不小于 Python 时,如何计算 Kramers-Moyal 系数?

How to compute Kramers-Moyal coefficients when the time step is not to small in Python?

我正在 python 中编写一个简单的一维 Ornstein-Uhlenbeck 模拟来解释来自视频源的一些实验数据,即跟踪帧序列中的布朗粒子。相机的采样频率是 fps=30 帧/秒,这意味着我的时间分辨率大约是 dt=0.03 秒。另一方面,我能够测量的最小时间尺度约为 tau=0.5 秒,比 dt 大一个数量级(这是一个合理的差异,能够计算可观测值,例如过程)。

现在,对于模拟数据,我使用 kramersmoyal 计算前两个 Kramers-Moyal 系数。只有当 dt 不比 tau 小至少两个数量级时,第二个系数才会出现问题,在这种情况下,噪声强度的估计变为凸函数而不是平坦函数。

所以手头的问题是:

为了更具体,下面的代码显示了两个不同时间步长的模拟,dt,分别与 tau 相差两个和一个数量级。然后为这两种情况计算第二个系数,并估计过程的噪声强度。第一种情况的噪声强度看起来很平坦,但第二种情况则不然。

# === Ornstein-Uhlenbeck simulation ===

import numpy as np
import kramersmoyal as km
import matplotlib.pyplot as plt

np.random.seed(0)

n = 100_000       # total number of time steps
dt = [.003, .03]  # time steps two/one order of magnitud smaller than tau
tau = .5          # relaxation or characteristic time
sigma = 5         # noise intensity

scale_dW = sigma * np.sqrt(dt)    # scale parameter of the Wiener process
scale_x = sigma / np.sqrt(2/tau)  # scale parameter of the process under study

dW = np.random.normal(scale=scale_dW, size=(n, 2))  # Wiener process array
x = np.empty((n, 2))                                # x array
x[0] = np.random.normal(scale=scale_x, size=2)      # initial condition

# Euler-Maruyama method to solve the SDE
for i in range(n - 1):
    x[i + 1] = x[i] - 1/tau * x[i] * dt + dW[i]
# === Second Kramers-Moyal coefficient ===

fig, axs = plt.subplots(1, 2, sharey=True, figsize=(9,3.5))
bins = np.array([100])         # number of bins
powers = np.array([[1], [2]])  # first and second power

for i in range(len(dt)):
    # computation of the coefficients using `kramersmoyal`
    kmc, edges = km.km(x[:,i], bins, powers)

    # sigma parameter estimation
    sigma_est = np.sqrt(2 * kmc[1] / dt[i])

    # plotting
    axs[i].plot(edges[0], sigma_est, '.-', label=f'dt = {dt[i]}')
    axs[i].legend()
    axs[i].set_title(['FLAT', 'NOT FLAT'][i])
    axs[i].set_xlabel('x')
    axs[i].set_ylabel('estimated sigma')
plt.show()

tl;dr:将校正添加到扩散中

D₂(x) = (M₂(x) - (M₁(x)²)/2)/dt

或在您的符号中使用 kmc

sigma_est = np.sqrt(2 * (kmc[1] - 0.5*kmc[0]**2) / dt[i])

这实际上是一个已知的“问题”,它源于在求解 Kramers-Moyal 方程(或类似的 Fokker-Planck 方程)时表达 Kramers-Moyal 运算符的数学近似。您可以在 On the definition and handling of different drift and diffusion estimatesNew Journal of Physics 10、083034、2008 中找到此问题的 first-ish 示例。

为了直接得到答案,对

给出的第二个 Kramers-Moyal 系数进行了 finite-time 修正
D₂(x) = (M₂(x) - (M₁(x)²)/2)/dt

这应该会立即纠正您观察到的凸性(或二次效应)。真是finite-time效果。

您可以在 Arbitrary-Order Finite-Time Corrections for the Kramers–Moyal OperatorEntropy23[=38= 中找到所有 Kramers-Moyal 系数的全套校正](5), 517, 2021.

披露:我是 kramersmoyal python 图书馆和最后提到的出版物的作者之一。