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

Python绘制Nyquist图动画并保存为GIF:animate函数实现求助

解决动态Nyquist图动画及GIF保存问题

Hey there! Let's work through getting your dynamic Nyquist plot animation up and running, and saved as a GIF.

First, let's break down what makes the example sine wave animation work: it updates the data array for each frame (shifting the sine wave's phase) and refreshes the line object with line.set_data(). For a Nyquist plot, the core idea is similar—but instead of shifting a sine wave, we'll be updating the frequency range (or system parameter) that generates the real (Re) and imaginary (Im) parts of your system's frequency response.

Key Concepts for Nyquist Animation

A Nyquist plot plots Re(G(jω)) vs Im(G(jω)) as ω (frequency) goes from 0 to ∞. For animation, we typically either:

  • Grow the curve incrementally: Start with ω=0 and gradually extend the frequency range to ω_max over frames, or
  • Vary a system parameter: Adjust a parameter like gain K or time constant τ each frame, and redraw the full Nyquist curve for that parameter.

Full Working Example Code

Let's use the first approach (growing the curve) with a sample transfer function. You can swap in your own Re/Im calculations easily:

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

# ----------------------
# Replace these with YOUR system's real/imag calculations
# Example: G(s) = 1/(s+1) → G(jω) = 1/(1+jω) = 1/(1+ω²) - jω/(1+ω²)
# ----------------------
def calculate_real(omega):
    return 1 / (1 + omega**2)

def calculate_imag(omega):
    return -omega / (1 + omega**2)

# Animation settings
omega_max = 15  # Upper limit for frequency
total_frames = 60  # Number of frames in the GIF
omega_full = np.linspace(0, omega_max, 1000)  # Full frequency range

# Set up the plot
fig, ax = plt.subplots(figsize=(6,6))
ax.set_xlabel('Real Part')
ax.set_ylabel('Imaginary Part')
ax.set_title('Dynamic Nyquist Plot')
ax.grid(True, linestyle='--', alpha=0.7)
ax.axhline(0, color='black', lw=0.5)
ax.axvline(0, color='black', lw=0.5)
ax.set_aspect('equal')  # Critical for Nyquist plot readability

# Initialize empty line for animation
line, = ax.plot([], [], 'b-', linewidth=2)

# Initialization function (runs once at start)
def init():
    line.set_data([], [])
    return line,

# Animation function: runs for each frame i
def animate(i):
    # Get the frequency range up to the current frame's progress
    progress = (i + 1) / total_frames
    current_omega = omega_full[:int(len(omega_full) * progress)]
    
    # Calculate real and imaginary parts for current frequency range
    real_vals = calculate_real(current_omega)
    imag_vals = calculate_imag(current_omega)
    
    # Update the line with new data
    line.set_data(real_vals, imag_vals)
    return line,

# Create the animation
ani = FuncAnimation(
    fig, animate, init_func=init,
    frames=total_frames, interval=80, blit=True
)

# Save as GIF (requires Pillow library: pip install pillow)
ani.save('nyquist_animation.gif', writer='pillow', dpi=100)

plt.show()

Critical Fixes for Your animate Function

If your current code isn't working, check these common issues:

  • Your real/imag variables need to change per frame: Unlike the static sine wave example, for Nyquist animation, you must generate new real and imag arrays for each frame (either by expanding the frequency range or adjusting a system parameter).
  • Return the line object with a comma: return line, (not return line) is required because FuncAnimation expects an iterable of artists to update.
  • Set equal aspect ratio: Nyquist plots are meant to be square—adding ax.set_aspect('equal') prevents distortion.

If You Want to Animate a System Parameter

Instead of growing the frequency range, you could vary a parameter like gain K each frame. Here's how to adjust the animate function for that:

def animate(i):
    # Let K go from 0 to 10 over frames
    K = 10 * (i / total_frames)
    # Recalculate real/imag with current K
    real_vals = K * calculate_real(omega_full)
    imag_vals = K * calculate_imag(omega_full)
    line.set_data(real_vals, imag_vals)
    return line,

Troubleshooting Tips

  • If the GIF won't save: Make sure you have Pillow installed (pip install pillow). Alternatively, use writer='imagemagick' if you have ImageMagick set up.
  • If the animation is choppy: Increase total_frames or decrease interval (the time between frames in milliseconds).
  • If your Nyquist curve looks wrong: Double-check your real/imaginary calculations for your transfer function—small math errors here will break the plot entirely.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:06:43