SciPy与Python Control库lsim函数行为不一致问题排查
SciPy与Python Control库lsim函数仿真结果差异的原因及解决方法
问题根源
- SciPy的
lsim函数在处理**无输入(u=None)**的连续系统仿真时存在逻辑疏漏:当输入为None且系统B矩阵为列向量(如示例中的(2,1))时,会错误地将连续系统按离散时间系统的逻辑处理,而非执行连续时间的状态积分。 - Python Control库的
lsim对无输入场景的处理符合控制工程预期,会严格按照连续时间状态方程$\dot{x}=Ax$进行数值积分。
解决方法
要让SciPy的lsim正确仿真无输入连续系统,需显式传入与时间序列长度匹配的零输入矩阵,而非使用None。
修正后的完整MWE
""" Minimal working example (MWE) fixing the discrepancy between lsim for the SciPy module and control module """ # Import modules import numpy as np import scipy.signal as sgnl import matplotlib.pyplot as plt import control as ctrl import control.matlab as ctrl_mtl # Number of samples N_k = 100 # Total number of outputs # Continous-time (unstable) open loop system dynamics A = np.array([[0, 1], [-2, 3]]) B = np.array([[0], [1]]) n_x = A.shape[0] n_u = B.shape[1] # Initial state x_0 = np.array([[1], [1]], dtype=float) # Sampling period h = 0.5 # Controller (full-state feedback) K = np.array([[0, -4]]) # Closed-loop (stable) continous-time system sys_cl_scipy = sgnl.StateSpace(A + B @ K, np.zeros((n_x, 1)), np.eye(n_x), np.zeros((n_x, 1))) sys_cl_ctrl = ctrl.StateSpace(A + B @ K, np.zeros((n_x, 1)), np.eye(n_x), np.zeros((n_x, 1))) # Simulate dynamics # 修正:显式生成零输入序列,替代None u_scipy = np.zeros((N_k, n_u)) _, _, x_scipy = sgnl.lsim(sys_cl_scipy, u_scipy, np.linspace(0, h * (N_k - 1), N_k), X0=np.ravel(x_0), interp=False) _, _, x_ctrl = ctrl_mtl.lsim(sys_cl_ctrl, T=np.linspace(0, h * (N_k - 1), N_k), X0=x_0) x_scipy = x_scipy.T x_ctrl = x_ctrl.T # Plot the state through state-space (verification) fig_verify, ax = plt.subplots() ax.plot(np.ravel(x_scipy[0, :]), np.ravel(x_scipy[1, :]), label="x SciPy", color="green") ax.plot(np.ravel(x_ctrl[0, :]), np.ravel(x_ctrl[1, :]), label="x control", color="blue") plt.legend() plt.title("State trajectory") # Display all plots plt.show()
补充说明
- 当系统存在非零输入时,SciPy的
lsim行为与Control库一致;仅在无输入且B矩阵为列向量的场景下会触发该问题。 - 显式传入零输入序列可绕过SciPy内部的逻辑判断漏洞,确保连续系统的仿真逻辑正确执行。
内容的提问来源于stack exchange,提问作者Bart Wolleswinkel
相关产品推荐
相关产品推荐

