自动控制 一阶线性系统参数测定

140 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

想做一个PID温控电烙铁,首先需要测定系统参数,便于以后的仿真和选择PID参数 设电烙铁发热器的发热功率为x(t)x(t)(输入),比外界温度高为y(t)y(t)(输出),热导为GG,热容量为CC,可列出以下微分方程: Cdy(t)dt+Gy(t)=x(t)C\frac{dy(t)}{dt}+Gy(t)=x(t) 时间常数τ=CG\tau=\frac{C}{G} 该微分方程的通解y(t)=y0+1Cet/τtx(t)et/τdty(t)=y_0+\frac{1}{C}e^{-t/\tau}\int_{-\infty}^{t}x(t)e^{t/\tau}dt 先来看看仿真结果

# 参数
C = 20
G = 1
t = np.arange(0, 600, 0.1)
Pf = lambda t: 1 + np.sin(t**2/5000)
P = Pf(t) #发热功率必须为正数

# 生成数据,加入噪声
#pn = P.mean()/50
#P += np.random.normal(0, pn, P.shape)  # 实际功率噪声,odeint无效
# 使用通解进行计算,但数值太大,可能会浮点溢出,不建议使用
T = 1/C*np.exp(-G/C*t)*np.cumsum(P*np.exp(G/C*t))*(t[1]-t[0])
# 使用scipy求解ODE,不能仿真实际功率噪声
#T = odeint(lambda T,t_:(Pf(t_)-T*G)/C, 0, t)[:, 0]
pn = P.mean()/50
P += np.random.normal(0, pn, P.shape)  # 功率测量噪声
tn = T.mean()/50
T += np.random.normal(0, tn, T.shape)  # 温度测量噪声

# 温度测量比功率测量落后(>0)或超前(<0)多少帧
dt = 0
if dt > 0:
    P, T, t = P[:-dt], T[dt:], t[:-dt]
if dt < 0:
    P, T, t = P[-dt:], T[:dt], t[:dt]

# 绘图
plt.plot(t, P, c='r')
plt.twinx()
plt.plot(t, T, c='b')
plt.show()

功率和温度的波形图傅里叶变换一下,看看频谱

Pw = np.fft.rfft(P)
Tw = np.fft.rfft(T)
PwTw = Pw/Tw
w = np.linspace(0, 2*np.pi/(2*(t[1]-t[0])), Pw.shape[0])

n = 30
plt.plot(w[:n], np.log(np.abs(Pw[:n])), c='r')
plt.twinx()
plt.plot(w[:n], np.log(np.abs(Tw[:n])), c='b')
plt.show()

FFT后的频谱图

经过傅里叶变换,变为 jωCY(ω)+GY(ω)=X(ω)j\omega CY(\omega)+GY(\omega)=X(\omega) (jωC+G)Y(ω)=X(ω)(j\omega C+G)Y(\omega)=X(\omega) 实部GRe[Y(ω)]=Re[X(ω)]G *Re[Y(\omega)]=Re[X(\omega)] 虚部ωCIm[Y(ω)]=Im[X(ω)]\omega C*Im[Y(\omega)]=Im[X(\omega)] 实际测量到的数据是有噪声的 H1(ω)=X(ω)Y(ω)=jωC+GH^{-1}(\omega)=\frac{X(\omega)}{Y(\omega)}=j\omega C+G G=Re[H1(ω)]G=Re[H^{-1}(\omega)] C=1ωIm[H1(ω)]C=\frac{1}{\omega}Im[H^{-1}(\omega)]

n = 30
plt.plot(w[:n], PwTw.real[:n], c='r')
plt.twinx()
plt.plot(w[:n], PwTw.imag[:n], c='b')
plt.twiny()
plt.xlim(-1, n+1)  # 数组索引
plt.show()

逆传递函数的实部和虚部 只要X(s)输入啁啾信号,这样可以在实验中测定CCGG 另外,实际测量到的数据是有噪声的,为了提高分辨率,需要进行最小二乘法 Q(G,U)=Xi(jωiC+G)Yi2=εi2=[Re2(εi)+Im2(εi)]Q(G, U)=\sum\left|X_i-(j\omega_iC+G)Y_i\right|^2=\sum\left|\varepsilon_i\right|^2=\sum[Re^2(\varepsilon_i)+Im^2(\varepsilon_i)]

