kramann.info
© Guido Kramann

Login: Passwort:










kramann.info
© Guido Kramann

Login: Passwort:




Optimierer für den Fuzzy-geregelten Pendel mit modifiziertem Gradientenverfahren

  • Als zunächst letzter Schritt wird das modifizierte Gradientenverfahren verwendet zur Optimierung verwendet.
Kritische Anmerkungen hierzu:
  • Es wird nur eine Simulation mit festen Anfangsbedingungen als Grundlage der Fehlerfunktion benutzt. Dies ist unzureichend, da bei anderen Ausgangssituationen andere Regelparameter sinnvoll sein können.
  • Es wäre denkbar, wenigstens mit den optimierten Parametern Tests für andere ABn durchzuführen.
  • Das modifizierte Gradientenverfahren findet womöglich nur ein schlechtes lokales Minimum. Andere Startwerte bei den Parametersätzen sollten durchgespielt werden.
Übung
  • Hinweis: starten.bat ist für Linux ausgelegt. Bitte nehmen Sie die notwendigen Anpassungen für Windows selber vor.
  • Suchen Sie unter Berücksichtigung obiger kritischer Anmerkungen nach besseren Regelparametern.
  • Legen Sie dazu eine Klasse (Menge) an Simulations-Anfangsbedingungen fest, die das Spektrum des zu erwartenden Verhaltens auch repräsentieren.
  • Modifizieren Sie die Fehlerfunktion dahingehend, dass alle diese Simulationen mit den verschiedenen ABn in den Fehler mit eingehen.
  • Variieren Sie die Start-Fuzzy-Parameter des Reglers für die Optimierung systematisch, indem Sie die Klasse TestOptimiererModGrad umschreiben.
  • Kontrollieren Sie auch die Stellgröße. Ergeben sich im Verlauf nur erlaubte Werte?
  • Hierarchisch absteigend werden die anzupassenden Klassen vorgestellt (vergl. Vorlesung):
package opti;
public class TestOptimiererModGrad
{
    public static void main(String[] args)
    {
        SimulatorAntrieb simulator = new SimulatorAntrieb();
        FehlerfunktionAntrieb fehlerfunktion = new FehlerfunktionAntrieb();
        fehlerfunktion.add(simulator);
        OptimiererModGrad optimierer = new OptimiererModGrad();
        optimierer.add(fehlerfunktion);
        optimierer.startparameter[0] = 1.0;
        optimierer.startparameter[1] = 1.0;
        optimierer.startparameter[2] = 1.0;
        optimierer.startparameter[3] = 1.0;
        optimierer.startparameter[4] = 1.0;
        optimierer.startparameter[5] = 1.0;
        optimierer.startparameter[6] = 1.0;
        optimierer.startparameter[7] = 1.0;
        optimierer.startparameter[8] = 1.0;
        optimierer.startparameter[9] = 1.0;
        optimierer.optimieren();
    }
}

Code 0-1: Klasse TestOptimiererModGrad

