You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python实现圆柱绕流动画:速度向量异常及动画优化求助

圆柱绕流动画优化问题

我正在编写Python代码实现圆柱绕流的动画,目前流线绘制正常,但绘制速度向量时部分向量异常偏大。同时希望实现速度向量沿流线运动的动画效果,相关代码如下:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

# 计算圆柱绕流的流函数
def stream_function(x, y, U, R):
    r = np.sqrt(x**2 + y**2)
    theta = np.arctan2(y, x)
    psi_cylinder = U * (r - R**2 / r) * np.sin(theta)
    psi_freestream = U * y
    psi = np.where(r < R, 0, psi_freestream + psi_cylinder)
    return psi

# 从流函数计算速度分量(u, v)
def velocity_components(x, y, U, R):
    psi_x = -U * (1 - R**2 / x**2) * np.sin(np.arctan2(y, x))
    psi_y = U * (1 + R**2 / y**2) * np.cos(np.arctan2(y, x))
    psi_x = psi_x * ( x ** 2 + y ** 2 >= R **2 )
    psi_y = psi_y * ( x ** 2 + y ** 2 >= R **2 )
    return psi_x, psi_y

# 绘制流线
def plot_streamlines(ax, X, Y, stream_function, U, R):
    psi = stream_function(X, Y, U, R)
    levels = np.linspace(np.min(psi), np.max(psi), 100)
    ax.contour(X, Y, psi, levels=levels, colors='b', linestyles='dashed')
    
    # 绘制圆柱下方的实流线
    ax.contour(X, Y, psi, levels=[0], colors='b')

# 绘制速度向量
def plot_velocity_vectors(ax, X, Y, velocity_components, U, R, frame):
    spacing = 5
    x_points = X[::spacing, ::spacing]
    y_points = Y[::spacing, ::spacing]

    psi_x, psi_y = velocity_components(x_points, y_points, U, R)
    ax.quiver(x_points, y_points, psi_x, psi_y, color='g', scale=0.5, width=0.01)

# 创建画布和坐标轴
fig, ax = plt.subplots()

# 圆柱参数
D = 2  # 圆柱直径(英寸)
R = D / 2  # 圆柱半径
U = 0.01  # 来流速度(英尺/秒)

# 设置绘图范围
ax.set_xlim(-D, D)
ax.set_ylim(-D, D)

# 设置等比例显示
ax.set_aspect('equal')

# 创建流线网格
x = np.linspace(-D, D, 200)
y = np.linspace(-D, D, 200)
X, Y = np.meshgrid(x, y)

# 帧更新函数
def update(frame):
    ax.clear()
    
    # # 绘制流线
    # plot_streamlines(ax, X, Y, stream_function, U, R)
    
    # 绘制速度向量
    plot_velocity_vectors(ax, X, Y, velocity_components, U, R, frame)
    
    # 重置绘图范围
    ax.set_xlim(-D, D)
    ax.set_ylim(-D, D)
    
    # 重置等比例显示
    ax.set_aspect('equal')
    
    # 设置标题
    ax.set_title(f'圆柱绕流 - 帧 {frame}')

# 创建动画
animation = FuncAnimation(fig, update, frames=np.arange(0, 4, 1), interval=100)  # 每秒10帧

# 显示初始图
plt.show()

# 保存动画
animation.save('fluid_flow_over_cylinder_with_vectors.gif', writer='imagemagick', fps=10)

当前绘制效果显示部分速度向量异常偏大,期望优化向量显示并实现速度向量沿流线运动的动画。


解决方案

1. 修复速度向量异常偏大问题

向量异常的核心原因是velocity_components函数的推导错误,误用直角坐标的x²、y²替代了极坐标下的r²。圆柱绕流的速度分量需基于极坐标公式推导:

  • 径向速度:(v_r = U\left(1 - \frac{R2}{r2}\right)\cos\theta)
  • 切向速度:(v_\theta = -U\left(1 + \frac{R2}{r2}\right)\sin\theta)
    再转换为直角坐标分量:
  • (u = v_r\cos\theta - v_\theta\sin\theta)
  • (v = v_r\sin\theta + v_\theta\cos\theta)

修正后的速度分量函数:

def velocity_components(x, y, U, R):
    r = np.sqrt(x**2 + y**2)
    theta = np.arctan2(y, x)
    # 极坐标速度分量
    v_r = U * (1 - R**2 / r**2) * np.cos(theta)
    v_theta = -U * (1 + R**2 / r**2) * np.sin(theta)
    # 转换为直角坐标
    u = v_r * np.cos(theta) - v_theta * np.sin(theta)
    v = v_r * np.sin(theta) + v_theta * np.cos(theta)
    # 圆柱内部速度置0
    mask = r >= R
    u = np.where(mask, u, 0)
    v = np.where(mask, v, 0)
    return u, v

同时调整quiver的scale参数适配速度量级,比如改为scale=0.02,避免向量过长:

