18 Ekim 2018, 19:17:46

Haberler:

Eposta uyarılarını yanıtlamayınız ( ! ) https://bit.ly/2J7yi0d


PID Kontrol Problemi (C#)

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

baran123

29 Eylül 2018, 05:10:16 Son düzenlenme: 29 Eylül 2018, 05:16:09 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
Kod Seç
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 Kpdouble Kidouble Kddouble setValuedouble dtdouble maxdouble 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
Kod Seç
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(kpkikd350.051000);

        public 
Form1()
        {
            
InitializeComponent();
        }

        private 
void timer1_Tick(object senderEventArgs 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 10);
        }

        private 
void trackBar1_ValueChanged(object senderEventArgs e)
        {
            
label1.Text "Current Value = " trackBar1.Value.ToString();
        }

        private 
void trackBar2_ValueChanged(object senderEventArgs 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 ?
İdrak i meali bu küçük akla gerekmez, zira bu terazi bu kadar sıkleti çekmez.

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.
Istanbul Technical University                                  Control and Automation Engineering

Zoroaster

30 Eylül 2018, 05:37:06 #4 Son düzenlenme: 30 Eylül 2018, 09:17:34 Zoroaster
Alıntı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.
....
....
Çı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, 05: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.
Istanbul Technical University                                  Control and Automation Engineering

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 ?
İdrak i meali bu küçük akla gerekmez, zira bu terazi bu kadar sıkleti çekmez.

Firzen

30 Eylül 2018, 22:06:02 #8 Son düzenlenme: 30 Eylül 2018, 22:35:24 Firzen
Alıntı yapılan: baran123 - 30 Eylül 2018, 21: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:
Kod Seç
import time

class PID:

    
def __init__(selfP=0.2I=0.0D=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
(selffeedback_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(selfproportional_gain):
        
self.Kp proportional_gain

    def setKi
(selfintegral_gain):
        
self.Ki integral_gain

    def setKd
(selfderivative_gain):
        
self.Kd derivative_gain

    def setWindup
(selfwindup):
        
self.windup_guard windup

    def setSampleTime
(selfsample_time):
        
self.sample_time sample_time

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

Istanbul Technical University                                  Control and Automation Engineering

baran123

Hocam tesekkurler

Deneme yapip bilgi verecegim
İdrak i meali bu küçük akla gerekmez, zira bu terazi bu kadar sıkleti çekmez.

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, 15: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.
Istanbul Technical University                                  Control and Automation Engineering

foseydon

Alıntı yapılan: Firzen - 01 Ekim 2018, 18: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.
İdrak i meali bu küçük akla gerekmez, zira bu terazi bu kadar sıkleti çekmez.

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.
Istanbul Technical University                                  Control and Automation Engineering