重要改正 前面的matlab程式存在重大問題

2021-10-01 12:06:01 字數 3875 閱讀 7076

這一篇部落格非常重要,因為這篇部落格是為了糾正之前的幾篇關於pid的matlab程式設計的錯誤

錯誤之處:

1.每一次的取樣週期內,也就是每一次的for迴圈內,反饋的訊號在時序上應該是屬於這一次取樣週期的,也就是反饋的訊號應該是屬於本次迴圈。之前的犯的錯誤就是每一次取樣週期(for迴圈)內都是將上一次取樣週期(for迴圈)內的輸出作為反饋訊號然後進行求差值,這是不對的。

在程式上的體現就是:

erro=

y_d(k)

- y(k)//對的

erro=

y_d(k)

- y(k-

1)//錯的

上面那個就是對的,輸入的參考訊號和反饋的訊號在時序上因該是一致的,都屬於當前取樣時刻。而下面那個就是錯的,因為這裡的反饋訊號用的是上乙個取樣週期內的輸出。其實這個問題我最早在學習自控時就想過,只是當時沒管他。

而採用erro=y_d(k) - y(k-1)這種錯的形式就會導致erro這個值慢慢就錯了,相應導致此時的pid輸出錯誤,後面就引起一系列的錯誤。

2.因為1的原因,所以控制開始的時候初始反饋訊號不能像我之前寫的直接令其等於0,而是應該根據物件模型算這個初始反饋訊號,再去求差值。

3.綜上所述,在for迴圈裡面首先應該幹的事情是先根據模型算此時此刻的反饋,然後求差值,然後計算pid輸出。而不是一來就利用上一時刻的輸出來求差值然後計算pid輸出,然後計算模型輸出,之前犯的錯誤就是這麼造成的。

修改的程式應該為:

for k=1:

1:200time

(k)=k*ts;

%儲存時間,用於後面畫圖

y(k)=

-den(2

)*y_1+

num(2)

*pi_out_5;

%控制物件

y_feed=

y(k)

;erro

(k)=

y_d(k)

- y_feed;

erro_middle =

(erro

(k)+ erro_1 )/2

;if m==

0%採用變速積分pid

if(abs

(erro

(k))

)>

1beta

(k)=0;

endif

(abs

(erro

(k))

)<=1&

(abs

(erro

(k))

)>

0.6beta

(k)=(1

-abs

(erro

(k)))/

0.4;

endif

(abs

(erro

(k))

)<=

0.6beta

(k)=1;

end

endif m==

1%不採用積分分離

beta

(k)=1;

enderro_total = erro_total + erro_middle*ts;

pi_out =

erro

(k)*k_p+k_d*

(erro

(k)-erro_1 )

/ts + k_i*

beta

(k)*erro_total;

%對pid的輸出進行限幅

if pi_out>=

10 pi_out =10;

endif pi_out<=-10

pi_out =-10

; end

%更新系統輸出狀態

y_1=

y(k)

;%更新pid輸出狀態

pi_out_5=pi_out_4;

pi_out_4=pi_out_3;

pi_out_3=pi_out_2;

pi_out_2=pi_out_1;

pi_out_1=pi_out;

%更新訊號差值狀態

erro_1=

erro

(k);

end

對比之前的錯誤程式:

for k=1:

1:200time

(k)=k*ts;

%儲存時間,用於後面畫圖

y(k)=

-den(2

)*y_1+

num(2)

*pi_out_5;

%控制物件

y_feed=

y(k)

;erro

(k)=

y_d(k)

- y_feed;

erro_middle =

(erro

(k)+ erro_1 )/2

;if m==

0%採用變速積分pid

if(abs

(erro

(k))

)>

1beta

(k)=0;

endif

(abs

(erro

(k))

)<=1&

(abs

(erro

(k))

)>

0.6beta

(k)=(1

-abs

(erro

(k)))/

0.4;

endif

(abs

(erro

(k))

)<=

0.6beta

(k)=1;

end

endif m==

1%不採用積分分離

beta

(k)=1;

enderro_total = erro_total + erro_middle*ts;

pi_out =

erro

(k)*k_p+k_d*

(erro

(k)-erro_1 )

/ts + k_i*

beta

(k)*erro_total;

%對pid的輸出進行限幅

if pi_out>=

10 pi_out =10;

endif pi_out<=-10

pi_out =-10

; end

y(k)=

-den(2

)*y_1+

num(2)

*pi_out_5;

%控制物件

y_feed=

y(k)

;%更新系統輸出狀態

y_1=

y(k)

;%更新pid輸出狀態

pi_out_5=pi_out_4;

pi_out_4=pi_out_3;

pi_out_3=pi_out_2;

pi_out_2=pi_out_1;

pi_out_1=pi_out;

%更新訊號差值狀態

erro_1=

erro

(k);

end

發現就是下面的這句話順序問題,如果你放在最後,就有問題了,此時你每次for迴圈開始用的y_feed都是上一次for的,而如果你放在開頭,則每次for迴圈開始用的y_feed都是這一次的,就不存在時序問題,所以要注意。

y

(k)=

-den(2

)*y_1+

num(2)

*pi_out_5;

%控制物件

y_feed=

y(k)

;