New Page 1

Symulator sterowania wybranym obiektem przy pomocy sieci neuronowych.

Program realizuje symulację sterowania obiektem przy pomocy sieci neuronowych. Umożliwia on symulacyjne badanie jakości regulacji, użytkownik ma możliwość wpływania na podstawowe parametry sieci neuronowych jak współczynnik szybkości uczenia sieci. może również definiować współczynniki badanego obiektu, który jest opisany równaniem typu ARMA.

Struktura sieci i algorytm sterowania zastosowane w rozwiązaniu

Ponieważ system miał działać w czasie rzeczywistym dlatego odrzucone zostały modele z neuronami w warstwach ukrytych  i zaimplementowano najprostszą sieć dwuwarstwową  z jednym neuronem wyjściowym.

Model układu sterującego jest przedstawiony na poniższym rysunku:

Aby można było zaimplementować powyższy schemat, trzeba przyjąć, że obiekt jest opisany następującym równaniem ARMA (klasyczne równanie dyskretne):

A(q-1) oraz B(q-1) są wielomianami zdefiniowanymi następująco:

gdzie: 
   
          ;

Trzeba tu założyć co następuje :

             1) znane są górne granice n i m ,
               2) B(q-1) jest wielomianem stabilnym,
               3) współczynnik b1 jest różny od zera.

Warunek pierwszy jest konieczny aby można było wyestymować parametry badanego obiektu. Warunek drugi musi być spełniony aby otrzymać stabilną pętlę sterowania sterownika neuronowego, trzecie założenie musi być spełnione aby móc skonstruować neuronowy sterownik.

 

 Estymatorem jest w tym przypadku dwuwarstwowa liniowa sieć neuronowa składająca się z n+m wejść. Podajemy na nią takie same sygnały jak na sterowany obiekt. Sieć ta uczy się dynamiki badanego obiektu.

Neuronowy estymator

Wektor wag sieci neuronowej ma następującą postać:

                                           

Wektor ten jest uaktualniany zgodnie z regułą Widrowa-Hoffa:

                                                                                                                                                                                

gdzie:

