PID Kontrol Problemi (C#)

Başlatan baran123, 29 Eylül 2018, 02:10:16

baran123

İlerde yapacağım basınç regülasyonu için PID kullanmak istiyorum.
Deneme amaçlı C# ile bir proje oluşturdum fakat istediğim gibi sonuç alamıyorum.

Test yazılımına 2 adet track bar ekledim.
Birisi ile "Şuan ki" değeri değiştiriyorum
Diğeri ile "Set Point" değerini değiştiriyorum.
Listboxda belirlediğim şekilde bir sonuç alamadım.

Bir algoritma hatası mı yapıyorum ?

PID.cs
using System;

namespace PID_Control
{
    public class PID
    {
        private double _Kp;
        private double _Ki;
        private double _Kd;

        private double _dt;
        private double _setPoint;

        private double _pre_error;
        private double _integral;

        private double _max;
        private double _min;

        public PID(double Kp, double Ki, double Kd, double setValue, double dt, double max, double min)
        {
            _Kp = Kp;
            _Ki = Ki;
            _Kd = Kd;

            _dt = dt;
            _setPoint = setValue;

            _pre_error = 0;
            _integral = 0;

            _max = max;
            _min = min;
        }

        public void SetValue(double targetValue)
        {
            _setPoint = targetValue;
        }

        public double Update(double pv)
        {
            // Calculate error
            double error = _setPoint - pv;

            // Proportional term
            double Pout = _Kp * error;

            // Integral term
            _integral += error * _dt;
            double Iout = _Ki * _integral;

            // Derivative term
            double derivative = (error - _pre_error) / _dt;
            double Dout = _Kd * derivative;

            // Calculate total output
            double output = Pout + Iout + Dout;

            // Restrict to max/min
            if (output > _max)
                output = _max;
            else if (output < _min)
                output = _min;

            // Save error to previous error
            _pre_error = error;

            return output;
        }
    }
}

Örnek
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace PID_Control
{
    public partial class Form1 : Form
    {
        const double kp = 3;
        const double ki = 0.1;
        const double kd = 1;

        PID PID = new PID(kp, ki, kd, 35, 0.05, 100, 0);

        public Form1()
        {
            InitializeComponent();
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            double input = (double)trackBar1.Value;

            double output = PID.Update(input);

            listBox1.Items.Add(output);

            int visibleItems = listBox1.ClientSize.Height / listBox1.ItemHeight;
            listBox1.TopIndex = Math.Max(listBox1.Items.Count - visibleItems + 1, 0);
        }

        private void trackBar1_ValueChanged(object sender, EventArgs e)
        {
            label1.Text = "Current Value = " + trackBar1.Value.ToString();
        }

        private void trackBar2_ValueChanged(object sender, EventArgs e)
        {
            double setValue = (double)trackBar1.Value;

            PID.SetValue(setValue);

            label2.Text = "Set Value = " + trackBar2.Value.ToString();
        }
    }
}

Çıktılar genelde 0 yada 100 oluyor.
Ben nerede hata yapıyorum ?

exmachine

Anladığım kadarıyla Kp, Kd ve Ki parametrelerinin sonuca etkisini gözlemleyebilmek için bilgisayarda simulasyon benzeri bir şey yapmak istiyorsun.

Projeye bir timer ekle. Bu timer'in tick süresi senin örnekleme periyodun olacak. Pid fonksiyonunu bu timer'in tick event'i içine yaz.

Şu haliyle programın çıktısının minimum veya maksimuma ulaşması normal, çünkü çıkış ne olursa olsun hata değişmiyor. Bunun sonucunda çıkış minimum ya da maksimum saturasyon noktasına ulaşıyor.

Okan AKÇA

Kp, Kd ve Ki katsayılarını bilemediğiniz sürece dogru sonucu vermeyecektir. Auto tuning veya yukarıda hocamızın bahsettiği gibi simule ederek bulmamız gerekmektedir.
Piyasada bir cok ısı kontrol cihazı pid kontrol olsada tam verimli çalısan cihaz sayısı çok azdır.
Pid oldukça önemli bir konu takipteyim

Firzen

Merhabalar @baran123.

Katsayıları tune etmekte sıkıntı yok. Sıkıntı şu :  Yazdığın kod sürekli Sistem için geçerli. Senin ayrık kod yazman lazım.

Öncelik olarak :
1- Sistemin örnekleme zamanı koy.
2- Bu örnekleme zamanına bağlı ayrık sistem PID formülünü çıkar (Tustin, Backward, Forward)
3- Bu formülü fark denklemi olarak yaz

Test için;
1- Oluşturulan sisteme bir set input değeri belirle
2- İşlem süresini belirle (örn: 10sn)
3- Matlab simulinkte discrete blok diyagram koy ve toplam süreyi aynı yap
4- Yazdığın C# kodu ile karşılaştır.
Kararsız...

Zoroaster

#4
Alıntı YapTest yazılımına 2 adet track bar ekledim.
Birisi ile "Şuan ki" değeri değiştiriyorum
Diğeri ile "Set Point" değerini değiştiriyorum.
....
....
Çıktılar genelde 0 yada 100 oluyor.
Ben nerede hata yapıyorum ?

Bu cok normal. PID Controller cikisini kontrol duzenegine vermiyor ve geri beslemeyi sanki sistem, PID ciktisina tepki vermis gibi  elle  Track bar ile belirliyorsun.

Eger bu sekilde test edeceksen Delta T degerini 5 sn gibi yuksekce degerlere ayarla ki Track bari degistirmeye firsatin olsun.

Fakat PID yi bu sekilde test etmek sana fayda saglamaz.

Onerim, PID cikisina bir sistem modeli ekle ve onu test et. Boylece PID gercek sistem tepkisine maruz kalsin.

Mesela plant olarak a/(s+a) ya da a^2/(s^2+bs+a^2) gibi sistem modeli ekle.



Seytan deliginden kacti.

Firzen

Alıntı yapılan: Zoroaster - 30 Eylül 2018, 02:37:06Bu cok normal. PID Controller cikisini kontrol duzenegine vermiyor ve geri beslemeyi sanki sistem, PID ciktisina tepki vermis gibi  elle  Track bar ile belirliyorsun.

Eger bu sekilde test edeceksen Delta T degerini 5 sn gibi yuksekce degerlere ayarla ki Track bari degistirmeye firsatin olsun.

Fakat PID yi bu sekilde test etmek sana fayda saglamaz.

Onerim, PID cikisina bir sistem modeli ekle ve onu test et. Boylece PID gercek sistem tepkisine maruz kalsin.

Mesela plant olarak a/(s+a) ya da a^2/(s^2+bs+a^2) gibi sistem modeli ekle.


Aynen Benim dediğim gibi hocam. Burada sistemi test düzeneğinde bende aynısını yaptım.

Öncelik olarak Simullink ile Discrete control ve model oluşturdum.
Aynı sistemi pythonda yazdım. Kendi kontrol fark denklemimi yazdım.
Örnekleme zamanını belirleyip belirli bir süre çalıştırdım. Bu sayede kontrolümü test etmiş oldum.
Kararsız...

Zoroaster

Yazilan bir PID fonksiyonunu tetst etmek icin;

PID dongusunde her defasinda

Err=Err+0.1 yapilirsa PID nin 100'uncu dongude alacagi deger 

islem hatasi yoksa PID[100]=10Kp+500KpDT+KdDT/10 olmasi gerekir.
Seytan deliginden kacti.

baran123

Ben tımer olarak C# ın kendi içinde bulunan timerı kurup bunun interval değerini 50 ms yaptım.
Yine programda da dt değerini 0.05 olarak girdim.

Z hocamın dediği gibi çıkışı girişe aktarma olayını düzelttim.

1-input al
2-pid fonksiyonuna bu değeri yükle.
3-input = output yap

fakat yine saçma değerler görüyorum.
Katsayılar ise internetten buldum bir excel ile ayarladım.
Katsayılar kötü de olsa sistem uzun bir süre sonra yine set değerine oturmaz mı ?

Kontrol teorisi bilgim şuan için zayıf.
Yani şuan s domenin de bir fonksiyonu sistemin çıkışına ekleyip fonksiyondan dönen değeri mi input olarak almam gerekiyor ?

Firzen

#8
Alıntı yapılan: baran123 - 30 Eylül 2018, 18:30:05Ben tımer olarak C# ın kendi içinde bulunan timerı kurup bunun interval değerini 50 ms yaptım.
Yine programda da dt değerini 0.05 olarak girdim.

Z hocamın dediği gibi çıkışı girişe aktarma olayını düzelttim.

1-input al
2-pid fonksiyonuna bu değeri yükle.
3-input = output yap

fakat yine saçma değerler görüyorum.
Katsayılar ise internetten buldum bir excel ile ayarladım.
Katsayılar kötü de olsa sistem uzun bir süre sonra yine set değerine oturmaz mı ?

Kontrol teorisi bilgim şuan için zayıf.
Yani şuan s domenin de bir fonksiyonu sistemin çıkışına ekleyip fonksiyondan dönen değeri mi input olarak almam gerekiyor ?

Normalde kod paylaşmam ama konu gereksiz uzadı herkes aynı şeyleri paraphrase edip söylüyor.

Python dilinde yazdığım kod:
import time

class PID:

    def __init__(self, P=0.2, I=0.0, D=0.0):

        self.Kp = P
        self.Ki = I
        self.Kd = D

        self.sample_time = 0.00
        self.current_time = time.time()
        self.last_time = self.current_time

        self.clear()

    def clear(self):
        self.SetPoint = 0.0

        self.PTerm = 0.0
        self.ITerm = 0.0
        self.DTerm = 0.0
        self.last_error = 0.0

        self.int_error = 0.0
        self.windup_guard = 20.0

        self.output = 0.0

    def update(self, feedback_value):
        error = self.SetPoint - feedback_value

        self.current_time = time.time()
        delta_time = self.current_time - self.last_time
        delta_error = error - self.last_error

        if (delta_time >= self.sample_time):
            self.PTerm = self.Kp * error
            self.ITerm += error * delta_time

            if (self.ITerm < -self.windup_guard):
                self.ITerm = -self.windup_guard
            elif (self.ITerm > self.windup_guard):
                self.ITerm = self.windup_guard

            self.DTerm = 0.0
            if delta_time > 0:
                self.DTerm = delta_error / delta_time
            self.last_time = self.current_time
            self.last_error = error

            self.output = self.PTerm + (self.Ki * self.ITerm) + (self.Kd * self.DTerm)

    def setKp(self, proportional_gain):
        self.Kp = proportional_gain

    def setKi(self, integral_gain):
        self.Ki = integral_gain

    def setKd(self, derivative_gain):
        self.Kd = derivative_gain

    def setWindup(self, windup):
        self.windup_guard = windup

    def setSampleTime(self, sample_time):
        self.sample_time = sample_time

Deneme yaparken sistem bile kurmana gerek yok.
set değerini ver kontrol çıkışına bak. feedback = 0 yap.

Kararsız...

baran123

Hocam tesekkurler

Deneme yapip bilgi verecegim

foseydon

böyle bir uygulama olmaz. senin sisteminin modeli ne? sıcaklık kontrolü için yapacağın PID farklı, motor için farklı, güç çevrimi için farklı çalışır. düz PID kodunu yazmak birşey ifade etmez, ki zaten C# ile yazdığın kodu gömülü yazılımda kullanamayacaksın.

amaç, PID mantığını anlamak ve değişkenler nasıl etki ediyor onu görmek ise MATLAB PID Tuner var. Aç örnek sistem yükle, katsayılarla oyna gör.

Firzen

Alıntı yapılan: foseydon - 01 Ekim 2018, 12:07:59böyle bir uygulama olmaz. senin sisteminin modeli ne? sıcaklık kontrolü için yapacağın PID farklı, motor için farklı, güç çevrimi için farklı çalışır. düz PID kodunu yazmak birşey ifade etmez, ki zaten C# ile yazdığın kodu gömülü yazılımda kullanamayacaksın.

amaç, PID mantığını anlamak ve değişkenler nasıl etki ediyor onu görmek ise MATLAB PID Tuner var. Aç örnek sistem yükle, katsayılarla oyna gör.

Dediğin doğru. Örnekler yanlış. Basınç Regülasyonu, Motor Kontrolü ve Sıcaklık 2.Derece Sistemlerdir. Bu yüzden Cascade PID, Paralel yapı, Derivative Kick vs gerek olmaksızın aynı yapıyı kullanabilir. Tek farkı katsayıları tune etmek olacaktır.

Ama dediğim gibi örnekleme vs buradaki asıl önemli konu.
Konuda basınç regülasyonu diyor.
Kararsız...

foseydon

Alıntı yapılan: Firzen - 01 Ekim 2018, 15:33:26Dediğin doğru. Örnekler yanlış. Basınç Regülasyonu, Motor Kontrolü ve Sıcaklık 2.Derece Sistemlerdir. Bu yüzden Cascade PID, Paralel yapı, Derivative Kick vs gerek olmaksızın aynı yapıyı kullanabilir. Tek farkı katsayıları tune etmek olacaktır.

Ama dediğim gibi örnekleme vs buradaki asıl önemli konu.
Konuda basınç regülasyonu diyor.

hocam asıl mevzu şu, arkadaş PID konusunu fazla bilmiyor ama C# biliyor. C# ile birşeyler yapayım, anlamama yardımcı olur gibi bir yaklaşım var. bu gereksiz ve hatalı. salt PID controller kodu yazmak, PID mantığını anlamak için pek işe yaramaz. zaten kod yazmaya bile gerek yok, muhtemelen kullanılan işlemcinin PID kütüphanesi vardır. dspic için texas'ın işlemcileri için var bunlar, üstelik assembly ile yazılımış. sen otursan o kadar verimli yazamazsın zaten.

dediğim gibi mantığı anlamak istiyorsan, ya simülasyon yapacaksın. ya gerçek uygulama yapacaksın. burada sistem ortada yok ki. sadece hesap eden bir kod parçası var. sen kontrol sonucunda bir şey değiştirdiğinde(örneğin PWM duty cycle'ı) aldığın örnek nereye gidecek? bunu ne belirliyor bu kodda? bu olmadan sistem kararlı mı? tepkisi ne oluyor nasıl göreceksin? bu durumda MATLAB gibi bir programda simülasyon yapmak daha faydalı olur. dediğim gibi zaten kodu yazmaya bile gerek yok, yazman gerekirse de 1 saatlik iş C ile.

baran123

Sadece PC de simülasyon yapmak için deneyecektim fakat bu şekilde projeme yönelik verimli olmayacak gibi.
PC tarafında MATLAB ile denemeye karar verdim.
Diğer kısım için PCB yi tamamlayınca test edeceğim.
Cevap verenlere teşekkür ederim.

Firzen

@foseydon PID öğrenmek içinse dediğiniz doğru ben @baran123 ün en azından azda olsa otomatik kontrol biliyor diye paylaştım. İşin aslı yanlış yönlendirilmeye gitmesin diye yazdım.
Kararsız...