亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

python實(shí)現(xiàn)PID溫控算法的示例代碼

 更新時間:2024年01月05日 16:48:20   作者:天才小C  
PID算法是一種常用的控制算法,用于調(diào)節(jié)和穩(wěn)定控制系統(tǒng)的輸出,這篇文章主要為大家詳細(xì)介紹了如何使用Python實(shí)現(xiàn)pid溫控算法,需要的可以參考下

PID算法介紹

PID算法是一種常用的控制算法,用于調(diào)節(jié)和穩(wěn)定控制系統(tǒng)的輸出。

PID代表比例(Proportional)、積分(Integral)和微分(Derivative)

比例(Proportional):比例控制是根據(jù)當(dāng)前誤差的大小來產(chǎn)生輸出的一部分。誤差是指期望值與實(shí)際值之間的差異。比例控制通過將誤差乘以一個比例常數(shù)來產(chǎn)生輸出,該輸出與誤差成正比。比例控制的作用是使系統(tǒng)更快地響應(yīng)誤差,但可能會導(dǎo)致系統(tǒng)產(chǎn)生超調(diào)或震蕩。

積分(Integral):積分控制是根據(jù)誤差的累積來產(chǎn)生輸出的一部分。積分控制通過將誤差累積起來,并乘以一個積分常數(shù)來產(chǎn)生輸出,該輸出與誤差的積分成正比。積分控制的作用是消除系統(tǒng)的穩(wěn)態(tài)誤差,即系統(tǒng)在長時間內(nèi)無法達(dá)到期望值的情況。

微分(Derivative):微分控制是根據(jù)誤差的變化率來產(chǎn)生輸出的一部分。微分控制通過將誤差的變化率乘以一個微分常數(shù)來產(chǎn)生輸出,該輸出與誤差的微分成正比。微分控制的作用是抑制系統(tǒng)的過沖和震蕩,使系統(tǒng)更加穩(wěn)定。

PID算法通過將這三個部分的輸出相加,得到最終的控制輸出。每個部分的權(quán)重可以通過調(diào)整相應(yīng)的常數(shù)來控制。PID算法的目標(biāo)是使系統(tǒng)的輸出盡可能接近期望值,并在系統(tǒng)受到擾動時能夠快速恢復(fù)到期望狀態(tài)。

PID算法廣泛應(yīng)用于工業(yè)控制、自動化系統(tǒng)、機(jī)器人控制、溫度控制等領(lǐng)域。它是一種簡單而有效的控制算法,可以根據(jù)具體的系統(tǒng)和需求進(jìn)行調(diào)整和優(yōu)化。

PID參數(shù)作用

P參數(shù)控制器的輸出是與偏差(誤差)成比例的,即控制器輸出隨著系統(tǒng)的偏差增加而增加。P參數(shù)的作用是限制系統(tǒng)的上升時間和穩(wěn)定性,但過大的P值會導(dǎo)致震蕩和不穩(wěn)定的轉(zhuǎn)移函數(shù)。

I參數(shù)控制器的輸出是與偏差的積分成比例的,即控制器輸出隨著時間的累積而增加。

I參數(shù)的作用是消除系統(tǒng)的靜態(tài)誤差,即系統(tǒng)的偏差將在時間推移中逐漸消失,但過大的I值會導(dǎo)致超調(diào)和系統(tǒng)不穩(wěn)定。

D參數(shù)控制器的輸出是偏差的微分與時間成比例的,即控制器輸出隨著偏差的變化率的增加而增加。作用是降低系統(tǒng)的超調(diào)和減少震蕩,但過大的D值可能導(dǎo)致噪聲的放大或沒有響應(yīng)。

三個參數(shù)的綜合作用是控制系統(tǒng)的響應(yīng)速度(上升時間)、穩(wěn)定性和精度。 調(diào)整PID控制器的參數(shù)可以幫助控制系統(tǒng)達(dá)到更高的響應(yīng)速度和精度,同時保持系統(tǒng)的穩(wěn)定性。通常,通過試驗(yàn)和調(diào)整這些參數(shù),可以根據(jù)控制系統(tǒng)需求得到最佳的控制響應(yīng)。

簡單來說就是:

  • P <—> 比例控制<—>對當(dāng)前狀態(tài)的處理<—>提高響應(yīng)速度,過大則無靜差
  • I <—> 微分控制<—>對過去狀態(tài)的處理<—>用于減小靜差
  • D <—> 積分控制<—>對將來狀態(tài)的預(yù)測<—>用于抑制震蕩

位置式PID

位置式PID是當(dāng)前系統(tǒng)的實(shí)際位置,與你想要達(dá)到的預(yù)期位置的偏差,進(jìn)行PID控制

