BP神经网络实现NTC热敏电阻非线性校准

某型号热敏电阻温度-阻值有如下关系,根据表数据,通过BP算法找出其映射关系。

电阻(KΩ)温度(℃)
72.686-20
69.1102-19
65.7325-18
62.5405-17
59.5232-16
56.6698-15
53.9705-14
51.4161-13
48.998-12
46.7082-11
44.539-10
42.4835-9
40.535-8
38.6874-7
36.9349-6
35.272-5
33.6937-4
32.1952-3
30.772-2
29.42-1
28.13510
26.91361
25.75222
24.64753
23.59644
22.5965
21.64376
20.73697
19.8738
19.059
18.265610
17.517811
16.804812
16.124613
15.475714
14.856415
14.265316
13.700817
13.161818
12.646819
12.154720
11.684321
11.234722
10.804723
10.393524
1025
9.623526
9.263127
8.918128
8.587729
8.271330
7.968131
7.677632
7.399133
7.132234
6.876335
6.630836
6.395337
6.169438
5.952539
5.744440
5.544641
5.352742
5.168443
4.991344
4.821245
4.657746
4.500547
4.349448
4.204149
4.064450
3.929951
3.800652
3.676153
3.556354
3.44155
3.329956
3.22357
3.1258
3.020859
2.925160
2.83361
2.744262
2.658563
2.57664
2.496465
2.419666
2.345567
2.27468
2.20569
2.138570
2.074271
2.012272
1.952373
1.894474
1.838575
1.784576
1.732477
1.681978
1.633279
1.586180
1.540681
1.496682
1.45483
1.412884
1.37385
1.334486
1.297187
1.26188
1.226189
1.192390
1.159591
1.127892
1.097193
1.067494
1.038695
1.010796
0.983697
0.957498
0.93299
0.9074100
0.8836101
0.8604102
0.838103
0.8162104
0.7951105
0.7746106
0.7548107
0.7355108
0.7168109
0.6986110
0.681111
0.6639112
0.6473113
0.6312114
0.6155115
0.6003116
0.5855117
0.5712118
0.5572119
0.5437120
编程步骤
  • 加载数据、并对数据进行归一化处理。
    把数据映射到0~1范围之内进行处理,这样可以使算法能够快速收敛。
# 加载样本数据 格式:电阻值(K)   温度值(℃)
dat = np.loadtxt('trainData.txt')

# 获取电阻数据
R = dat[:,0]
# 获取温度数据
T = dat[:,1]

# 分别对R、T归一化处理
R_K = R.max()-R.min()
R_B = R.min()

T_K = T.max()-T.min()
T_B = T.min()

R = (R - R_B)/R_K
T = (T - T_B)/T_K
  • 定义bp网络结构
    在这里插入图片描述
    如图所示,含有一个隐含层的神经网络,Wh、Wo、Bh、Bo分别表示隐含层,输出层权值与偏置。输入层不参与计算,由于输入只有一个特征,所以三个输入端均输入R。
    由图可知,隐含层三个神经元,每个神经元有三个输入端,则隐含层权值Wh向量应改是一个3X3矩阵。隐含层偏置项Bh为3x1矩阵。同理可得输出层权值向量Wo为1X3矩阵,偏差Bo为1X1矩阵。

  • 网络参数初始化
    bp网络权值初始化很重要,过大或过小都会对模型训练产生影响,根据经验一般选取在-2.4/F~2.4/F之间,F为网络输入端个数。

# 定义bp网络结构

# 初始化隐含层权值向量
W_h = np.array([[-0.8,1.2,1.6],[1.3,-1.5,1.9],[1.8,-1.4,1.6]])
B_h = np.array([[-0.1],[-0.3],[0.4]])

# 初始化输出层权值向量
W_o = np.array([[1.1,-1.9,1.7]])
B_o = np.array([0.1])

  • 定义激活函数
    本例中所有神经元均采用sigmoid函数作为激活函数
    在这里插入图片描述
