用神經網路來估計PID控制器引數?(附核心程式碼)

前面的文章說了PID的本質,原來PID不止只能做控制器,還能做融合訊號的功能,有興趣的朋友可以去看看——你真的瞭解PID嗎?PID的本質純乾貨分析。或者點選我的頭像在我釋出的文章裡也可以檢視。

今天來說說PID控制器已經設計出來了,那怎麼來調引數呢?調參是自動控制工程師頭疼的事情,PID又是無模型的控制器,怎麼確認初始引數都不好說。作為一個自動控制工程師,以懶……不對,以提高效率為原則,那何不讓機器自己去調,工程師最後來檢查引數效果就行了唄。

本文介紹的是整定PID控制器的引數,不會涉及到PID控制的理論,也不會講解PID控制過程(頭條上有很多優秀的文章有講解)。本文會從一個專案來說明怎麼讓機器自己去調節PID,即純粹的引數調節。機器自整定引數的框圖如下:

用神經網路來估計PID控制器引數?(附核心程式碼)

我們主要是實現PID控制器前面的引數估計器,採用最近比較火的BP神經網路(關於BP神經網路朋友們可以自己去了解,目前是機器學習的熱門方向)來整定引數。為什麼選擇神經網路,因為神經網路在理論上可以擬合任意非線性函式。

建立神經網路

我們建立一個最簡單的神經網路,總共三層——輸入層、隱藏層和輸出層。輸入層總共3個節點,隱藏層5個節點,輸出層3個節點。輸入層的輸入訊號分別為目標量x1,量測量x2和誤差x3;輸出層的輸出為PID的三個引數(輸出層的節點個數取決於PID引數個數,PI控制就只有2個節點);神經網路的隱藏層讀者朋友們可以自己設定層數和節點數,看看多少層多少節點是比較合適的。下面是神經網路的結構圖。

用神經網路來估計PID控制器引數?(附核心程式碼)

這個神經網路要實現的功能一目瞭然,當輸入x1和x2相等,x3為0時,所有輸出y會收斂到一組固定值。

神經網路輸入層的輸入為:x;

神經網路隱藏層的輸入為:c=x*w0;

神經網路隱藏層的輸出為:c‘=f(c)=tanh(c);

神經網路輸出層的輸入為:c’‘=c’*w1;

神經網路輸出層的輸出為:y=f(c‘’)=tanh(c‘’);

隱藏層的啟用函式採用tanh函式,tanh函式的定義域為R,值域為(-1,1),影象穿過原點,設f(x)=tanh(x),f(x)的導數為1-f(x)^2。tanh函式及其影象如下:

用神經網路來估計PID控制器引數?(附核心程式碼)

輸出層的啟用函式這裡要考慮一下了,

由於PID引數都為非負值

,所以採用的啟用函式的值域需要在(0,+∞),這裡我們採用g(x)=0。5*(1+tanh(x)),非負的tanh函式。g(x)就是把tanh沿y軸向上平移1個單位的距離,然後再把值域限制到(0,1)。由於PID引數範圍可能不在(0,1),這裡讀者朋友們可以自己調節輸出的值域。

神經網路的傳播過程

損失函式取為:e=0。5*(x1-x2)^2。x1為目標量,x2為量測量。

用梯度下降法來最佳化各層的加權係數,我們就需要計算損失函式對加權係數向量的偏導數,顯然這是一個很複雜的函式,但是,對

複合函式的求導我們擁有鏈式法則

這一神奇的工具(感謝偉大的數學家牛某某,萊某某),問題就迎刃而解了。由導數鏈式法則我們可以得到:

用神經網路來估計PID控制器引數?(附核心程式碼)

其中w1為隱藏層到輸出層的加權係數向量,u為PID輸出量,所以第二項x2對u的偏導是未知的,和被控物件的傳遞函式有關,但是我們可以用符號函式代替,即PID輸出量和量測量的變化趨勢是一致,保證極性正確,計算誤差可以用學習率來調整。其它的偏導數都可以直接得到,在此不贅述。同理w0還要多傳幾層。

