Optimierer für den Fuzzy-geregelten Pendel mit modifiziertem Gradientenverfahren
|
Kritische Anmerkungen hierzu:
|
Übung
|
|
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.
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.