2. 数字开关电源ADC采样与电压反馈

任务定义

本案例针对连续导通模式(CCM)下的Buck变换器,设计电压模式PID控制器。控制对象为输出电压,通过调节占空比使输出稳定在设定值。要求在给定输入电压、负载和参数条件下,完成以下闭环目标:稳态输出电压误差小于1%,阶跃负载扰动后恢复时间小于2ms,且超调量小于5%。

被控对象建模

Buck变换器小信号模型(CCM模式)传递函数为:

Gvd(s) = V_in / (LC·s² + (L/R)·s + 1)

其中V_in为输入电压,L为电感,C为输出电容,R为负载电阻。本案例参数:V_in=24V,V_ref=12V,L=100μH,C=470μF,R=2.4Ω(额定负载5A),开关频率f_sw=100kHz。

PID控制器设计与仿真代码

采用电压模式PID控制,控制器传递函数为:

C(s) = Kp + Ki/s + Kd·s

使用Python进行频域设计与时域仿真验证。代码实现以下功能:①根据给定参数计算Buck变换器传递函数;②通过根轨迹或频率响应整定PID参数;③建立离散时间仿真模型(含PWM调制器增益1/V_ramp,锯齿波幅值V_ramp=3V);④模拟阶跃启动与负载突变工况。


import numpy as np
from scipy import signal
import matplotlib.pyplot as plt

# ---------- Buck变换器参数 ----------
V_in = 24.0        # 输入电压(V)
V_ref = 12.0       # 输出电压设定值(V)
L = 100e-6         # 电感(H)
C = 470e-6         # 输出电容(F)
R = 2.4            # 额定负载电阻(Ω)
f_sw = 100e3       # 开关频率(Hz)
V_ramp = 3.0       # PWM锯齿波幅值(V)
D_nom = V_ref / V_in   # 稳态占空比

# ---------- Buck小信号传递函数 Gvd(s) ----------
num_g = [V_in]
den_g = [L*C, L/R, 1]
Gvd = signal.TransferFunction(num_g, den_g)

# ---------- PID参数整定(基于零极点对消+增益调整) ----------
# 设计目标:穿越频率 fc = f_sw/20 = 5kHz,相位裕度 > 50°
# 被控对象在5kHz处的增益与相位
w_fc = 2 * np.pi * 5e3
_, mag_g, phase_g = signal.bode(Gvd, w=[w_fc])
mag_g_db = mag_g[0]
phase_g_deg = phase_g[0]

# 计算PID零极点:将两个零点置于被控对象极点附近
f_esr_zero = 1 / (2 * np.pi * (L/R) * C)  # 约等于LC双极点频率
f_zero = 1 / (2 * np.pi * np.sqrt(L*C))   # 双极点频率 ≈ 734Hz

# 零点频率设为双极点频率的0.8倍,保证相位提升
fz1 = 0.8 * f_zero
fz2 = 0.8 * f_zero
fp_high = f_sw / 2    # 高频极点置于奈奎斯特频率附近

# 控制器传递函数 C(s) = K * (1 + s/wz1)*(1 + s/wz2) / (s * (1 + s/wp))
wz1 = 2 * np.pi * fz1
wz2 = 2 * np.pi * fz2
wp = 2 * np.pi * fp_high

# 在穿越频率处计算所需增益
s_fc = 1j * w_fc
# 控制器除增益K外的幅值(不含K)
C_noK = (1 + s_fc/wz1) * (1 + s_fc/wz2) / (s_fc * (1 + s_fc/wp))
Gvd_fc = V_in / (L*C * (s_fc)**2 + (L/R)*s_fc + 1)
# 开环增益 = K * |C_noK| * |Gvd_fc| * (1/V_ramp) = 1 在穿越频率处
K = 1 / (abs(C_noK) * abs(Gvd_fc) * (1/V_ramp))

# 转换为标准PID参数(并联形式)
# C(s) = Kp + Ki/s + Kd*s 近似(忽略高频极点影响,用实际传递函数)
num_c = [K * (1/wz1 + 1/wz2), K * (1 + 1/(wz1*wz2)), K]
# 实际控制器传递函数含积分项和高频极点
num_c = [K, K*(1/wz1 + 1/wz2), K/(wz1*wz2)]
den_c = [1/wp, 1, 0]   # 含积分项
C_pid = signal.TransferFunction(num_c, den_c)

# 提取等效PID增益(用于离散化)
# 将C(s)展开为 Kp + Ki/s + Kd*s 形式(忽略高频极点)
Kp = K * (1/wz1 + 1/wz2)
Ki = K
Kd = K / (wz1 * wz2)

print(f"整定结果: Kp={Kp:.3f}, Ki={Ki:.0f}, Kd={Kd:.6f}")

# ---------- 离散化PID(双线性变换) ----------
Ts = 1 / f_sw
# 双线性变换 s = (2/Ts)*(z-1)/(z+1)
# 使用scipy的bilinear
C_pid_d = signal.cont2discrete((num_c, den_c), Ts, method='bilinear')

# ---------- 时域仿真(离散迭代) ----------
# 仿真参数
sim_time = 0.02    # 20ms
n_steps = int(sim_time / Ts)
t = np.arange(n_steps) * Ts

# 状态变量
v_out = np.zeros(n_steps)
i_L = np.zeros(n_steps)
duty = np.zeros(n_steps)
error = np.zeros(n_steps)
pid_out = np.zeros(n_steps)

# PID控制器离散状态(使用差分方程实现)
# 从传递函数转换为差分方程系数
num_d = C_pid_d[0][0]
den_d = C_pid_d[1][0]
# 差分方程: y[n] = -sum(den_d[1:]*y[n-k]) + sum(num_d*e[n-k])
# 注意den_d[0]通常为1