因?yàn)橛姓`差積分 ∑e(i) 一直累加,也就是當(dāng)前的輸出u(k)與過去的所有狀態(tài)都有關(guān)系,用到了誤差的累加值;

輸出的u(k)對應(yīng)的是執(zhí)行機(jī)構(gòu)的實(shí)際位置,一旦控制輸出出錯(控制對象的當(dāng)前的狀態(tài)值出現(xiàn)問題 ),u(k)的大幅變化會引起系統(tǒng)的大幅變化

并且位置式PID在積分項(xiàng)達(dá)到飽和時,誤差仍然會在積分作用下繼續(xù)累積,一旦誤差開始反向變化,系統(tǒng)需要一定時間從飽和區(qū)退出,所以在u(k)達(dá)到最大和最小時,要停止積分作用,并且要有積分限幅和輸出限幅

所以在使用位置式PID時,一般我們直接使用PD控制,而位置式 PID 適用于執(zhí)行機(jī)構(gòu)不帶積分部件的對象,如舵機(jī)和平衡小車的直立和溫控系統(tǒng)的控制

增量式PID

增量式PID(Incremental PID)是PID控制算法的一種變體,與傳統(tǒng)的位置式PID(Positional PID)相對應(yīng)。增量式PID算法通過計(jì)算當(dāng)前時刻的控制量與上一時刻的控制量之差,來得到增量控制量,從而實(shí)現(xiàn)對系統(tǒng)的控制。

在增量式PID中,控制器的輸出是一個增量值,而不是一個絕對值。增量控制量表示了控制器輸出的變化量,可以直接應(yīng)用于系統(tǒng)中,而無需考慮系統(tǒng)的初始狀態(tài)。

增量式PID相對于位置式PID的優(yōu)點(diǎn)是:

不受系統(tǒng)初始狀態(tài)的影響:增量式PID只關(guān)注控制量的變化,而不需要考慮系統(tǒng)的初始狀態(tài)。這使得增量式PID在系統(tǒng)啟動時更加穩(wěn)定。減少積分飽和問題:位置式PID中的積分項(xiàng)可能會導(dǎo)致積分飽和問題,而增量式PID通過增量控制量的計(jì)算,可以減少積分飽和的發(fā)生。

然而,增量式PID也存在一些限制和注意事項(xiàng):

對控制器的輸出限制要求較高:增量式PID的輸出是控制量的增量,因此需要確??刂破鞯妮敵龇秶銐虼?,以避免輸出限制問題。對采樣周期要求較高:增量式PID對采樣周期的要求較高,需要保證采樣周期足夠小,以減小誤差的累積。

PID離散化公式

PID算法公式

PID算法公式如下:

PWM (k) =PWM(k-1)+Kp*(T(k)-T(k-1))+Ki*(T(k)-Ttarget)+Kd*(T(k)-2*T(k-1)+T(k-2))

參數(shù)整定口訣

參數(shù)整定尋最佳,從大到小順次查。

先是比例后積分,最后再把微分加。

曲線振蕩很頻繁,比例度盤要放大。

曲線漂浮繞大彎,比例度盤往小扳。

曲線偏離回復(fù)慢,積分時間往下降。

曲線波動周期長,積分時間再加長。

理想曲線兩個波,調(diào)節(jié)過程高質(zhì)量。

調(diào)試效果圖

最終效果圖

調(diào)試代碼

from cProfile import label
import time
from turtle import width
import numpy as np
import matplotlib.pyplot as plt
from subprocess import PIPE, Popen, DEVNULL
 
from numpy import append
 
 
def run(cmd, retype="r"):
    '''run System Command and Return Command Stdout Object'''
    try:
        with Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE, encoding="utf-8") as f:
            Ret_Type = {"r": f.stdout.read, "rl": f.stdout.readline, "rls" : f.stdout.readlines, "rc": f.wait}
            if retype == 're':
                return f.stdout.read() + f.stderr.read()
            return Ret_Type[retype]()
    except Exception as e:
        print("\033[31mExecute Err:%s\033[0m"%e)
 
 
class DeltaPid(object):
    '''
        PID calculate
        pwm = pre_pwm + kp*(err-pre_ee) + ki*err + kd*(err-2*pre_err+pre_pre_ee)
    '''
    def __init__(self, target_temp, max_pwm, min_pwm, p, i, d):
        self.max_pwm = max_pwm
        self.min_pwm = min_pwm
        self.k_p = p
        self.k_i = i
        self.k_d = d
        self.target_temp = target_temp
        self._pre_temp = target_temp
        self._pre_pre_temp = target_temp - 1
 
    def calculate(self, cur_temp, pwm_in):
        # pwm = pre_pwm + kp*(err-pre_ee) + ki*err + kd*(err-2*pre_err+pre_pre_ee)
        pwm_out = 0
        p_change = self.k_p * (cur_temp - self._pre_temp)
        i_change = self.k_i * (cur_temp - self.target_temp)
        d_change = self.k_d * (cur_temp - 2 * self._pre_temp + self._pre_pre_temp)
        print(f"p:{p_change} i:{i_change} d:{d_change}")
 
        delta_output = p_change + i_change + d_change
        print(f"p+i+d output={delta_output}")
 
        pwm_out = delta_output + pwm_in
        print(f"calculate pwm={pwm_out}")
        self._pre_pre_temp = self._pre_temp
        self._pre_temp = cur_temp
 
        pwm_out = self.max_pwm if pwm_out > self.max_pwm else (self.min_pwm if pwm_out < self.min_pwm else pwm_out )
        print(f"actual output pwm={pwm_out}")
 
        return pwm_out
 
 
class Pwm(object):
    '''
        function1: set and get fan and heater pwm
        function2: get socket temp
    '''
    def __init__(self, path):
        self.path = f"{path}"
        self.fan_en = []
        self.heater_en = []
        self.fan_pwm = []
        self.heater_pwm = []
        self.temp = []
        for i in range(1, 5):
            self.fan_en.append(f"{self.path}fan{i}_en")
            self.heater_en.append(f"{self.path}heater{i}_en")
            self.fan_pwm.append(f"{self.path}fan{i}_pwm")
            self.heater_pwm.append(f"{self.path}heater{i}_pwm")
            self.temp.append(f"{self.path}temp{i}")
 
    def en_fan(self, index):
        cmd = f"echo 100 > {self.fan_en[index - 1]}"
        run(cmd)
 
    def en_heater(self, index):
        cmd = f"echo 100 > {self.heater_en[index - 1]}"
        run(cmd)
 
    def get_temp(self, index):
        cmd = f"cat {self.temp[index - 1]}"
        return run(cmd).replace('\n', '')
 
    def get_fan_pwm(self, index):
        cmd = f"cat {self.fan_pwm[index - 1]}"
        return run(cmd).replace('\n', '')
 
    def set_fan_pwm(self, pwm, index):
        cmd = f"echo {pwm} > {self.fan_pwm[index - 1]}"
        run(cmd)
 
    def get_heater_pwm(self, index):
        cmd = f"cat {self.heater_pwm[index - 1]}"
        return run(cmd).replace('\n', '')
 
    def set_heater_pwm(self, pwm, index):
        cmd = f"echo {pwm} > {self.heater_pwm[index - 1]}"
        run(cmd)
 
 
def filter(index, limit):
    usb_path = "/sys/dev/char/USB0/USB/"
    pwm = Pwm(usb_path)
    temp = []
    for i in range(0, 7):
        temp_old = int(pwm.get_temp(index))
        temp_new = int(pwm.get_temp(index))
        print(temp_old, temp_new)
        if abs(temp_old - temp_new) < limit: 
            temp.append(temp_old)
            temp.append(temp_new)
    print(temp)
    if not temp:
        return int(pwm.get_temp(index))
    return int(sum(temp)/len(temp))
 
 
def test(count=5000, target_temp = 105):
    usb_path = "/sys/dev/char/USB0/USB/"
    pwm = Pwm(usb_path)
    counts = np.arange(count)
    outputs = []
    pwms = []
    # enable fan and heater
    pwm.en_fan(1)
    pwm.en_heater(1)
 
    # initial fan and heater pwm
    pwm.set_fan_pwm(0, 1)
    pwm.set_heater_pwm(100, 1)
 
    pid = DeltaPid(target_temp, 45, 5, 10, 0.7, 0.3)
    print(f"Now temp is {pwm.get_temp(1)}")
    print("start test ...")
    print(f"set heater pwm to 100, target temp is {target_temp} ...")
 
    # set temp to (target) and keep heater in 80 pwm
    print(f"time: {time.ctime()}")
    while True:
        temp1 = filter(1, 20)
        print(f"Now temp is {temp1}")
        time.sleep(1)
        if temp1 / 10 >= (target_temp):
            print("keep heater pwm to 80 ...")
            pwm.set_fan_pwm(35, 1)
            pwm.set_heater_pwm(80, 1)
            break
            # draw
    print(f"time: {time.ctime()}")
 
    for i in counts:
        print(f"No.{i} pid adjust")
        temp1 = filter(1, 20)
        now_fan_pwm = int(pwm.get_fan_pwm(1))
        pwms.append(now_fan_pwm)
        print(f"temp={temp1}C , fan pwm={now_fan_pwm}")
        now_pwm = pid.calculate(int(temp1) / 10, now_fan_pwm)
        pwm.set_fan_pwm(int(now_pwm), 1)
        time.sleep(1)
        outputs.append(int(temp1) / 10)
 
    print('Done')
 
    # draw
    plt.figure()
    plt.axhline(target_temp, c='red', label = "target_temp")
    plt.axhline(target_temp-3, c='yellow', label = "target_temp_min")
    plt.axhline(target_temp+3, c='red', label = "target_temp_max")
    plt.plot(counts, np.array(outputs), 'b.')
    plt.ylim(0, 130)
    plt.plot(counts, outputs, label = "temp")
    plt.plot(counts, pwms, label = "pwm")
    plt.title("PID")
    plt.xlabel('count')
    plt.ylabel('temperature')
    plt.legend()
    plt.tick_params(axis='both', width=1, length=5)
    plt.xticks(fontsize=13)
    plt.yticks(fontsize=13)
    plt.show()
 
 
if __name__ == "__main__":
    test()

以上就是python實(shí)現(xiàn)PID溫控算法的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于python PID溫控算法的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論