VAN_DER_POL
Overview
The VAN_DER_POL function numerically solves the Van der Pol oscillator system of ordinary differential equations, a classic nonlinear oscillator model used in physics, engineering, and biology. The Van der Pol oscillator is governed by the following equations:
where and are the state variables, and is the nonlinearity parameter. The function uses SciPy’s ODE solver (scipy.integrate.solve_ivp ) to integrate the system over a specified time interval. Only the basic two-variable oscillator is exposed; features such as external forcing or higher-order extensions are not supported. The integration method can be selected from several common solvers, but only the most used options are exposed. This example function is provided as-is without any representation of accuracy.
Usage
To use the function in Excel:
=VAN_DER_POL(x_initial, y_initial, mu, t_start, t_end, [timesteps], [solve_ivp_method])x_initial(float, required): Initial value.y_initial(float, required): Initial value.mu(float, required): Nonlinearity parameter.t_start(float, required): Start time of integration.t_end(float, required): End time of integration.timesteps(int, optional, default=10): Number of timesteps to solve for.solve_ivp_method(string (enum), optional, default=‘RK45’): Integration method. Valid options:RK45,RK23,DOP853,Radau,BDF,LSODA.
The function returns a 2D array (table) with columns: t, X, Y, representing time and variable values at each step. If the input is invalid or integration fails, a string error message is returned.
Examples
Example 1: Basic Case (Default Method)
Inputs:
| x_initial | y_initial | mu | t_start | t_end | timesteps |
|---|---|---|---|---|---|
| 2.0 | 0.0 | 1.0 | 0.0 | 10.0 | 10 |
Excel formula:
=VAN_DER_POL(2.0, 0.0, 1.0, 0.0, 10.0, 10)Output:
| t | X | Y |
|---|---|---|
| 0.000 | 2.000 | 0.000 |
| 1.111 | 1.418 | -0.840 |
| 2.222 | -0.136 | -2.304 |
| 3.333 | -2.030 | -0.013 |
| 4.444 | -1.459 | 0.819 |
| 5.556 | 0.031 | 2.206 |
| 6.667 | 2.007 | 0.065 |
| 7.778 | 1.452 | -0.819 |
| 8.889 | -0.046 | -2.218 |
| 10.000 | -2.007 | -0.051 |
Example 2: With Optional Method (RK23)
Inputs:
| x_initial | y_initial | mu | t_start | t_end | timesteps | solve_ivp_method |
|---|---|---|---|---|---|---|
| 2.0 | 0.0 | 1.0 | 0.0 | 10.0 | 10 | RK23 |
Excel formula:
=VAN_DER_POL(2.0, 0.0, 1.0, 0.0, 10.0, 10, "RK23")Output:
| t | X | Y |
|---|---|---|
| 0.000 | 2.000 | 0.000 |
| 1.111 | 1.418 | -0.840 |
| 2.222 | -0.134 | -2.302 |
| 3.333 | -2.007 | 0.025 |
| 4.444 | -1.417 | 0.843 |
| 5.556 | 0.139 | 2.307 |
| 6.667 | 2.007 | -0.029 |
| 7.778 | 1.415 | -0.844 |
| 8.889 | -0.145 | -2.313 |
| 10.000 | -2.007 | 0.034 |
Example 3: Different Nonlinearity Parameter
Inputs:
| x_initial | y_initial | mu | t_start | t_end | timesteps |
|---|---|---|---|---|---|
| 2.0 | 0.0 | 2.0 | 0.0 | 10.0 | 10 |
Excel formula:
=VAN_DER_POL(2.0, 0.0, 2.0, 0.0, 10.0, 10)Output:
| t | X | Y |
|---|---|---|
| 0.000 | 2.000 | 0.000 |
| 1.111 | 1.652 | -0.427 |
| 2.222 | 0.988 | -0.908 |
| 3.333 | -1.580 | -2.796 |
| 4.444 | -1.839 | 0.358 |
| 5.556 | -1.337 | 0.595 |
| 6.667 | -0.025 | 2.569 |
| 7.778 | 1.988 | -0.242 |
| 8.889 | 1.581 | -0.458 |
| 10.000 | 0.829 | -1.106 |
Example 4: Short Time Span
Inputs:
| x_initial | y_initial | mu | t_start | t_end | timesteps |
|---|---|---|---|---|---|
| 1.0 | 1.0 | 0.5 | 0.0 | 1.0 | 10 |
Excel formula:
=VAN_DER_POL(1.0, 1.0, 0.5, 0.0, 1.0, 10)Output:
| t | X | Y |
|---|---|---|
| 0.000 | 1.000 | 1.000 |
| 0.111 | 1.104 | 0.877 |
| 0.222 | 1.194 | 0.735 |
| 0.333 | 1.267 | 0.580 |
| 0.444 | 1.323 | 0.417 |
| 0.556 | 1.360 | 0.251 |
| 0.667 | 1.379 | 0.088 |
| 0.778 | 1.380 | -0.068 |
| 0.889 | 1.364 | -0.214 |
| 1.000 | 1.333 | -0.352 |
Python Code
import scipy.integrate as scipy_integrate
import numpy as np
def van_der_pol(x_initial, y_initial, mu, t_start, t_end, timesteps=10, solve_ivp_method='RK45'):
"""
Numerically solves the Van der Pol oscillator system of ordinary differential equations.
This function wraps scipy.integrate.solve_ivp. See:
https://docs.scipy.org/doc/scipy/reference/generated/scipy.integrate.solve_ivp.html
Args:
x_initial: Initial x value.
y_initial: Initial y value.
mu: Nonlinearity parameter.
t_start: Start time of integration.
t_end: End time of integration.
timesteps: Number of timesteps to solve for. Default is 10.
solve_ivp_method: Integration method ('RK45', 'RK23', 'DOP853', 'Radau', 'BDF', 'LSODA'). Default is 'RK45'.
Returns:
2D list with header row: t, X, Y. Each row contains time and variable values, or an error message (str) if input is invalid.
This example function is provided as-is without any representation of accuracy.
"""
# Validate input types
try:
x0 = float(x_initial)
y0 = float(y_initial)
mu_ = float(mu)
t0 = float(t_start)
t1 = float(t_end)
ntp = int(timesteps)
except Exception:
return "Invalid input: All initial values, parameters, and timesteps must be numbers."
if t1 <= t0:
return "Invalid input: t_end must be greater than t_start."
if ntp <= 0:
return "Invalid input: timesteps must be a positive integer."
if solve_ivp_method not in ['RK45', 'RK23', 'DOP853', 'Radau', 'BDF', 'LSODA']:
return "Invalid input: solve_ivp_method must be one of 'RK45', 'RK23', 'DOP853', 'Radau', 'BDF', 'LSODA'."
# Create time array for evaluation
t_eval = np.linspace(t0, t1, ntp)
# Van der Pol ODE system
def vdp_ode(t, y):
x, y_ = y
dxdt = y_
dydt = mu_ * (1 - x**2) * y_ - x
return [dxdt, dydt]
# Integrate
try:
sol = scipy_integrate.solve_ivp(
vdp_ode,
[t0, t1],
[x0, y0],
method=solve_ivp_method,
dense_output=False,
t_eval=t_eval
)
except Exception as e:
return f"Integration error: {e}"
if not sol.success:
return f"Integration failed: {sol.message}"
# Format output: header row then data rows
result = [["t", "X", "Y"]]
for i in range(len(sol.t)):
t_val = float(sol.t[i])
x_val = float(sol.y[0][i])
y_val = float(sol.y[1][i])
# Disallow nan/inf
if any([
not isinstance(t_val, float) or not isinstance(x_val, float) or not isinstance(y_val, float),
t_val != t_val or x_val != x_val or y_val != y_val, # NaN check
abs(t_val) == float('inf') or abs(x_val) == float('inf') or abs(y_val) == float('inf')
]):
return "Invalid output: nan or inf detected."
result.append([t_val, x_val, y_val])
return result