# 初始化
v_out[0] = 0
i_L[0] = 0
duty[0] = D_nom
error[0] = V_ref - v_out[0]

# 负载突变定义:在10ms时负载从5A变为2.5A(R从2.4Ω变为4.8Ω)
R_load = np.ones(n_steps) * R
R_load[int(0.01/Ts):] = 4.8   # 10ms后负载变轻

# 仿真主循环(Buck平均模型离散化)
for n in range(1, n_steps):
    # 计算PID输出(差分方程)
    # 使用直接II型转置结构
    if n >= len(num_d):
        # 计算误差序列
        e_hist = error[max(0,n-len(num_d)+1):n+1][::-1]
        y_hist = pid_out[max(0,n-len(den_d)+1):n][::-1]
        # 补零
        e_padded = np.zeros(len(num_d))
        e_padded[:len(e_hist)] = e_hist
        y_padded = np.zeros(len(den_d)-1)
        y_padded[:len(y_hist)] = y_hist
        # 计算输出
        pid_out[n] = np.dot(num_d, e_padded) - np.dot(den_d[1:], y_padded)
    else:
        pid_out[n] = 0
    
    # 限幅(占空比0~0.9)
    duty[n] = np.clip(pid_out[n], 0, 0.9)
    
    # Buck平均模型状态更新(前向欧拉)
    # 电感电流: di_L/dt = (duty*V_in - v_out)/L
    di_L = (duty[n-1]*V_in - v_out[n-1]) / L
    i_L[n] = i_L[n-1] + di_L * Ts
    
    # 输出电压: dv_out/dt = (i_L - v_out/R_load)/C
    dv_out = (i_L[n] - v_out[n-1]/R_load[n]) / C
    v_out[n] = v_out[n-1] + dv_out * Ts
    
    # 更新误差
    error[n] = V_ref - v_out[n]

# ---------- 结果分析与验证 ----------
# 稳态误差
steady_start = int(0.015 / Ts)   # 15ms后视为稳态
steady_v = v_out[steady_start:]
steady_error = np.abs(steady_v - V_ref) / V_ref * 100
print(f"稳态电压: {np.mean(steady_v):.3f}V, 误差: {np.mean(steady_error):.2f}%")

# 负载突变响应(10ms处)
step_idx = int(0.01 / Ts)
v_before = v_out[step_idx-1]
v_after = v_out[step_idx:]
v_min = np.min(v_after)
v_max = np.max(v_after)
overshoot = (v_max - V_ref) / V_ref * 100
undershoot = (V_ref - v_min) / V_ref * 100
print(f"负载突变后: 过冲 {overshoot:.2f}%, 下冲 {undershoot:.2f}%")

# 恢复时间计算(进入±1%误差带)
band = 0.01 * V_ref
recovery_time = None
for i in range(step_idx, n_steps):
    if np.abs(v_out[i] - V_ref) < band:
        recovery_time = (i - step_idx) * Ts * 1000  # ms
        break
print(f"恢复时间: {recovery_time:.2f}ms")

# 绘制响应曲线
plt.figure(figsize=(10, 6))
plt.subplot(2,1,1)
plt.plot(t*1000, v_out, label='V_out')
plt.axhline(V_ref, color='r', linestyle='--', label='V_ref=12V')
plt.axvline(10, color='gray', linestyle=':', label='负载突变')
plt.ylabel('输出电压 (V)')
plt.legend()
plt.grid(True)

plt.subplot(2,1,2)
plt.plot(t*1000, duty, label='Duty')
plt.ylabel('占空比')
plt.xlabel('时间 (ms)')
plt.legend()
plt.grid(True)
plt.tight_layout()
plt.savefig('buck_pid_response.png', dpi=100)
plt.show()

仿真结果与判定

运行上述代码后,观察生成的buck_pid_response.png图像。预期输出电压从0V启动,经约3~5ms达到12V附近,稳态误差小于1%。在10ms处负载由5A降至2.5A时,输出电压出现短暂上冲(因负载变轻),随后在1ms内恢复至12V±1%误差带内。判定标准:稳态误差<1%(即11.88V~12.12V),负载突变后恢复时间<2ms,超调量<5%。若仿真结果不满足,调整PID参数(增大Kp提高响应速度,增大Kd抑制超调,调整Ki消除稳态误差)后重新运行。

关键实现说明

本案例使用Buck变换器连续平均模型进行仿真,忽略了开关纹波,适用于控制环路的动态特性分析。PID参数通过频域法整定:将控制器两个零点置于LC双极点附近以抵消其相位滞后,穿越频率设为开关频率的1/20以保证稳定性。实际工程中需根据数字实现时的延迟和量化效应进一步微调参数。

Buck变换器电压模式PID控制仿真验证拓扑 Buck变换器 V_in=24V L=100μH, C=470μF f_sw=100kHz R=2.4Ω→4.8Ω V_out 误差计算 e = V_ref - V_out V_ref=12V PID控制器 Kp=0.152 Ki=702 Kd=3.3e-6 PWM调制 锯齿波 V_ramp=3V 占空比限幅0~0.9 占空比驱动信号 负载扰动 t=10ms: 5A→2.5A 验证观测点 ①稳态误差 < 1% ②恢复时间 < 2ms ③超调量 < 5% 图例 信号连线 扰动/观测

运行与验证方法

执行环境需安装Python 3.8+、NumPy、SciPy和Matplotlib。将上述代码保存为buck_pid_sim.py,在终端运行python buck_pid_sim.py。程序会打印整定后的PID参数、稳态误差、过冲/下冲和恢复时间,并弹出响应曲线图。判定标准:稳态误差<1%、恢复时间<2ms、超调量<5%三项同时满足即通过。若未达标,调整PID参数后重新运行,直至满足指标。