# 定义激活函数
def sigmoid(x):
    s = 1.0 / (1 + 1 / np.exp(x))
    return s

#sigmoid求导
def d_sigmoid(x):
    s = sigmoid(x)
    ds = s * (1 - s)
    return ds
  • 信号正向传播

设输入层激励输入为:
z i = w i R ( w i 为 输 入 层 权 值 [ 1 , 1 , 1 ] ) z^{i} =w^{i}R \qquad (w^{i} 为输入层权值[1,1,1]) zi=wiR(wi[1,1,1])

由于输入层不参与运算所以激励输出为:
y i = z i = R y^{i} = z^{i} =R yi=zi=R

隐含层激励输入为:
z h = w h y i z^{h} =w^{h}y^{i} zh=whyi
隐含层激励输出为:
y h = s i g m o i d ( z h + B h ) y^{h} =sigmoid(z^{h}+B^{h}) yh=sigmoid(zh+Bh)

同理得输出层激励输入、输出为:
z o = w o y h z^{o} =w^{o}y^{h} zo=woyh
y o = s i g m o i d ( z o + B o ) y^{o} =sigmoid(z^{o}+ B^{o}) yo=sigmoid(zo+Bo)

  #输入层激励输入  输入层不作计算,设输入层权值为常数1
  z_i = np.ones((3,1))*input
  # 输入层激励输出
  y_i = z_i
  
  #隐含层激励输入 3x3矩阵乘以3x1矩阵
  z_h = np.dot(W_h,np.array(y_i))
  #隐含层激励输出
  y_h = sigmoid(z_h+B_h)

  #输出层激励输入 1x3矩阵乘以3x1矩阵
  z_o = np.dot(W_o,np.array(y_h))
  #输出层激励输出
  y_o = sigmoid(z_o+B_o)
  
  • 误差信号反向传播
    输入一个R后得到实际输出y,通过计算实际输出与期望输出的误差,将误差信号逐层传递到输入端,传递过程中调整每层的权值向量。
    参考bp网络误差反向传播相关推导

# 误差反向传播

# 输出层误差权值向量
e_o = (y_o - lable)*d_sigmoid(z_o)
# 输出层权值调整
dW_o = dl()*dW_o +  Learning()*(np.dot(e_o,y_h.T))
W_o = W_o - dW_o
B_o = B_o - Learning()*e_o

# 隐含层误差权值向量3x1
e_h = np.dot(W_o.T,e_o)*d_sigmoid(z_h)
# 隐含层权值调整
dW_h = dl()*dW_h + Learning()*(np.dot(e_h,y_i.T))
W_h = W_h - dW_h
B_h = B_h - Learning()*e_h

# 计算误差
e = e + ((y_o-lable)*(y_o-lable))

Learning() 返回一个常数,称为学习速率,该值选取很重要,值小收敛慢,值大会不稳定,选取时应根据经验不断试验。
代码中dl()*dW_h称为动量项,可以解决收敛速度慢与陷入局部最小值问题。

  • 完整代码
import numpy as np
import matplotlib.pyplot as plt

# R25=10k B25/50=3470 NTC热敏电阻特性数据表

# 加载样本数据 格式:电阻值(K)   温度值(℃)
dat = np.loadtxt('trainData.txt')

# 数据归一化处理
R = dat[:,0]
T = dat[:,1]

R_K = R.max()-R.min()
R_B = R.min()

T_K = T.max()-T.min()
T_B = T.min()


R = (R - R_B)/R_K
T = (T - T_B)/T_K


# 定义bp网络结构

# 初始化隐含层权值向量
W_h = np.array([[-0.8,1.2,1.6],[1.3,-1.5,1.9],[1.8,-1.4,1.6]])
B_h = np.array([[-0.1],[-0.3],[0.4]])

# 初始化输出层权值向量
W_o = np.array([[1.1,-1.9,1.7]])
B_o = np.array([0.1])

dW_h = np.array([[-0.8,1.2,1.6],[1.3,-1.5,1.9],[1.8,-1.4,1.6]])
dW_o = np.array([[1.1,-1.9,1.7]])


