Musterlösung für die Implementierung eines Schwarms in Java basierend auf gleitenden Scheiben
|
java_puck2.zip - Download der folgenden Java-Programme
Dynamisches Modell einer passiven gleitenden Scheibe
Bild 0-1: Simulationsmodell für eine passive gleitende Scheibe mit Dämpfung der Bewegung
|
Objektorientierte Umsetzung ohne Visualisierung mit Java unter Verwendung eines Runge-Kutta-Integrators
|
import java.io.*;
import java.util.*;
public class Hauptprogramm
{
private int puck_anzahl = 10;
private double t = 0.0;
private double dt = 0.1;
private int schritte = 10000;
public Modell[] modell;
public Integrator[] integrator;
private int iabs(int x)
{
if(x<0)
return -x;
else
return x;
}
public void init()
{
//Erzeugen aller Modelle
modell = new Modell[puck_anzahl];
for(int i=0;i<puck_anzahl;i++)
modell[i] = new Modell();
Random random = new Random(0);
//Zufällige Anfangsbedingungen für die Pucks setzen:
for(int i=0;i<puck_anzahl;i++)
{
modell[i].yalt[0] = (double)(50 + iabs(random.nextInt())%400);
modell[i].yalt[1] = 0.001*(double)(iabs(random.nextInt())%2000 - 1000);
modell[i].yalt[2] = (double)(50 + iabs(random.nextInt())%400);
modell[i].yalt[3] = 0.001*(double)(iabs(random.nextInt())%2000 - 1000);
}
//Erzeugen der zugehörigen Integratoren
integrator = new Integrator[puck_anzahl];
for(int i=0;i<puck_anzahl;i++)
integrator[i] = new Integrator(modell[i]);
}
private void zeitschritt()
{
for(int i=0;i<puck_anzahl;i++) //alle Pucks durchgehen
{
integrator[i].zeitschritt(t,dt);
}
}
public void simulieren()
{
for(int i=0;i<schritte;i++)
{
System.out.print(""+t);
for(int k=0;k<puck_anzahl;k++)
{
//Für Scilab Zeit und dann alle Koordinaten zeilenweise ausgeben
System.out.print(" "+modell[k].yalt[0]+" "+modell[k].yalt[2]);
integrator[k].zeitschritt(t,dt);
}
System.out.println();
t+=dt;
}
}
public static void main(String[] args)
{
Hauptprogramm hp = new Hauptprogramm();
hp.init();
hp.simulieren();
}
}
Code 0-1: Quellcode zu Hauptprogramm.java in puck01_passiv
public class Modell
{
public double[] param = {1.0,0.001};
public double[] yalt; //Im Modell den letzten Zustand merken
private int anzahl=4;
private double m;
private double D;
private double f;
public Modell()
{
yalt = new double[anzahl];
}
public double rechteSeite(double[] y,double t, int zeile)
{
m = param[0];
D = param[1];
switch(zeile)
{
case 0:
f = y[1];
break;
case 1:
f = -(D/m)*y[1];
break;
case 2:
f = y[3];
break;
default:
f = -(D/m)*y[3];
break;
}
return f;
}
public int holeAnzahlGleichungen()
{
return anzahl;
}
}
Code 0-2: Quellcode zu Modell.java in puck01_passiv
//Integrator, der ein Runge-Kutta-Verfahren verwendet.
//Bei Aufruf des Konstruktors wird ein Zeiger auf das zu integrierende Modell im
//Integrator-Objekt gespeichert.
public class Integrator
{
private Modell modell;
private double[] yneu;
private double[] yhilf;
private double[] k1,k2,k3,k4;
public Integrator(Modell modell)
{
this.modell = modell;
yneu = new double[modell.holeAnzahlGleichungen()];
yhilf = new double[modell.holeAnzahlGleichungen()];
k1 = new double[modell.holeAnzahlGleichungen()];
k2 = new double[modell.holeAnzahlGleichungen()];
k3 = new double[modell.holeAnzahlGleichungen()];
k4 = new double[modell.holeAnzahlGleichungen()];
}
void zeitschritt(double t,double dt)
{
for(int i=0;i<modell.holeAnzahlGleichungen();i++)
{
k1[i] = modell.rechteSeite(modell.yalt,t,i);
yhilf[i] = modell.yalt[i] + 0.5*dt*k1[i];
}
for(int i=0;i<modell.holeAnzahlGleichungen();i++)
{
k2[i] = modell.rechteSeite(yhilf,t,i);
yhilf[i] = modell.yalt[i] + 0.5*dt*k2[i];
}
for(int i=0;i<modell.holeAnzahlGleichungen();i++)
{
k3[i] = modell.rechteSeite(yhilf,t,i);
yhilf[i] = modell.yalt[i] + dt*k3[i];
}
for(int i=0;i<modell.holeAnzahlGleichungen();i++)
{
k4[i] = modell.rechteSeite(yhilf,t,i);
}
for(int i=0;i<modell.holeAnzahlGleichungen();i++)
{
yneu[i] = modell.yalt[i] + (dt/6.0)*(k1[i]+2.0*k2[i]+2.0*k3[i]+k4[i]);
}
//Neuen y-Wert als alten im Modell speichern:
for(int i=0;i<modell.holeAnzahlGleichungen();i++)
modell.yalt[i] = yneu[i];
}
}
Code 0-3: Quellcode zu Integrator.java in puck01_passiv
|
m=fscanfMat('test.txt');
//plot(m(:,1),sqrt(m(:,2).*m(:,2)+m(:,5).*m(:,5)));
plot(m(:,2),m(:,3),m(:,4),m(:,5), ... ,m(:,20),m(:,21));
Code 0-4: Skript, um folgende Ergebnisse zu zeigen.
Bild 0-2: Zurückgelegter Weg im Betrag von Puck Nr. 0 (Es ist die Dämpfung erkennbar)
Bild 0-3: Zurückgelegter Weg aller 10 simulierten Puck-Elemente in der Ebene
Ergänzen von Kollision
|
Bild 0-4: Ergänzung der dynamischen Gleichungen durch einen Term, der für jeden Puck bei durchdringen eines anderen Pucks proportional zu der Durchdringungstiefe eine Gegenkraft erzeugt.
|
public class Modell
{
public Modell[] puck;
public static int zaehler=0; //Zählt wieviele Pucks bereits erzeugt wurden.
public int nr; //Nummer des aktuellen Pucks
public double[] param = {1.0,0.001,30.0,20.0};
public double[] yalt; //Im Modell den letzten Zustand merken
public double[] yneu; //Veränderten Zustand innerhalb eines Zeitschritts auch merken.
private int anzahl=4;
private double m;
private double D;
private double K;
private double R; //Puckradius
private double f;
public Modell(Modell[] puck)
{
this.puck = puck; //Alle Pucks in jedem Puck-Objekt registrieren.
yalt = new double[anzahl];
yneu = new double[anzahl];
nr=zaehler; //Aktuell erstelltem Puck eine Nummer zuweisen.
zaehler++; //In statischer Variablen mitzaehlen, wieviele Pucks schon erstellt wurden.
}
public double rechteSeite(double[] y,double t, int zeile)
{
m = param[0];
D = param[1];
K = param[2];
R = param[3];
//Durch Kollisionen entstehende Zusatzkraft bestimmen.
//Alle anderen Pucks durchgehen.
double x_koll=0.0;
double y_koll=0.0;
for(int i=0;i<puck.length;i++)
{
if(i!=nr) //nur wenn Auswahl nicht aktueller Puck selbst ist.
{
double x1 = yalt[0];
double y1 = yalt[2];
double x2 = puck[i].yalt[0];
double y2 = puck[i].yalt[2];
double betrag = Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2)); //Distanz der Puck-Mittelpunkte nr und i
if(betrag<2.0*R && betrag!=0.0)
{
//Richtungsvektor bestimmen:
double ex = (x1-x2)/betrag;
double ey = (y1-y2)/betrag;
//Kraft hinzuaddieren:
x_koll += K*(2.0*R-betrag)*ex;
y_koll += K*(2.0*R-betrag)*ey;
}
}
}
switch(zeile)
{
case 0:
f = y[1];
break;
case 1:
f = -(D/m)*y[1]+x_koll/m;
break;
case 2:
f = y[3];
break;
default:
f = -(D/m)*y[3]+y_koll/m;
break;
}
return f;
}
public int holeAnzahlGleichungen()
{
return anzahl;
}
}
Code 0-5: Modell.java in puck02_kollision
import java.io.*;
import java.util.*;
public class Hauptprogramm
{
private int puck_anzahl = 10;
private double t = 0.0;
private double dt = 0.1;
private int schritte = 10000;
public Modell[] modell;
public Integrator[] integrator;
private int iabs(int x)
{
if(x<0)
return -x;
else
return x;
}
public void init()
{
//Erzeugen aller Modelle
modell = new Modell[puck_anzahl];
for(int i=0;i<puck_anzahl;i++)
modell[i] = new Modell(modell);
Random random = new Random(0);
//Zufällige Anfangsbedingungen für die Pucks setzen:
for(int i=0;i<puck_anzahl;i++)
{
modell[i].yalt[0] = (double)(50 + iabs(random.nextInt())%400);
modell[i].yalt[1] = 0.001*(double)(iabs(random.nextInt())%2000 - 1000);
modell[i].yalt[2] = (double)(50 + iabs(random.nextInt())%400);
modell[i].yalt[3] = 0.001*(double)(iabs(random.nextInt())%2000 - 1000);
}
//Erzeugen der zugehörigen Integratoren
integrator = new Integrator[puck_anzahl];
for(int i=0;i<puck_anzahl;i++)
integrator[i] = new Integrator(modell[i]);
}
public void simulieren()
{
for(int i=0;i<schritte;i++)
{
System.out.print(""+t);
for(int k=0;k<puck_anzahl;k++)
{
//Für Scilab Zeit und dann alle Koordinaten zeilenweise ausgeben
System.out.print(" "+modell[k].yalt[0]+" "+modell[k].yalt[2]);
integrator[k].zeitschritt(t,dt);
}
//alle neuen Zustaende als alte umkopieren vorbereitend auf den nächsten Integrationsschritt:
for(int ii=0;ii<puck_anzahl;ii++) //alle Pucks durchgehen
{
for(int k=0;k<modell[ii].yneu.length;k++)
modell[ii].yalt[k] = modell[ii].yneu[k];
}
System.out.println();
t+=dt;
}
}
public static void main(String[] args)
{
Hauptprogramm hp = new Hauptprogramm();
hp.init();
hp.simulieren();
}
}
Code 0-6: Hauptprogramm.java in puck02_kollision
//Integrator, der ein Runge-Kutta-Verfahren verwendet.
//Bei Aufruf des Konstruktors wird ein Zeiger auf das zu integrierende Modell im
//Integrator-Objekt gespeichert.
public class Integrator
{
private Modell modell;
private double[] yneu;
private double[] yhilf;
private double[] k1,k2,k3,k4;
public Integrator(Modell modell)
{
this.modell = modell;
yneu = new double[modell.holeAnzahlGleichungen()];
yhilf = new double[modell.holeAnzahlGleichungen()];
k1 = new double[modell.holeAnzahlGleichungen()];
k2 = new double[modell.holeAnzahlGleichungen()];
k3 = new double[modell.holeAnzahlGleichungen()];
k4 = new double[modell.holeAnzahlGleichungen()];
}
void zeitschritt(double t,double dt)
{
for(int i=0;i<modell.holeAnzahlGleichungen();i++)
{
k1[i] = modell.rechteSeite(modell.yalt,t,i);
yhilf[i] = modell.yalt[i] + 0.5*dt*k1[i];
}
for(int i=0;i<modell.holeAnzahlGleichungen();i++)
{
k2[i] = modell.rechteSeite(yhilf,t,i);
yhilf[i] = modell.yalt[i] + 0.5*dt*k2[i];
}
for(int i=0;i<modell.holeAnzahlGleichungen();i++)
{
k3[i] = modell.rechteSeite(yhilf,t,i);
yhilf[i] = modell.yalt[i] + dt*k3[i];
}
for(int i=0;i<modell.holeAnzahlGleichungen();i++)
{
k4[i] = modell.rechteSeite(yhilf,t,i);
}
for(int i=0;i<modell.holeAnzahlGleichungen();i++)
{
yneu[i] = modell.yalt[i] + (dt/6.0)*(k1[i]+2.0*k2[i]+2.0*k3[i]+k4[i]);
}
//Neuen y-Wert als neuen im Modell speichern (später umkopieren):
for(int i=0;i<modell.holeAnzahlGleichungen();i++)
modell.yneu[i] = yneu[i];
}
}
Code 0-7: Integrator.java in puck02_kollision
Bild 0-5: Resultat nach Ergänzung der Kollisionskräfte im Programm.