news 2026/4/21 9:48:23

用Python的SciPy和Matplotlib,5分钟搞定单摆与双摆的混沌动画(附完整代码)

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
用Python的SciPy和Matplotlib,5分钟搞定单摆与双摆的混沌动画(附完整代码)

用Python打造单摆与双摆的混沌之美:从基础模拟到炫酷动画

你是否曾被物理课本上那些复杂的力学公式劝退,却又对单摆和双摆的优雅运动轨迹充满好奇?今天,我们将用Python的SciPy和Matplotlib这两个强大的工具,带你绕过繁琐的数学推导,直接动手实现单摆和双摆的模拟与可视化。即使你完全不懂拉格朗日力学,也能在短短几分钟内看到这些迷人的物理现象在你的屏幕上活灵活现。

1. 准备工作与环境配置

在开始之前,我们需要确保你的Python环境已经安装了必要的库。如果你使用的是Anaconda,这些库通常已经预装。如果没有,可以通过以下命令快速安装:

pip install numpy scipy matplotlib

这三个库将构成我们整个项目的基础:

  • NumPy:提供高效的数值计算功能
  • SciPy:包含我们需要的微分方程求解器
  • Matplotlib:用于数据可视化和动画制作

为了验证安装是否成功,可以运行以下测试代码:

import numpy as np from scipy.integrate import odeint import matplotlib.pyplot as plt print("所有库已正确安装!")

2. 单摆模拟:从简单开始

单摆是最基础的物理系统之一,也是理解更复杂系统(如双摆)的绝佳起点。让我们先建立一个简单的单摆模型。

2.1 单摆的物理模型

单摆的运动可以用以下微分方程描述:

θ'' + (g/L) * sin(θ) = 0

其中:

  • θ是摆角(弧度)
  • g是重力加速度(9.8 m/s²)
  • L是摆长(米)

这个方程看起来简单,但由于sin(θ)的非线性特性,解析求解相当复杂。幸运的是,我们可以用数值方法轻松解决。

2.2 使用SciPy求解单摆运动

下面是一个完整的单摆模拟代码:

from math import sin import numpy as np from scipy.integrate import odeint import matplotlib.pyplot as plt # 物理参数 g = 9.8 # 重力加速度 (m/s^2) L = 1.0 # 摆长 (m) # 微分方程定义 def pendulum_eq(y, t, L): theta, omega = y # 解包当前状态:角度和角速度 dydt = [omega, - (g/L) * sin(theta)] return dydt # 初始条件:初始角度1弧度(约57度),初始角速度0 y0 = [1.0, 0.0] # 时间点:0到10秒,步长0.01秒 t = np.linspace(0, 10, 1000) # 求解微分方程 sol = odeint(pendulum_eq, y0, t, args=(L,)) # 提取结果 theta = sol[:, 0] # 角度随时间变化 omega = sol[:, 1] # 角速度随时间变化 # 绘制角度随时间变化图 plt.figure(figsize=(10, 5)) plt.plot(t, theta, 'b', label='角度(rad)') plt.plot(t, omega, 'g', label='角速度(rad/s)') plt.legend(loc='best') plt.xlabel('时间 (s)') plt.ylabel('角度/角速度') plt.title('单摆运动') plt.grid() plt.show()

这段代码会生成一个展示单摆角度和角速度随时间变化的图表。你可以尝试修改初始角度(y0中的第一个值),观察不同初始条件下单摆的运动有何不同。

2.3 单摆周期与非线性效应

对于小角度摆动(θ < 0.5弧度),单摆的周期近似为:

T ≈ 2π√(L/g)

但当摆动角度增大时,这个近似就不再准确。我们可以用SciPy计算不同初始角度下的精确周期:

