python实现一般最小二乘系统辨识方法

问题:

对于一个未知参数的系统,往往需要用到系统辨识的方法,例如对于一个单输入单输出系统:

        Z(k)+a1*Z(k-1)+a2*Z(k-2)=b1*U(k-1)+b2*U(k-2)+V(k)

        其中:V(k)=c1*v(k)+c2*v(k-1)+c3*v(k-3)

输入信号采用四阶幅值为1的M序列,高斯噪声v(k)均值为0,方差为0.1。

假设真值为a1=1.6,a2=0.7,b1=1.0,b2=0.4,c1=1.0,c2=1.6,c3=0.7。需要对以上参数进行辨识。

方法:

一般最小二乘法是系统辨识中最简单的辨识方法之一,其MATLAB实现方法十分简单,我发现网上一大把,所以我决定“翻译”一个python版的一般最小二乘辨识方法供读者参考。

本文用到的库:

import numpy as np
import matplotlib.pyplot as plt
from operator import xor
from numpy.linalg import inv

 

M序列的产生:

在python中,M序列的产生方法与matlab类似,先产生随机数,然后采用四阶移位寄存器滤波变换,得到我们想要的M序列。

#M序列产生
L=16
#设置M序列周期
#定义初始值
y=np.zeros(L)
u=np.zeros(L)
y1=1
y2=1
y3=1
y4=0
for i in range(0,L):
    x1=xor(y3,y4)  
    x2=y1 
    x3=y2  
    x4=y3 
    y[i]=y4  
    if  y[i]>0.5:
        u[i]=-1  
    else:
        u[i]=1   
    y1=x1
    y2=x2
    y3=x3
    y4=x4     
plt.figure(num=2)
x=np.linspace(0,15,16)
plt.bar(x,u,width=0.1)
plt.title('输入信号M序列')

高斯分布噪声:

这里采用的是random库中的函数,可以看到,我们设置的均值为0,方差为0.1。

 #产生一组16个N(0,1)的高斯分布的随机噪声
 mu=0
 sigma=0.1
 samplenum=16
 n=np.random.normal(mu,sigma,samplenum) 
 plt.figure(num=1)
 plt.plot(n)
 plt.title("高斯分布随机噪声")

 最小二乘辨识程序:

#最小二乘辨识过程
z=np.zeros(16)

for k in range(2,15):   
    z[k]=-1.6*z[k-1]-0.7*z[k-2]+1.0*u[k-1]+0.4*u[k-2]+1.0*n[k]+1.6*n[k-1]+0.7*n[k-2] 
    
plt.figure(num=3) 
plt.bar(x,z,width=0.1)  
plt.title('输出观测值')    

H=np.array([[-z[1],-z[0],u[1],u[0]],[-z[2],-z[1],u[2],u[1]],[-z[3],-z[2],u[3],u[2]],[-z[4],-z[3],u[4],u[3]],[-z[5],-z[4],u[5],u[4]],[-z[6],-z[5],u[6],u[5]],[-z[7],-z[6],u[7],u[6]],[-z[8],-z[7],u[8],u[7]],[-z[9],-z[8],u[9],u[8]],[-z[10],-z[9],u[10],u[9]],[-z[11],-z[10],u[11],u[10]],[-z[12],-z[11],u[12],u[11]],[-z[13],-z[12],u[13],u[12]],[-z[14],-z[13],u[14],u[13]]])
Z=np.array([z[2],z[3],z[4],z[5],z[6],z[7],z[8],z[9],z[10],z[11],z[12],z[13],z[14],z[15]]) 

In_1=np.transpose(H)
In_2=np.dot(In_1,H)
In_3=inv(In_2)
In_4=np.dot(In_3,In_1)
c=np.dot(In_4,Z)

分离参数:

#分离参数并显示
a1=c[0] 
a2=c[1]
b1=c[2]
b2=c[3] 
print("a1的值是:",a1)
print("a2的值是:",a2)
print("b1的值是:",b1)
print("b2的值是:",b2)

注意:

由于在python中plt的库是不支持中文的,所以要加上这些代码,保证输出的图片标题的中文显示正常。

#显示中文字体
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负号

结果:

在网上找了半天python画针状图的资料,发现没有。。所以强行用瘦了的柱状图表示针状图了。

 

总结:

可以看出Python写的系统辨识误差还是有一些的,不过也是受到一般最小二乘参数辨识方法的限制,如果采用递推最小二乘,增广最小二乘等方法可能会进一步提高准确性。笔者尝试过递推最小二乘,但是与MATLAB相比,其代码量大大增加,因此在系统辨识方法上,不建议都用Python来写,MATLAB是个不错的选择。当然,喜欢写python的话,这都不是问题。

代码全文:

 

 1 # -*- coding: utf-8 -*-
 2 """
 3 Created on Wed Sep 20 16:11:27 2017
 4 @author: Hangingter
 5 """
 6 #一般最小二乘辨识
 7 
 8 #导入相应科学计算的包
 9 import numpy as np
10 import matplotlib.pyplot as plt
11 from operator import xor
12 from numpy.linalg import inv
13 
14 #显示中文字体
15 plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
16 plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
17 #产生一组16个N(0,1)的高斯分布的随机噪声
18 mu=0
19 sigma=0.1
20 samplenum=16
21 n=np.random.normal(mu,sigma,samplenum) 
22 plt.figure(num=1)
23 plt.plot(n)
24 plt.title("高斯分布随机噪声")
25 #M序列产生
26 L=16
27 #设置M序列周期
28 #定义初始值
29 y=np.zeros(L)
30 u=np.zeros(L)
31 y1=1
32 y2=1
33 y3=1
34 y4=0
35 for i in range(0,L):
36     x1=xor(y3,y4)  
37     x2=y1 
38     x3=y2  
39     x4=y3 
40     y[i]=y4  
41     if  y[i]>0.5:
42         u[i]=-1  
43     else:
44         u[i]=1   
45     y1=x1
46     y2=x2
47     y3=x3
48     y4=x4     
49 plt.figure(num=2)
50 x=np.linspace(0,15,16)
51 plt.bar(x,u,width=0.1)
52 plt.title('输入信号M序列')
53 #最小二乘辨识过程
54 z=np.zeros(16)
55 
56 for k in range(2,15):   
57     z[k]=-1.6*z[k-1]-0.7*z[k-2]+1.0*u[k-1]+0.4*u[k-2]+1.0*n[k]+1.6*n[k-1]+0.7*n[k-2] 
58     
59 plt.figure(num=3) 
60 plt.bar(x,z,width=0.1)  
61 plt.title('输出观测值')    
62 
63 H=np.array([[-z[1],-z[0],u[1],u[0]],[-z[2],-z[1],u[2],u[1]],[-z[3],-z[2],u[3],u[2]],[-z[4],-z[3],u[4],u[3]],[-z[5],-z[4],u[5],u[4]],[-z[6],-z[5],u[6],u[5]],[-z[7],-z[6],u[7],u[6]],[-z[8],-z[7],u[8],u[7]],[-z[9],-z[8],u[9],u[8]],[-z[10],-z[9],u[10],u[9]],[-z[11],-z[10],u[11],u[10]],[-z[12],-z[11],u[12],u[11]],[-z[13],-z[12],u[13],u[12]],[-z[14],-z[13],u[14],u[13]]])
64 Z=np.array([z[2],z[3],z[4],z[5],z[6],z[7],z[8],z[9],z[10],z[11],z[12],z[13],z[14],z[15]]) 
65 
66 In_1=np.transpose(H)
67 In_2=np.dot(In_1,H)
68 In_3=inv(In_2)
69 In_4=np.dot(In_3,In_1)
70 c=np.dot(In_4,Z)
71 
72 #分离参数并显示
73 a1=c[0] 
74 a2=c[1]
75 b1=c[2]
76 b2=c[3] 
77 print("a1的值是:",a1)
78 print("a2的值是:",a2)
79 print("b1的值是:",b1)
80 print("b2的值是:",b2)

 

参考:

MATLAB版的系统辨识一般最小二乘方法:

http://blog.csdn.net/sinat_20265495/article/details/51426537

 

posted @ 2017-09-22 15:29  hangingter  阅读(3523)  评论(0编辑  收藏  举报