import numpy as np
import matplotlib.pyplot as plt
from matplotlib.widgets import Slider
A = 1.0
T = 1.0
initial_duty = 0.5
initial_slew = 0.05
n_max = 80
fig = plt.figure(figsize=(10, 8))
ax1 = fig.add_subplot(211)
ax2 = fig.add_subplot(212)
plt.subplots_adjust(bottom=0.3, hspace=0.5)
n = np.arange(-n_max, n_max+1)
f = n / T
c_initial = A * initial_duty * np.sinc(n * initial_duty)
spect_container = ax1.stem(f, 20*np.log10(np.abs(c_initial) + 1e-12),
linefmt='b-', markerfmt='bo', basefmt=' ')
ax1.set(xlim=(-80,80), ylim=(-80, 6),
xlabel='Frequency (Hz)', ylabel='Amplitude (dB)',
title=f'Spectrum with Duty={initial_duty:.2f}, Slew={initial_slew:.2f}')
ax1.grid(linestyle=':', alpha=0.6)
stemlines = spect_container.stemlines
markers = spect_container.markerline
t = np.linspace(-2*T, 2*T, 2000)
def generate_wave(t, duty, slew_rate):
"""生成带可调斜边的梯形波"""
phase = (t % T)/T
rise_time = slew_rate
fall_time = slew_rate
on_time = duty - (rise_time + fall_time)
on_time = max(on_time, 0)
rise_end = rise_time
plateau_end = rise_end + on_time
fall_end = plateau_end + fall_time
wave = np.zeros_like(phase)
mask = phase < rise_end
wave[mask] = phase[mask]/rise_time
mask = (phase >= rise_end) & (phase < plateau_end)
wave[mask] = 1.0
mask = (phase >= plateau_end) & (phase < fall_end)
wave[mask] = 1.0 - (phase[mask] - plateau_end)/fall_time
return A * wave
wave_initial = generate_wave(t, initial_duty, initial_slew)
wave_line, = ax2.plot(t, wave_initial, 'b-')
ax2.set(xlim=(-2,2), ylim=(-0.1,1.1),
xlabel='Time (s)', ylabel='Amplitude',
title='Time Domain Waveform')
ax2.grid(linestyle=':', alpha=0.6)
ax_duty = plt.axes([0.25, 0.2, 0.65, 0.03])
duty_slider = Slider(ax_duty, 'Duty Cycle', 0.01, 1.0, valinit=initial_duty)
ax_slew = plt.axes([0.25, 0.15, 0.65, 0.03])
slew_slider = Slider(ax_slew, 'Slew Rate', 0.0, 0.5, valinit=initial_slew)
def update(val):
duty = duty_slider.val
slew = slew_slider.val
new_wave = generate_wave(t, duty, slew)
wave_line.set_ydata(new_wave)
N = 1024
t_fft = np.linspace(0, T, N, endpoint=False)
wave_fft = generate_wave(t_fft, duty, slew)
c_new = []
for ni in n:
k = ni
integrand = wave_fft * np.exp(-1j*2*np.pi*k*t_fft/T)
cn = np.trapz(integrand, t_fft) / T
c_new.append(cn)
c_new = np.array(c_new)
y_dB = 20*np.log10(np.abs(c_new) + 1e-12)
new_segments = []
for xi, yi in zip(f, y_dB):
new_segments.append([(xi, -80), (xi, yi)])
stemlines.set_segments(new_segments)
markers.set_ydata(y_dB)
ax1.set_ylim(-80, 6)
ax1.set_title(f'Spectrum with Duty={duty:.2f}, Slew={slew:.2f}')
ax2.set_title(f'Time Domain (Duty={duty:.2f}, Slew={slew:.2f})')
fig.canvas.draw_idle()
duty_slider.on_changed(update)
slew_slider.on_changed(update)
plt.show()