from scipy.optimize import fsolve from scipy.special import ellipk def pendulum_period(L, theta0): """计算单摆的精确周期""" return 4 * np.sqrt(L/g) * ellipk(np.sin(theta0/2)**2) # 计算不同初始角度下的周期 angles = np.linspace(0, np.pi/2, 20) periods = [pendulum_period(L, angle) for angle in angles] # 绘制周期与初始角度的关系 plt.figure(figsize=(10, 5)) plt.plot(angles, periods, 'ro-') plt.xlabel('初始角度 (rad)') plt.ylabel('周期 (s)') plt.title('单摆周期与初始角度的关系') plt.grid() plt.show()

3. 双摆模拟:探索混沌世界

双摆系统由两个单摆连接而成,是一个经典的混沌系统。微小的初始条件变化可能导致完全不同的运动轨迹,这就是所谓的"蝴蝶效应"。

3.1 双摆的物理模型

双摆的运动方程比单摆复杂得多。我们不需要自己推导这些方程(这需要拉格朗日力学知识),可以直接使用现成的公式:

class DoublePendulum: def __init__(self, m1=1.0, m2=1.0, l1=1.0, l2=1.0): self.m1, self.m2 = m1, m2 # 两个小球的质量 self.l1, self.l2 = l1, l2 # 两根杆的长度 self.g = 9.8 # 重力加速度 def equations(self, state, t): """双摆的微分方程""" theta1, z1, theta2, z2 = state c, s = np.cos(theta1-theta2), np.sin(theta1-theta2) # 方程组矩阵形式:M * [theta1'', theta2''] = F M = np.array([ [(self.m1+self.m2)*self.l1, self.m2*self.l2*c], [self.l1*c, self.l2] ]) F = np.array([ -self.m2*self.l2*z2**2*s - (self.m1+self.m2)*self.g*np.sin(theta1), self.l1*z1**2*s - self.g*np.sin(theta2) ]) # 解线性方程组得到角加速度 acc = np.linalg.solve(M, F) return [z1, acc[0], z2, acc[1]]

3.2 模拟双摆运动

现在我们可以用这个类来模拟双摆的运动:

# 创建双摆实例 pendulum = DoublePendulum(m1=1.0, m2=1.0, l1=1.0, l2=1.0) # 初始条件:[theta1, omega1, theta2, omega2] y0 = [np.pi/2, 0, np.pi/2, 0] # 时间点 t = np.linspace(0, 20, 1000) # 求解微分方程 sol = odeint(pendulum.equations, y0, t) # 提取结果 theta1, theta2 = sol[:, 0], sol[:, 2] # 计算小球坐标 x1 = pendulum.l1 * np.sin(theta1) y1 = -pendulum.l1 * np.cos(theta1) x2 = x1 + pendulum.l2 * np.sin(theta2) y2 = y1 - pendulum.l2 * np.cos(theta2) # 绘制轨迹 plt.figure(figsize=(10, 10)) plt.plot(x1, y1, label='上球轨迹') plt.plot(x2, y2, label='下球轨迹') plt.legend() plt.axis('equal') plt.title('双摆运动轨迹') plt.grid() plt.show()

尝试修改初始条件(y0中的值),观察双摆运动轨迹如何变化。你会发现即使初始角度只有微小差异,长期运动轨迹也可能完全不同——这正是混沌系统的特征。

4. 制作炫酷动画

静态图像难以展现双摆运动的魅力,让我们用Matplotlib的动画功能创建一个动态可视化。

4.1 创建单摆动画

首先是一个简单的单摆动画:

