Python绘制Nyquist图动画并保存为GIF:animate函数实现求助
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
ω=0and gradually extend the frequency range toω_maxover frames, or - Vary a system parameter: Adjust a parameter like gain
Kor 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/imagvariables need to change per frame: Unlike the static sine wave example, for Nyquist animation, you must generate newrealandimagarrays for each frame (either by expanding the frequency range or adjusting a system parameter). - Return the line object with a comma:
return line,(notreturn line) is required becauseFuncAnimationexpects 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, usewriter='imagemagick'if you have ImageMagick set up. - If the animation is choppy: Increase
total_framesor decreaseinterval(the time between frames in milliseconds). - If your Nyquist curve looks wrong: Double-check your
real/imaginarycalculations for your transfer function—small math errors here will break the plot entirely.
内容的提问来源于stack exchange,提问作者Pedro Bremer