- a (0,2) i jest współczynnikiem uczenia sieci,
  - e powinien dążyć do zera (  ma uchronić nas przed dzieleniem przez zero gdy iloczyn 

Tak jak to jest zaprezentowane na powyższym rysunku, sygnał błędu predykcji e(k) jest różnicą pomiędzy rzeczywistą odpowiedzią obiektu a wyestymowaną wartością otrzymaną z neuronowego estymatora. Wartość wyestymowanego sygnału jest obliczana ze wzoru:                                                                                                                                                                                                                         

 

Sterownik neuronowy podobnie jak estymator składa się z dwóch warstw neuronów z n+m warstwami wejściowymi i 1 warstwą wyjściową.

 

Wektor wejściowy sterownika jest zdefiniowany następująco : 

a wektor wag sterownika definiuje się następująco :

Sygnał sterujący u(k) jest sumą iloczynów następującego wyrażenia :

                                                                                                                                                                                                                                                               

 

3 Algorytm sterowania

  Sekwencja sterowania obiektem przedstawia się następująco:

 1. Zmierz y(k+1) oraz y(k);
   2. Przy pomocy estymatora oblicz
 korzystając ze starych wag wi(k-1);
   3. Oblicz e(k)=y(k) -  i przy pomocy reguły DELTA nowe wagi wi(k);
   4. Zmień wagi ci(k);
   5. Przy pomocy sterownika oblicz nowy sygnał sterujący u(k).

 Program symulacyjny oraz moduł do sterowania silnikiem krokowym zastał napisany w języku Turbo Pascal 7.0 w środowisku Turbo Vision.

Opis programu 

Opis powiązań między modułami

Zasadniczy program składa się z kilku modułów. Modułem nadrzędnym jest moduł sieci.pas. Z jego poziomu wywoływane są następujące moduły ( w odpowiedzi na działania użytkownika ): 

grafika.pas - moduł ten zawiera procedury obsługujące ekran graficzny podczas wyświetlania efektów symulacji ( wyświetla ramki, napisy, komunikaty itp. w trybie graficznym);

wymusz.pas - w module tym są zdefiniowane poszczególne sygnały wymuszające podawane na badany obiekt; Parametrem przekazywanym do tego modułu jest numer wymuszenia (np. 1 - skok jednostkowy ) oraz numer próbki. W odpowiedzi jest zwracana odpowiednia wartość sygnału wymuszającego. W module tym jest także  zaimplementowana procedura definiująca zakłócenia.

konwers.pas - ze względu na brak dostatecznej ilości wolnego miejsca w obszarze zmiennych, dane z symulacji wymuszeniem skokowym są zapisywane bezpośrednio do pliku DANE.TMP. Aby mogły one być następnie przetworzone w innym programie, następuje konwersja do standardowego formatu przyjętego przez kolegów. Format tego pliku jest opisany w dalszej części dokumentacji. 

sufler.pas, zasoby.pas - pliki zawierające dane do help'a oraz paska podpowiedzi (opis znajduje się dalej

 

Opis podstawowych procedur programu SIECI.EXE

 Podstawowymi procedurami zawartymi w programie są procedury przeznaczone do symulacji działania pętli sterowania i implementacji sieci neuronowych. Poniżej zostaną omówione najważniejsze z nich:

Definicja zmiennych globalnych wykorzystywanych w procedurach.  

param_obie : array[0..7] of Real; {W tej tablicy przechowywane są  parametry opisujące badany obiekt. Tablica ma rozmiar 8 liczb rzeczywistych ponieważ przyjęto, że  maksymalnym wprowadzonym obiektem może być obiekt 4-tego rzędu. Np. dla obiektu przyjętego standardowo po uruchomieniu programu tablica zawiera następujące dane ( mamy tutaj n=3 i m=3 ):
param_obie[0]=0.1;         { a1 }                 
param_obie[1]=0.02;       { a2 }  n =  3
param_obie[2]=0.03;     
  {a3} 
param_obie[3]=0.1;     
    { b1 }
param_obie[4]=0.2;     
    { b2 }  m =3
param_obie[5]=0.3;         { b3 }      } patrz równanie ARMA ( 1 )

ewagi,cwagi: array[1..8] of Real; {W tablicach tych są przechowywane wartości wag sieci neuronowych. Notacja jest podobna do powyższej. Waga ewagi[n+1]
przyjmuje podczas inicjalizacji wartość 1.0. Przyjmując, że badany model
zawiera parametry jak wyżej, indeks tej wagi jest ewagi[4]. Wszystkie
podane wagi pochodzą z chwili (k-1). Odpowiednikiem zmienne ewagi[1..n+m] na rys. 4 są zmienne w1(k-1)..wn+m(k-1). Odpowiednikiem zmiennej cwagi[1..n+m] na rys. 5 są zmienne c1(k-1)..cn+m(k-1) }  

sygnal_u,sygnal_y : array[0..4] of Real; { Zmienne te reprezentują odpowiednio sygnały wyjściowe z regulatora neuronowego i z wyjścia badanego obiektu. Indeks w tablicy [0] oznacza próbkę w chwili bieżącej (k), natomiast pozostałe indeksy odpowiednio: [1] próbkę w chwili (k-1), [2] oznacza próbkę (k-2) itd. do indeksu [4]. Czyli maksymalne opóźniona próbka w obwodzie będzie (k-4) - ta.}

y_estymowane, error, sygnal_we : Real; { Zmienna y_estymowane reprezentuje błąd predykcji - jest to różnica między wartością wyestymowaną przez neuronowy estymator a wartością z wyjścia badanego obiektu. Zmienna  error jest to uchyb regulacji - różnica pomiędzy wartością zadaną a wartością z wyjścia badanego obiektu. Natomiast zmienna sygnal_we jest to wartość zadana czyli na rysunku nr 3 jest to zmienna y'(k+1). }

Odpowiedź badanego obiektu ARMA

procedure Odp_obiektu;

var
             ysum,usum :Real;

  begin  
  
              ysum:=0;
                usum:=0;

     for i:=1 to n do
            ysum:=ysum+sygnal_y[i]*param_obie[i];

    for i:=n+1 to n+m do
            usum:=usum+sygnal_u[i-n]*param_obie[i];

     sygnal_y[0]:=usum-ysum;
end;
 

 {zmienne pomocnicze}

 {Zakładając, że n=3 j.w. można tę pętlę rozpisać:

sygnal_y[1]*param_obie[1], czyli y(k-1)*a1
sygnal_y[2]*param_obie[2], czyli y(k-2)*a2
sygnal_y[3]*param_obie[3], czyli y(k-3)*a3

  Zakładając, że m=3  można tę pętlę rozpisać:

sygnal_u[1]*param_obie[4], czyli u(k-1)*b1
sygnal_u[2]*param_obie[5], czyli u(k-2)*b2
sygnal_u[3]*param_obie[6], czyli u(k-3)*b3

}

{odpowiedź obiektu w chwili bieżącej (k) }

Sygnał sterujący z regulatora neuronowego

procedure Wy_kontrolera;

var
               
wy_kontr :Real;

  begin
               
wy_kontr:=0;
                wy_kontr:=sygnal_we*cwagi[1];

    for i:=0 to n-1 do
                wy_kontr:=wy_kontr+(1*sygnal_y[i+1]*cwagi[i+2]);

   end;

for i:=1 to m-1 do
   
            wy_kontr:=wy_kontr+(-1*sygnal_u[i]*cwagi [i+n+1]);

{Zmienna pomocnicza }

{  y(k+1) * c1(k-1) na rys. 5}

 sygnal_u[0]:=wy_kontr;
{ sygnał sterujący obiektem w chwili (k)

 

Implementacja estymatora neuronowego

procedure Wy_estymatora;

var
               
ysum,usum :Real;

  begin
               ysum:=0;
    
   
        usum:=0;

    for i:=1 to n do
               ysum:=ysum+sygnal_y[i]*ewagi[i];

 for i:=n+1 to n+m do
               usum:=usum+sygnal_u[i-n]*ewagi[i];
   
             y_estymowane:=usum-ysum;  

end; 

{ zmienne pomocnicze }

 {Na podstawie rysunku estymatora oraz założenia, że n,m=3 pętle te odpowiadają zapisowi:

y(k-1)*w1(k-1),
y(k-2)*w2(k-1),
y(k-3)*w3(k-1),

u(k-1)*w4(k-1),
u(k-2)*w5(k-1),
u(k-3)*w6(k-1)}

 { sygnał wyestymowany na podstawie wag i próbek z poprzednich chwil pobranych z  wyjścia badanego obiektu }

Implementacja algorytmu Widrow-Hoffa modyfikującego wagi sieci

procedure Edelta;

var
               
mianownik,licznik :Real;
                epsylon,alfa: Real;
   
             kod:Integer;

  begin
   
             mianownik:=0;
   
             licznik:=0; 

    Val(DaneReguly.epsylon,epsylon,kod);
   Val(DaneReguly.alfa,alfa,kod);

  for i:=1 to n do
  mianownik:=mianownik+sygnal_y[i]*sygnal_y[i];
 for i:=n+1 to n+m do
 mianownik:=mianownik+sygnal_u[i-n] *sygnal_u[i-n];
 mianownik:=mianownik+epsylon;

 licznik:=alfa*error;

     for i:=1 to n do
                ewagi[i]:=ewagi[i]+(-1*sygnal_y[i] *licznik/mianownik);

 { zmienne lokalne pomocnicze }

 {Zamiana wprowadzonych przez użytkownika parametrów definiujących uczenie sieci ( alfa i epsylon ) na wartości numeryczne ( użytkownik w Turbo Vision wprowadza je jako zmienne typu string ) }

 {Obliczenie iloczynu macierzy : }

 {Zmienna error jest błędem predykcji

e(k)=y(k) - , na rys. 4 : e(k-1)}

 { Tutaj następuje właściwa modyfikacja wektora wag neuronowego estymatora}


for i:=n+1 to n+m do

                ewagi[i]:=ewagi[i]+(sygnal_u[i-n]*licznik/mianownik);

  end;

            W poniższej procedurze zostało zaimplementowane równanie (8) - modyfikacja wag neuronowego regulatora.

procedure Cdelta;

begin
   
         cwagi[1]:=1.0/ewagi[n+1];

   for i:=2 to n+1 do
            cwagi[i]:=ewagi[i-1]/ewagi[n+1];  

for i:=n+2 to m+n do
            cwagi[i]:=ewagi[i]/ewagi[n+1];

end;

{ cwagi[1] według algorytmu są zawsze równe odwrotności zmiennej /ewagi[n+1]}

{Modyfikacja wag regulatora neuronowego polega zawsze na podzieleniu wag regulatora przez zmienną ewagi[n+1]}

Procedury dodatkowe

       Przed każdym kolejnym procesem symulacyjnym tablice obsługujące algorytm sterowania (sieci neuronowe) powinny zostać wyzerowane. Realizuje to poniższa procedura:

procedure Zeruj_tablice;

 begin
   
            
for i:=1 to 8 do

       begin
                ewagi[i]:=0;
                cwagi[i]:=0;
        end;
            
   
         for i:=0 to 4 do
                sygnal_y[i]:=0;

          for i:=0 to 4 do
                sygnal_u[i]:=0;
 end;

                 Po każdym  jednym cyklu symulacyjnym trzeba przepisać odpowiednio próbki z chwili (k) na (k-1) itd. Realizuje to procedura :

 procedure Uporzadkuj_probki;

  begin

    for i:=n downto 1 do
   
             sygnal_y[i]:=sygnal_y[i-1];
   
for i:=m downto 1 do
   
             sygnal_u[i]:=sygnal_u[i-1];
  end;

{********** procedura prezentacji sygnałów z symulacji ***********}

repeat
   
              if l>kol_probka then  {wejscie do petli nastapi wtedy, gdy nadejdzie nowa probka}

       begin
            
if (wysw_wag=0) then

             begin {Wyświetlanie zdefiniowanych parametrów na ekranie}
  
                if  (par_wysw and 1 =1) then rysuj_linie(l,40,wym_pop,sygnal_we,LightBlue,skala);
   
              if (par_wysw and 2 =2) then rysuj_linie(l,40,blad_pop,error,LightCyan,skala);
                if  (par_wysw and 4 =4) then rysuj_linie(l,40,blad_reg,uchyb,LightMagenta,skala)
   
            if  (par_wysw and 8=8) then rysuj_linie(l,40,sygn_u_pop,sygnal_u[0],Yellow,skala/10);  
   
          
if (par_wysw and 16=16) then rysuj_linie(l,40,odp_y_pop,sygnal_y[0],LightRed,skala);

            end
                else
            begin
{Wyświetlanie wag estymatora neuronwego}

                     for i:=1 to n+m do
                              rysuj_linie(l,40,pop_wagi[i],ewagi[i],i+7,500);
                                rysuj_linie(l,40,wym_pop,sygnal_we,LightGray,skala);
                    for i:=1 to 8 do
                             pop_wagi[i]:=ewagi[i];
             
end;

                       if (NrWymuszenia.wymuszenie=0) and (l>100) and (l<=500) then

                begin
   
                  if sygnal_y[0]>y_max then y_max:=sygnal_y[0];
   
                
sygnal_sterujacy^[l-100]:=sygnal_u[0];
   
                 sygnal_wyjsciowy^[l-100]:=sygnal_y[0];
                    sygnal_uch^[l-100]:=uchyb;
   
                jakosc_regul:=jakosc_regul+(uchyb*uchyb); {Obliczanie jakości regulacji}
                end;

                                                wym_pop         :=sygnal_we;          
   
                                             odp_y_pop      :=sygnal_y[0];
   
                                             blad_pop         :=error;
   
                                             sygn_u_pop    :=sygnal_u[0];
                                                blad_reg       
          :=uchyb;
   
                                             kol_probka      :=l;

                 end;

              until l=600; {Koniec kiedy zostanie pobrane 600 próbek}