from matplotlib.animation import FuncAnimation # 重新计算单摆运动 t = np.linspace(0, 10, 200) sol = odeint(pendulum_eq, y0, t, args=(L,)) theta = sol[:, 0] x = L * np.sin(theta) y = -L * np.cos(theta) # 创建动画 fig, ax = plt.subplots(figsize=(8, 8)) ax.set_xlim(-1.2*L, 1.2*L) ax.set_ylim(-1.2*L, 1.2*L) ax.grid() line, = ax.plot([], [], 'o-', lw=2) trace, = ax.plot([], [], 'b-', lw=1, alpha=0.5) time_text = ax.text(0.02, 0.95, '', transform=ax.transAxes) def init(): line.set_data([], []) trace.set_data([], []) time_text.set_text('') return line, trace, time_text def animate(i): thisx = [0, x[i]] thisy = [0, y[i]] line.set_data(thisx, thisy) trace.set_data(x[:i], y[:i]) time_text.set_text(f'时间 = {t[i]:.1f}s') return line, trace, time_text ani = FuncAnimation(fig, animate, frames=len(t), init_func=init, blit=True, interval=20) plt.show()

4.2 创建双摆动画

双摆动画更加复杂但也更加迷人:

# 重新计算双摆运动 t = np.linspace(0, 20, 500) sol = odeint(pendulum.equations, y0, t) theta1, theta2 = sol[:, 0], sol[:, 2] x1 = pendulum.l1 * np.sin(theta1) y1 = -pendulum.l1 * np.cos(theta1) x2 = x1 + pendulum.l2 * np.sin(theta2) y2 = y1 - pendulum.l2 * np.cos(theta2) # 创建动画 fig, ax = plt.subplots(figsize=(10, 10)) ax.set_xlim(-2.2, 2.2) ax.set_ylim(-2.2, 2.2) ax.grid() line, = ax.plot([], [], 'o-', lw=2) trace1, = ax.plot([], [], 'b-', lw=1, alpha=0.5) trace2, = ax.plot([], [], 'r-', lw=1, alpha=0.5) time_text = ax.text(0.02, 0.95, '', transform=ax.transAxes) def init(): line.set_data([], []) trace1.set_data([], []) trace2.set_data([], []) time_text.set_text('') return line, trace1, trace2, time_text def animate(i): thisx = [0, x1[i], x2[i]] thisy = [0, y1[i], y2[i]] line.set_data(thisx, thisy) trace1.set_data(x1[:i], y1[:i]) trace2.set_data(x2[:i], y2[:i]) time_text.set_text(f'时间 = {t[i]:.1f}s') return line, trace1, trace2, time_text ani = FuncAnimation(fig, animate, frames=len(t), init_func=init, blit=True, interval=20) plt.show()

4.3 保存动画

如果你想保存动画为GIF或视频文件,可以取消注释以下代码:

# 保存为GIF(需要安装pillow) # ani.save('pendulum.gif', writer='pillow', fps=30) # 保存为MP4(需要安装ffmpeg) # ani.save('pendulum.mp4', writer='ffmpeg', fps=30)

5. 探索与扩展

现在你已经掌握了单摆和双摆模拟的基本方法,可以尝试以下扩展:

  1. 参数调整:改变质量、摆长等参数,观察系统行为变化
  2. 能量分析:计算并绘制系统的动能、势能和总能量
  3. 相图:绘制角度与角速度的关系图,观察相空间轨迹
  4. 三摆系统:挑战更复杂的多摆系统
  5. 交互式控制:使用ipywidgets创建可交互的模拟界面

例如,这里是一个简单的能量计算函数:

def calculate_energies(theta1, theta2, omega1, omega2, m1, m2, l1, l2, g=9.8): # 计算坐标和速度 x1 = l1 * np.sin(theta1) y1 = -l1 * np.cos(theta1) x2 = x1 + l2 * np.sin(theta2) y2 = y1 - l2 * np.cos(theta2) # 速度分量 vx1 = l1 * omega1 * np.cos(theta1) vy1 = l1 * omega1 * np.sin(theta1) vx2 = vx1 + l2 * omega2 * np.cos(theta2) vy2 = vy1 + l2 * omega2 * np.sin(theta2) # 动能 T = 0.5 * m1 * (vx1**2 + vy1**2) + 0.5 * m2 * (vx2**2 + vy2**2) # 势能 V = m1 * g * (y1 + l1) + m2 * g * (y2 + l1 + l2) return T, V, T + V # 计算双摆的能量 T, V, E = calculate_energies(theta1, theta2, sol[:,1], sol[:,3], pendulum.m1, pendulum.m2, pendulum.l1, pendulum.l2) # 绘制能量随时间变化 plt.figure(figsize=(10, 5)) plt.plot(t, T, 'r', label='动能') plt.plot(t, V, 'b', label='势能') plt.plot(t, E, 'g', label='总能量') plt.legend() plt.xlabel('时间 (s)') plt.ylabel('能量 (J)') plt.title('双摆能量变化') plt.grid() plt.show()