# 定义激活函数
def sigmoid(x):
    s = 1.0 / (1 + 1 / np.exp(x))
    return s

#sigmoid求导
def d_sigmoid(x):
    s = sigmoid(x)
    ds = s * (1 - s)
    return ds

# 定义学习速率
def Learning():
    return 0.004

# 动量项
def dl():
    if n >10:
        return 0.9999999 - 0.98**(n+1)
    return 0

# 迭代次数
n = 0;

# 全局误差
E = [];

# 样本个数
datLen = dat.shape[0]


# 系统参数调整
def update():

    global E,W_o,W_h,B_h,B_o,dW_h,dW_o
    e = 0
    for i in range(datLen):

        # 输入数据(电阻值)
        input = R[i]

        # 期望输出(温度值)
        lable = T[i]

        # 信号正向传播

        #输入层激励输入  输入层不作计算,设输入层权值为常数1
        z_i = np.ones((3,1))*input
        #输入层激励输出
        # y_i = sigmoid(z_i)
        y_i = z_i


        #隐含层激励输入 3x3矩阵乘以3x1矩阵
        z_h = np.dot(W_h,np.array(y_i))
        #隐含层激励输出
        y_h = sigmoid(z_h+B_h)

        #输出层激励输入 1x3矩阵乘以3x1矩阵
        z_o = np.dot(W_o,np.array(y_h))
        #输出层激励输出
        y_o = sigmoid(z_o+B_o)


        # 误差反向传播

        # 输出层误差权值向量
        e_o = (y_o - lable)*d_sigmoid(z_o)
        # 输出层权值调整
        dW_o = dl()*dW_o +  Learning()*(np.dot(e_o,y_h.T))
        W_o = W_o - dW_o
        B_o = B_o - Learning()*e_o

        # 隐含层误差权值向量3x1
        e_h = np.dot(W_o.T,e_o)*d_sigmoid(z_h)
        # 隐含层权值调整
        dW_h = dl()*dW_h + Learning()*(np.dot(e_h,y_i.T))
        W_h = W_h - dW_h
        B_h = B_h - Learning()*e_h

        # 计算误差
        e = e + ((y_o-lable)*(y_o-lable))

    err = np.sqrt(e/datLen)
    E.append(err[0])
    return  err


# 测试
def test(r):
    # 信号正向传播
    
    #输入层激励输入  输入层不作计算,设输入层权值为常数1

    z_i = np.ones((3,1))*r

    #输入层激励输出
    # y_i = sigmoid(z_i)
    y_i = z_i

    #隐含层激励输入 3x3矩阵乘以3x1矩阵
    z_h = np.dot(W_h,np.array(y_i))
    #隐含层激励输出

    y_h = sigmoid(z_h+B_h)
    #输出层激励输入 1x3矩阵乘以3x1矩阵
    z_o = np.dot(W_o,np.array(y_h))

    #输出层激励输出
    y_o = sigmoid(z_o+B_o)

    return y_o



if __name__ == "__main__":
    # 训练
    for i in range(930):
        n = i
        err = update()
        print("err=",err,"n=",n)


    plt.rcParams['font.sans-serif']=['SimHei']
    plt.rcParams['axes.unicode_minus'] = False
    plt.xlabel("迭代次数")
    plt.ylabel("标准差")
    plt.plot(E)
    plt.show()

    
    # 测试
    # 预测值
    y=[];

    for i in range(datLen):
        y_temp = test(R[i])*T_K+T_B
        y.append(y_temp[0])


    # dat_R = dat[:,0]
    # dat_T = dat[:,1]
    # plt.plot(dat_R ,dat_T ,color="red",label='R-T特性曲线')
    # plt.plot(dat_R,y,label='拟合曲线')
    # plt.legend()
    # plt.show()
  • 运行结果
    迭代930次后,标准差为0.01
    在这里插入图片描述
    在这里插入图片描述
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值