\frac{\partial Q}{\partial G}=-2\sum[ Re(\varepsilon_i)Re(Y_i)+Im(\varepsilon_i)Im(Y_i)]=0 \\ \frac{\partial Q}{\partial U}=2\sum[Re(\varepsilon_i)Im(Y_i)-Im(\varepsilon_i)Re(Y_i)]=0 \\ \end{cases}$$ $Re(X_i-j\omega_iCY_i-GY_i)Re(Y_i)+Im(X_i-j\omega_iCY_i-GY_i)Im(Y_i)=0$ $\sum Re(X_i)Re(Y_i)+Im(X_i)Im(Y_i)=G\sum [Re^2(Y_i)+Im^2(Y_i)]$ $\hat G=\frac{\sum[Re(X_i)Re(Y_i)+Im(X_i)Im(Y_i)]}{Re^2(Y_i)+Im^2(Y_i)}=\frac{\sum(\bar XY+X\bar Y)}{2\sum\left|Y_i\right|^2}$ $\sum Re(X_i-j\omega_iCY_i-GY_i)Im(Y_i)-Im(X_i-j\omega_iCY_i-GY_i)Re(Y_i)=0$ $\sum Im(X_i)Re(Y_i)-Re(X_i)Im(Y_i)=C\sum\omega_i[Re^2(X_i)+Im^2(Y_i)]$ $\hat C=\frac{[\sum Im(X_i)Re(Y_i)-Re(X_i)Im(Y_i)]}{\omega_i[Re^2(X_i)+Im^2(Y_i)]}=\frac{\sum(X\bar Y-\bar XY)}{2i\sum\omega_i\left|Y_i\right|^2}$ ```python n = 10 Tw2 = Tw[:n] Pw2 = Pw[:n] w2 = w[:n] G_ = np.sum(Pw2.real*Tw2.real+Pw2.imag*Tw2.imag) / np.sum(np.abs(Tw2)**2) print(G_) C_ = np.sum(Pw2.imag*Tw2.real-Pw2.real*Tw2.imag) / np.sum(w2*np.abs(Tw2)**2) print(C_) ``` ``` 1.0280348744030454 19.339144120677265 ``` 接下来尝试另外一种线性近似的噪声分析的方法: $X_测(\omega)=X(\omega)+X_噪(\omega)$ $Y_测(\omega)=Y(\omega)+Y_噪(\omega)$ 假设噪声为相互独立的白噪声,即时域上是$x_噪(t)$和$y_噪(t)$是与$t$无关的正态随机变量。则频域上$X_噪(\omega)$和$Y_噪(\omega)$的实部和虚部都是与$\omega$无关的正态随机变量 由于噪声很小,可以采取线性近似。好像有点不严谨,因为这些都是复数,我复变函数这门课忘光了,可能会用错。 $\frac{X_测}{Y_测}=\frac{X+X_噪}{Y+Y_噪}\approx(1+\frac{\partial}{\partial X}X_噪+\frac{\partial}{\partial Y}Y_噪)\frac{X}{Y}$ $\frac{X_测}{Y_测}-\frac{X}{Y}\approx(\frac{\partial}{\partial X}X_噪+\frac{\partial}{\partial Y}Y_噪)\frac{X}{Y}\approx(\frac{\partial}{\partial X_测}X_噪+\frac{\partial}{\partial Y_测}Y_噪)\frac{X_测}{Y_测}$ $=(\frac{1}{Y_测}X_噪-\frac{X_测}{Y_测^2}Y_噪)\frac{X_测}{Y_测}$ 在实际FFT计算中,根据帕塞瓦尔定理 $std(X_噪)=\sqrt N*std(x_噪)$ $std(Y_噪)=\sqrt N*std(y_噪)$ $H^{-1}_噪(\omega)=\frac{X_测}{Y_测}-\frac{X}{Y}\approx\sqrt N[\frac{1}{Y_测}std(x_噪)-\frac{X_测}{Y_测^2}std(y_噪)]\frac{X_测}{Y_测}$ 使用加权平均估计$G$和$C$ $\hat G=\sum_{\omega=0}^{n}\frac{1/H^{-1}_噪[\omega]}{\sum_{i=1}^{n}(1/H^{-1}_噪[i])}Re(\frac{X_测}{Y_测})$ $\hat C=\sum_{\omega=0}^{n}\frac{\omega/H^{-1}_噪[\omega]}{\sum_{i=1}^{n}(\omega/H^{-1}_噪[i])}\frac{1}{\omega}Im(\frac{X_测}{Y_测})$ ```python n = 12 Tw2 = Tw[:n] Pw2 = Pw[:n] w2 = w[:n] PwTw2 = Pw2/Tw2 H1z = np.sqrt(len(t))*(pn/Tw2-Pw2/Tw2**2*tn) H1z = np.abs(H1z)**(1/8) # H^-1的误差 wG = 1/H1z/(1/H1z).sum() G_ = np.sum(wG*PwTw2.real) plt.plot(w2, wG, c='r') # 画热导的权重曲线 print(G_) w2 = w2[2:] H1z = H1z[2:] PwTw2 = PwTw2[2:] wC = w2/H1z/(w2/H1z).sum() C_ = np.sum(wC*PwTw2.imag/w2) plt.twinx() plt.plot(w2, wC, c='b') # 画热容的权重曲线 print(C_) plt.show() ``` ``` 1.0217989734791504 19.80496304275252 ``` ![权重曲线图](https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/d00d9084e07d4203a9cfba4f6a6275f8~tplv-k3u1fbpfcp-zoom-1.image) $G$需要选取适当的高频截断点,$C$需要选择一定频谱范围,精度与最小二乘法差不多。因为使用了加权,是有偏估计。还有不稳定,选择不恰当的参数会使误差会很大。操作起来还会很麻烦。 花了那么多精力计算和整理,这段文字还是保留下来吧。提示以后不要用随便想出来的算法,真的想用也至少得先去验证一下,跟常规算法的性能比较一下再应用。 我不想在CSDN上写博客了,贴张图都很麻烦。我想在jupyter notebook上写,再挂到gitee上供大家浏览。 另外PID仿真程序的代码已经写好了,但没有什么好说的,我有空会发到gitee,有需要可以联系我。