通过这个项目,你不仅学会了如何用Python模拟物理系统,还掌握了科学计算和可视化的核心技能。这些技术可以应用于从工程分析到金融建模的广泛领域。最重要的是,你看到了即使是最复杂的物理现象,也可以通过计算工具变得触手可及。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/21 9:48:20

苍穹外卖Day09Day10笔记

苍穹外卖笔记Day09Day10 1. SpringTask 定时任务&#xff08;苍穹外卖实战&#xff09; 1.1 基本概念 SpringTask 是 Spring 框架原生自带 的定时任务工具&#xff0c;无需整合 Quartz 等第三方中间件&#xff0c;轻量、简单、开箱即用&#xff0c;专门用于处理苍穹外卖中「周期…

作者头像 李华
网站建设 2026/4/21 9:47:15

终极指南:3步实现微信平板模式,轻松突破安卓多设备登录限制

终极指南&#xff1a;3步实现微信平板模式&#xff0c;轻松突破安卓多设备登录限制 【免费下载链接】WeChatPad 强制使用微信平板模式 项目地址: https://gitcode.com/gh_mirrors/we/WeChatPad 你是否曾为微信"手机与平板不能同时在线"的限制而烦恼&#xff1…

作者头像 李华
网站建设 2026/4/21 9:43:21

Qianfan-OCR详细步骤:Gradio WebUI本地部署与Layout-as-Thought调用

Qianfan-OCR详细步骤&#xff1a;Gradio WebUI本地部署与Layout-as-Thought调用 1. 项目概述 Qianfan-OCR是百度千帆推出的开源端到端文档智能多模态模型&#xff0c;基于4B参数的Qwen3-4B语言模型构建。这个多模态视觉语言模型(VLM)采用Apache 2.0协议&#xff0c;完全开源且…

作者头像 李华
网站建设 2026/4/21 9:40:21

STM32F4 + FreeRTOS + LwIP 2.1.3 网络栈移植保姆级避坑指南(附完整源码)

STM32F4 FreeRTOS LwIP 2.1.3 网络栈移植实战全解析 在嵌入式系统开发中&#xff0c;网络功能的实现往往是最具挑战性的环节之一。当我们需要在STM32F4平台上结合FreeRTOS实时操作系统和LwIP轻量级TCP/IP协议栈构建网络应用时&#xff0c;版本兼容性、接口适配和系统整合等问…

作者头像 李华
网站建设 2026/4/21 9:40:19

PinWin窗口置顶工具:告别窗口切换烦恼,让多任务效率翻倍

PinWin窗口置顶工具&#xff1a;告别窗口切换烦恼&#xff0c;让多任务效率翻倍 【免费下载链接】PinWin Pin any window to be always on top of the screen 项目地址: https://gitcode.com/gh_mirrors/pin/PinWin 你是否曾经在编写代码时&#xff0c;需要频繁地在编辑…

作者头像 李华
网站建设 2026/4/21 9:39:22

合并两个有序数组

题目思路两个数组非递减有序&#xff0c;合并到nums1且原地修改。采用从后往前双指针&#xff1a;i指向nums1有效尾部&#xff0c;j指向nums2尾部k指向nums1最终尾部&#xff0c;每次放较大元素最后把nums2剩余元素直接复制进nums1。难点从前向后会覆盖nums1原数据&#xff0c;…

作者头像 李华