Recipes for simulating the classical Wiener process in both continuous and discrete time.
The goal is to construct a process \( X_t \) such that $$ \mathbb{E}[X_t] = 0, \quad \text{Cov}(X_s, X_t) = K(s, t) $$ For Brownian motion, the covariance kernel is $$ K(s, t) = \min(s, t) $$ The Karhunen–Loève expansion gives $$ W_t = \sqrt{2} \sum_{k=1}^\infty Z_k \frac{\sin\left((k-\frac{1}{2})\pi t\right)}{(k-\frac{1}{2})\pi} $$ where \( Z_k \sim \mathcal{N}(0, 1) \) are independent.
import numpy as np
def brownian_motion_ctr(steps=100, n_terms=500, paths=1):
t = np.linspace(0, 1, steps)
Bt = np.zeros((paths, steps))
for p in range(paths):
Z = np.random.normal(0, 1, n_terms)
k = np.arange(1, n_terms + 1)
for i, ti in enumerate(t):
sin_terms = np.sin((k - 0.5) * np.pi * ti) / ((k - 0.5) * np.pi)
Bt[p, i] = np.sqrt(2) * np.dot(Z, sin_terms)
return Bt
Summary: This approach yields sample paths of Brownian motion with the correct covariance structure, as guaranteed by the Karhunen–Loève theorem.
In discrete time, we want to construct a vector \( X \) such that $$ \mathbb{E}[X] = 0, \quad \text{Cov}(X) = \Gamma $$ where \( \Gamma_{ij} = \min(t_i, t_j) \) is the covariance matrix for Brownian motion.
import numpy as np
def brownian_motion_dtr(steps=100, paths=1, T=1):
t = np.linspace(0, T, steps)
Gamma = np.zeros((steps, steps))
for i in range(steps):
for j in range(steps):
Gamma[i, j] = min(t[i], t[j])
eigenvals, eigenvecs = np.linalg.eigh(Gamma)
Z = np.random.normal(0, 1, (steps, paths))
Wt = eigenvecs @ np.diag(np.sqrt(eigenvals)) @ Z
return Wt.T
Summary: This approach produces Brownian motion sample paths with the correct covariance structure by diagonalizing the covariance matrix and scaling standard normal draws.
This note discusses the necessary steps to simulate a stochastic process with a desired covariance structure. In this context, I outline the Karhunen–Loéve theorem and provide intuition and general recipes to decompose a stochastic process by establishing the integral eigenvalue problem (continuous-time) or, equivalently, the covariance matrix diagonalization problem (discrete-time). I then apply these general recipes to a Brownian motion and Brownian bridge to numerically simulate paths.