ax.quiver(x_points, y_points, psi_x, psi_y, color='g', scale=0.02, width=0.005)

2. 实现速度向量沿流线运动的动画

通过预定义追踪点、每帧更新点位置的方式实现运动效果,完整代码如下:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

def stream_function(x, y, U, R):
    r = np.sqrt(x**2 + y**2)
    theta = np.arctan2(y, x)
    psi_cylinder = U * (r - R**2 / r) * np.sin(theta)
    psi_freestream = U * y
    psi = np.where(r < R, 0, psi_freestream + psi_cylinder)
    return psi

def velocity_components(x, y, U, R):
    r = np.sqrt(x**2 + y**2)
    theta = np.arctan2(y, x)
    v_r = U * (1 - R**2 / r**2) * np.cos(theta)
    v_theta = -U * (1 + R**2 / r**2) * np.sin(theta)
    u = v_r * np.cos(theta) - v_theta * np.sin(theta)
    v = v_r * np.sin(theta) + v_theta * np.cos(theta)
    mask = r >= R
    u = np.where(mask, u, 0)
    v = np.where(mask, v, 0)
    return u, v

def plot_streamlines(ax, X, Y, stream_function, U, R):
    psi = stream_function(X, Y, U, R)
    levels = np.linspace(np.min(psi), np.max(psi), 100)
    ax.contour(X, Y, psi, levels=levels, colors='b', linestyles='dashed')
    ax.contour(X, Y, psi, levels=[0], colors='b')
    # 绘制圆柱
    circle = plt.Circle((0, 0), R, color='gray')
    ax.add_artist(circle)

# 初始化追踪点
def init_trace_points(num_points, D, R):
    points = []
    # 在圆柱上游和两侧生成初始点(避免落在圆柱内部)
    for i in range(num_points):
        x = np.random.uniform(-2*D, D)
        y = np.random.uniform(-D, D)
        while x**2 + y**2 < R**2:
            x = np.random.uniform(-2*D, D)
            y = np.random.uniform(-D, D)
        points.append([x, y])
    return np.array(points)

# 更新追踪点位置
def update_trace_points(points, U, R, dt=0.1):
    x, y = points[:, 0], points[:, 1]
    u, v = velocity_components(x, y, U, R)
    # 按速度更新位置
    x_new = x + u * dt
    y_new = y + v * dt
    # 超出边界的点重置到上游
    reset_mask = (np.abs(x_new) > 2*D) | (np.abs(y_new) > D)
    x_new[reset_mask] = np.random.uniform(-2*D, -D, size=np.sum(reset_mask))
    y_new[reset_mask] = np.random.uniform(-D, D, size=np.sum(reset_mask))
    # 避免进入圆柱内部
    inside_mask = (x_new**2 + y_new**2) < R**2
    x_new[inside_mask] = np.random.uniform(-2*D, -D, size=np.sum(inside_mask))
    y_new[inside_mask] = np.random.uniform(-D, D, size=np.sum(inside_mask))
    return np.column_stack((x_new, y_new))

fig, ax = plt.subplots()

D = 2
R = D / 2
U = 0.5  # 增大速度让动画效果更明显

ax.set_xlim(-2*D, 2*D)
ax.set_ylim(-D, D)
ax.set_aspect('equal')

x = np.linspace(-2*D, 2*D, 200)
y = np.linspace(-D, D, 200)
X, Y = np.meshgrid(x, y)

# 初始化30个追踪点
trace_points = init_trace_points(30, D, R)

def update(frame):
    ax.clear()
    # 绘制流线和圆柱
    plot_streamlines(ax, X, Y, stream_function, U, R)
    
    # 更新追踪点位置
    global trace_points
    trace_points = update_trace_points(trace_points, U, R)
    
    # 绘制追踪点的速度向量和点本身
    u, v = velocity_components(trace_points[:,0], trace_points[:,1], U, R)
    ax.quiver(trace_points[:,0], trace_points[:,1], u, v, color='g', scale=2, width=0.005)
    ax.scatter(trace_points[:,0], trace_points[:,1], color='r', s=10)
    
    ax.set_title(f'圆柱绕流动画 - 帧 {frame}')
    ax.set_xlim(-2*D, 2*D)
    ax.set_ylim(-D, D)
    ax.set_aspect('equal')

animation = FuncAnimation(fig, update, frames=np.arange(0, 50, 1), interval=100)

plt.show()
animation.save('cylinder_flow_animation.gif', writer='pillow', fps=10)

代码说明

  • 修正了速度分量计算逻辑,彻底解决向量异常问题
  • 添加追踪点的初始化与更新逻辑,实现点沿流线运动的效果
  • 增大来流速度并调整向量缩放参数,让动画更直观
  • 加入圆柱可视化,完善整体画面

内容的提问来源于stack exchange,提问作者remusconnor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 07:17:05