• 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

  • 相关阅读:
    Spring Batch 中的 chunk
    群晖(Synology)NAS 安装 MongoDB
    CentOS 上安装 Sonatype Nexus 仓库
    Jenkins pipeline Git 检出的 Step
    Npm 使用 Nexus 仓库的登录时候出现授权的问题
    Jenkins pipeline 如何到子文件中去执行命令
    Sonatype Nexus 管理员初始密码
    关于tkintergui窗体中循环周期性执行某段代码的方法记录
    关于windows服务器修改hosts文件不生效的问题原因分析
    关于Centos8.X操作系统不能使用yum源的解决方法
  • 原文地址:https://www.cnblogs.com/Hangingter/p/7575167.html
Copyright © 2020-2023  润新知