package opti;
import java.awt.*; //package awt für die paint()-Methode nötig.
public class SimulatorAntrieb extends Simulator
{
    public double[] fuzzy_parameter = new double[] {0.0, 1.0/4.0, 1.0/3.0, 1.0/2.0, 1.0,
                                                    0.0, 1.0/4.0, 1.0/3.0, 1.0/2.0, 1.0};
    public double[] fuzzy_param_phi   = new double[] {0.0, 1.0/4.0, 1.0/3.0, 1.0/2.0, 1.0};
    public double[] fuzzy_param_omega = new double[] {0.0, 1.0/4.0, 1.0/3.0, 1.0/2.0, 1.0};
    public int simulationsschritte = 1000;
    /**init() dient zur Initialisierung des Simulators.<br/>
    Diese Methode solte von erbenden Klassen überschrieben werden und enthält dann
    alles, was als Vorbereitung zur Durchführung von Simulationen nötig ist,
    z.B. ein Integratorobjekt und ein Modellobjekt erzeugen und mit add(..) als Referenz speichern (registrieren),
    sowie die notwendige Anzahl an Speicherplätzen für y und t allokieren.
    */
    public void init()
    {
        Antrieb antrieb = new Antrieb();
        RungeKuttaIntegrator rungekuttaintegrator = new RungeKuttaIntegrator();
        rungekuttaintegrator.add(antrieb);
        add(antrieb);
        add(rungekuttaintegrator);
        y=new double[simulationsschritte][];
        for(int i=0;i<simulationsschritte;i++)
            y[i] = new double[simulationsmodell.getAnzahlGleichungen()];
        t=new double[simulationsschritte];
    }
    /**Simulation durchführen*/
    public void simulieren()    
    {
        double dt = 0.005;
        t[0] = 0;
        y[0][0] = Math.PI*0.25; //phi
        y[0][1] = 0.0; //omega
        for(int i=1;i<simulationsschritte;i++)
        {
            double[] referenz = integrator.zeitschritt(y[i-1],t[i-1],dt);
            y[i][0] = referenz[0];
            y[i][1] = referenz[1];
            t[i]    = t[i-1]+dt;
        }
    }
    /**i-ten Parameter des Modells ändern*/
    public void setParameter(double param, int i)
    {
        if(param>1.0)
            fuzzy_parameter[i] = 1.0;
        else if(param<0.0)
            fuzzy_parameter[i] = 0.0;
        else
            fuzzy_parameter[i] = param;
        for(int k=0;k<fuzzy_param_phi.length;k++)
            fuzzy_param_phi[k] = fuzzy_parameter[k];
        for(int k=0;k<fuzzy_param_omega.length;k++)
            fuzzy_param_omega[k] = fuzzy_parameter[k+5];
        ((Antrieb)simulationsmodell).fuzzyregler.fes[0].verteileFuzzyGroessenNormiert(fuzzy_param_phi);                
        ((Antrieb)simulationsmodell).fuzzyregler.fes[1].verteileFuzzyGroessenNormiert(fuzzy_param_omega);                
    }
    /**Alle Parameter des Modells ändern*/
    public void setParameter(double[] param)
    {
        for(int i=0;i<param.length;i++)
        {
            if(param[i]>1.0)
                fuzzy_parameter[i] = 1.0;
            else if(param[i]<0.0)
                fuzzy_parameter[i] = 0.0;
            else
                fuzzy_parameter[i] = param[i];
        }
        for(int k=0;k<fuzzy_param_phi.length;k++)
            fuzzy_param_phi[k] = fuzzy_parameter[k];
        for(int k=0;k<fuzzy_param_omega.length;k++)
            fuzzy_param_omega[k] = fuzzy_parameter[k+5];
        ((Antrieb)simulationsmodell).fuzzyregler.fes[0].verteileFuzzyGroessenNormiert(fuzzy_param_phi);                
        ((Antrieb)simulationsmodell).fuzzyregler.fes[1].verteileFuzzyGroessenNormiert(fuzzy_param_omega);                
    }
}

Code 0-2: Klasse SimulatorAntrieb

package opti;
import java.awt.*; //package awt für die paint()-Methode nötig.
public class FehlerfunktionAntrieb implements Fehlerfunktion
{
    public Simulator simulator = null;
    /**Liefert die Anzahl der zu optimierenden Parameter*/
    public int getAnzahlParameter()
    {
        return 10;
    }
    /**Registrieren eines Simulators*/
    public void add(Simulator simulator)
    {
        this.simulator = simulator;
    }
    public double berechneFehler(double[] parameter)
    {
        double fehler = 0.0;
        simulator.init();
        simulator.setParameter(parameter); 
        simulator.simulieren();
        for(int i=0;i<simulator.getAnzahl();i++)
        {
            double y = (simulator.getY(i))[0];
            fehler += y*y; //soll zu Null geregelt werden!
        }
        return fehler;
    }
    public String getSimulation(double[] parameter)
    {
        StringBuffer text = new StringBuffer();
        double fehler = 0.0;
        simulator.init();
        simulator.setParameter(parameter); 
        simulator.simulieren();
        for(int i=0;i<simulator.getAnzahl();i++)
        {
            double y = (simulator.getY(i))[0];
            double t = (simulator.getT(i));
            fehler += y*y; //soll zu Null geregelt werden!
            text.append(t+" "+y+"\n");
        }
        return text.toString();
    }
}

Code 0-3: Klasse FehlerfunktionAntrieb

package opti;
import java.awt.*; //package awt für die paint()-Methode nötig.
import hilfsklassen.Dateioperationen;
public class OptimiererModGrad extends Optimierer
{
    /**Optimierungsvorgang auslösen. Wird von ergbenden Klassen überschrieben*/
    public void optimieren()
    {
        /**Faktoren, mit denen die Sprungweite beim Ändern eines  Parameters
        variiert wird.*/
        double[] faktor = {-2.0,-1.0,-0.5,0.0,0.5,1.0,2.0};
        double[] testfehler = new double[7];
        /**Vektorlänge in die Suchrichtung*/
        double[] laenge = new double[anzahlParameter];
        for(int i=0;i<anzahlParameter;i++)
            laenge[i]=1.0;
        /**Fehler mit aktuellem Parametersatz bestimmen:*/
        double fehler = fehlerfunktion.berechneFehler(startparameter);
        double fehler_best = fehler;
        double fehler_akt = fehler;
        double[] neueparameter = new double[anzahlParameter];        
        for(int i=0;i<anzahlParameter;i++)
            neueparameter[i] = startparameter[i];
        boolean fertig = false;
        int imerk=0,kmerk=0;
        while(fertig==false)
        {
            //Fehler der Varianten bestimmen:
            for(int i=0;i<anzahlParameter;i++)
            {
                for(int k=0;k<faktor.length;k++)
                {
                    neueparameter[i]+=laenge[i]*faktor[k];
                    fehler_akt = fehlerfunktion.berechneFehler(neueparameter); 
//                    if(fehler_akt<fehler_best )
//Ergänzung wg. Beschränkung auf 0..1:
                    if(fehler_akt<fehler_best && neueparameter[i]>=0.0 && neueparameter[i]<=1.0)
                    {
                        imerk=i;
                        kmerk=k;
                        fehler_best = fehler_akt;
                    }
                    neueparameter[i]-=laenge[i]*faktor[k];
                }
            }
            neueparameter[imerk]+=laenge[imerk]*faktor[kmerk];                   
            //fehler_best = fehlerfunktion.berechneFehler(neueparameter);
            if(kmerk!=3)             
               laenge[imerk]*=faktor[kmerk]; /**Sprungweite verbessern für nächsten Schritt*/
            if(fehler_akt-fehler_best<epsilon)
                fertig = true;
            fehler_akt = fehler_best;
System.out.println("aktueller kleinster Fehler: "+fehler_akt);
        }
        System.out.println("Start-Parametersatz:");
        for(int i=0;i<anzahlParameter;i++)
        {
            System.out.println("Parameter Nr.0: "+startparameter[i]);
        }
        System.out.println("Startfehler: "+fehler);
        System.out.println("Minimierter Fehler: "+fehler_best);
        System.out.println("Bester gefundener Parametersatz:");
        for(int i=0;i<anzahlParameter;i++)
        {
            System.out.println("Parameter Nr.0: "+neueparameter[i]);
        }
        String simulationsergebnis0 = fehlerfunktion.getSimulation(startparameter);
        String simulationsergebnis1 = fehlerfunktion.getSimulation(neueparameter);
        Dateioperationen.speichern("data0.txt", simulationsergebnis0);
        Dateioperationen.speichern("data1.txt", simulationsergebnis1);
    }
    /** paint(..) wird bei der Konsolenanwendung nicht verwendet.*/
    public void paint(Graphics2D g)
    {
    }
}

Code 0-4: Klasse OptimiererModGrad.

Vergleich zwischen Simulation des optimierten Reglers (blau) und des nicht optimierten (rot).

Bild 0-1: Vergleich zwischen Simulation des optimierten Reglers (blau) und des nicht optimierten (rot).

aktueller kleinster Fehler: 222.2821669258332
aktueller kleinster Fehler: 183.10416725903283
aktueller kleinster Fehler: 157.00082251201323
aktueller kleinster Fehler: 143.18553041541554
aktueller kleinster Fehler: 56.493369958083875
aktueller kleinster Fehler: 35.4414319488113
aktueller kleinster Fehler: 35.335773263982276
aktueller kleinster Fehler: 35.240669609315226
aktueller kleinster Fehler: 31.29837311789471
aktueller kleinster Fehler: 31.253479024528605
aktueller kleinster Fehler: 29.358361846503414
aktueller kleinster Fehler: 29.358361846503414

Code 0-5: Beispielverlauf der Fehlerreduktion durch den Optimierer.

pendelopt.zip - Download des obigen Projekts.