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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM