numpy中empty()与zeros()初始化洛伦兹吸引子绘图异常问题咨询

问题原因
核心bug是初始值赋值的位置写反了:代码中先执行了20000次迭代计算,才给三个数组的索引0位置赋预设的初始值(0., 1., 1.05)。迭代过程中计算索引1及之后的数值时,用到的索引0位置的值,完全是数组初始化时自带的默认值,根本不是设定的初始条件,属于典型的未定义行为。
不同初始化方式表现不一致的原因:
np.empty()创建数组时不会对内存空间做任何赋值操作,数组元素是对应内存位置残留的旧数据,值完全随机。之前能跑出正确图形纯靠运气:内存残留值刚好满足洛伦兹迭代的混沌触发条件,就得到了看似正确的结果,本质是错误代码碰巧跑出了符合预期的输出。np.zeros()会把数组所有元素初始化为0。当dydt用zeros初始化时,迭代用到的dydt[0]为0,代入第一步迭代公式后,所有后续计算值都会沿着固定线性路径变化,不会进入混沌状态,最终绘制出直线。- 单独把
dxdt、dzdt换成zeros初始化仍能出图,是因为这两个位置初始为0时,只要dydt[0]的随机残留值不为0,仍然能碰巧触发混沌迭代路径,不代表代码逻辑正确。
原代码还存在两处显性问题:一是迭代公式中dzdt[i\]多了多余的反斜杠,会触发语法错误;二是fig.gca(projection='3d')的写法在高版本matplotlib中已被废弃。
修复方案
把初始值赋值语句移动到迭代循环之前,先给数组起始位赋正确的初始值,再开始迭代计算。修正后无论用np.empty()还是np.zeros()初始化数组,都能稳定得到正确的洛伦兹吸引子图形。
修正后的代码如下:
import numpy as np import matplotlib.pyplot as plt # 混沌模型参数 σ = 10 ρ = 28 β = 8/3 dt = 0.01 # 迭代步长 num_steps = 20000 # 初始化数组 dxdt = np.zeros(num_steps + 1) dydt = np.zeros(num_steps + 1) dzdt = np.zeros(num_steps + 1) # 先赋初始值,再做迭代 dxdt[0], dydt[0], dzdt[0] = (0., 1., 1.05) # 迭代计算 for i in range(num_steps): dxdt[i+1] = dxdt[i] + σ*(dydt[i] - dxdt[i])*dt dydt[i+1] = dydt[i] + (dxdt[i] * (ρ - dzdt[i]) - dydt[i])*dt dzdt[i+1] = dzdt[i] + (dxdt[i] * dydt[i] - β * dzdt[i])*dt # 绘图 fig = plt.figure(figsize=(16, 16), dpi=400) ax = fig.add_subplot(projection='3d') ax.plot(dxdt, dydt, dzdt, lw=0.5) ax.set_xlabel("X Axis") ax.set_ylabel("Y Axis") ax.set_zlabel("Z Axis") ax.set_title("Lorenz Attractor") plt.show()
内容的提问来源于stack exchange,提问作者Trissa Shamp
相关产品推荐
相关产品推荐