用神經網路來估計PID控制器引數?(附核心程式碼)

神經網路測試

這裡我模擬一個轉速控制系統的過程。系統的開環傳遞函式為:

用神經網路來估計PID控制器引數?(附核心程式碼)

由於被控物件不同,我的學習率設定的是0。01,這裡我先設定輸出節點只有一個,即先只訓練P值。我們給個階躍訊號做系統的輸出測試。下面是訓練結果:

用神經網路來估計PID控制器引數?(附核心程式碼)

可以發現P在0。86左右收斂,我們在系統上測試一下P=0。86是否合適。

用神經網路來估計PID控制器引數?(附核心程式碼)

看起來還可以啊,那讓我們把3個引數都加入估計。

用神經網路來估計PID控制器引數?(附核心程式碼)

P值大約收斂到0。75,I值為0,D值為0。37。再來看看新引數下的階躍響應:

用神經網路來估計PID控制器引數?(附核心程式碼)

嗯,這個引數也可以用。我們達到了想要的結果,說明機器透過神經網路可以整定PID引數。機器:哼,愚蠢的人類,要你們何用。

最後的話

實際上,我在除錯這個網路的時候出現過很多次控制發散的結果,我發現初始權值引數對控制的發散起到了很關鍵的作用,所以調好一部分權值引數後就儲存下來,下次接著調,才能保證控制不發散。學習率也是一個很重要的引數,剛開始建議使用較小的學習率,後面等穩定了再把學習率加大。

在工程應用中,更多的是靠經驗法人為除錯PID引數,實際上從很多角度來說都比用神經網路這種方式要快,你說你調參都有大量經驗了,要機器自己去調節幹嘛,還要花這麼多時間來編寫神經網路?你說你一點經驗沒有,那怎麼建立起引數除錯的神經網路?所以,在工程應用上,更多的還是靠經驗法或者是公式法,下個篇章我將描述用公式法如何除錯PID的引數。

附錄:神經網路核心程式碼MATLAB格式

function [kp,ki,kd,w0_out,w1_out] = bp_get_pid_paras(target,current,integ,delE,pidout,k)persistent last_current;persistent last_pidout;persistent w0;persistent w1;%神經網路輸出為 pid引數N=5; %隱藏層N個節點Mi=3; %輸出層M個節點Mo=3; %輸出層M個節點ng = 0。00001;%學習率if k == 2 % 初始化神經網路% load w0_save_pid; %直接用儲存好的引數% load w1_save_pid;% w0 = w0_save;% w1 = w1_save; w0 = 2*rand(N,Mi) - 1; w1 = 2*rand(Mo,N) - 1; last_current = current; last_pidout = pidout;enderror = target - current;x = [target,current,error];% 神經網路輸入l0 = x;x1 = l0*w0‘; % 隱藏層輸入l1 = tanh(x1);% 隱藏層輸出x2 = w1*l1’;% 輸出層輸入for i=1:Mo l2(i) = exp(x2(i))/(exp(x2(i))+exp(-x2(i)));%輸出層輸出end% 輸出層temp = (exp(x2)+exp(-x2))。^2;for i=1:Mo dl2_x2(i) = 2/temp(i);enddpid = [error; integ; delE];sig = sign((current - last_current)/(pidout - last_pidout + 0。0001));last_current = current;last_pidout = pidout;for i=1:Mo l2_del(i) = -error * sig * dpid(i) * dl2_x2(i);end% 隱藏層temp = tanh(x1)。^2;dl1_x1 = (1 - temp);l1_del = dl1_x1。*(l2_del * w1);% 更新系數w1 = w1 - ng*l2_del‘*l1;w0 = w0 - ng*l1_del’*l0;% 更新PID引數kp=l2(1);ki=l2(2);kd=l2(3);% 供主程式檢視w0_out = w0;w1_out = w1;end