simulationen

SIMULATIONEN

 

 

SCHWARM SIMULATION

 

Schwarmverhalten ist ein in der Natur häufig auftretendes Phänomen. Einzelne Individuen einer Population verhalten sich so, als wären sie Teil eines grösseren Ganzen. Für die Individuen entstehen Vorteile bei der Flucht vor Fressfeinden durch kollektive Wachsamkeit und beim Energieverbrauch der Bewegung. In unserem Beispiel wird ein Vogelschwarm simuliert.

In deinem Programm ermittelst du die Nachbarknoten so, dass du von den 4 angrenzenden Zellen diejenigen auswählst, die nicht auf der Wand und nicht ausserhalb des Gitters liegen.

Ein Vogel im Schwarm möchte einerseits seinen Nachbaren nahe sein, andererseits möchte er Kollisionen vermeiden. Sein Verhalten lässt sich mit folgenden Regeln beschreiben:

1. Separation: Jeder Actor hält einen gewissen Abstand zu den Nachbaren, um mögliche Kollisionen zu vermeiden. Der Beschleunigungsvektor des Akteurs ist entgegengesetzt zum Vektor der Summe der Positionen der Nachbarn.

2. Aligment: hat zum Ziel, die Geschwindigkeit und Richtung an die Bewegung der Nachbarn anzugleichen. Der Geschwindigkeitsvektor des Akteurs wird als Mittelwert der Geschwindigkeitsvektoren der Nachbarn gebildet.

3. Cohesion: hat zum Ziel, den Schwarm zusammenzuhalten und lässt den Akteur möglichst nahe beim Nachbarn bleiben. Die Richtung des Beschleunigungsvektors des Akteurs zeigt in Richtung des gemeinsamen Schwerpunktes der Punktmassen der Nachbarn.

Programm:

# Swarm.py
from gamegrid import *
import math
import random

class Tree(Actor):
    def __init__(self):
        Actor.__init__(self, "sprites/tree1.png")

class Bird(Actor):
    def __init__(self):
        Actor.__init__(self, True, "sprites/arrow1.png")
        self.r = GGVector(0, 0)  # Position
        self.v = GGVector(0, 0)  # Velocity
        self.a = GGVector(0, 0)  # Acceleration
 
    # Called when actor is added to gamegrid
    def reset(self):
        self.r.x=self.getX()
        self.r.y=self.getY()
        self.v.x=startVelocity*math.cos(math.radians(self.getDirection()))
        self.v.y=startVelocity*math.sin(math.radians(self.getDirection()))
  
    # ----------- cohesion ---------------
    def cohesion(self, distance):
        return self.getCenterOfMass(distance).sub(self.r)

    # ----------- alignment --------------
    def alignment(self, distance):
        align = self.getAverageVelocity(distance)
        align = align.sub(self.v)
        return align

    # ----------- separation -------------
    def separation(self, distance):
        repulse = GGVector()
        # ------ from birds ------
        for p in birdPositions:
            dist = p.sub(self.r)
            d = dist.magnitude()
            if d < distance and d != 0:
                repulse = repulse.add(dist.mult((d-distance)/d))

        # ------ from trees ------
        trees = self.gameGrid.getActors(Tree)
        for actor in trees:
            p = GGVector(actor.getX(), actor.getY())
            dist = p.sub(self.r)
            d = dist.magnitude()
            if d < distance and d != 0:
               repulse = repulse.add(dist.mult((d-distance)/d))
        return repulse
  
    # ----------- wall interaction -------
    def wallInteraction(self):
        width = self.gameGrid.getWidth()
        height = self.gameGrid.getHeight()
        acc = GGVector()
        if self.r.x < wallDist:
            distFactor = (wallDist - self.r.x) / wallDist
            acc = GGVector(wallWeight * distFactor, 0)
        if width - self.r.x < wallDist:
            distFactor = ((width - self.r.x)-wallDist)/wallDist
            acc = GGVector(wallWeight * distFactor, 0)
        if self.r.y < wallDist:
            distFactor = (wallDist - self.r.y) / wallDist
            acc = GGVector(0, wallWeight * distFactor)
        if height - self.r.y < wallDist:
            distFactor = ((height - self.r.y)-wallDist)/wallDist
            acc = GGVector(0, wallWeight * distFactor)
        return acc
  
    def getPosition(self):
        return self.r
      
    def getVelocity(self):
        return self.v

    def getCenterOfMass(self, distance):
        center = GGVector()
        sum = 0
        for p in birdPositions:
            dist = p.sub(self.r)
            d = dist.magnitude()
            if d < distance:
                center = center.add(p)
                sum += 1
        if sum != 0:        
            return center.mult(1.0/sum)
        else:
            return center

    def getAverageVelocity(self, distance):
        avg = GGVector()
        sum = 0
        for i in range(len(birdPositions)):
            p = birdPositions[i]
            if (self.r.x - p.x)*(self.r.x-p.x) + \
               (self.r.y - p.y)*(self.r.y-p.y)<distance*distance:
                avg = avg.add(birdVelocities[i]);
                sum += 1
        return avg.mult(1.0/sum)

    def limitSpeed(self):
        m = self.v.magnitude()
        if m < minSpeed:
            self.v = self.v.mult(minSpeed / m)
        if m > maxSpeed:
            self.v = self.v.mult(minSpeed / m)

    def setAcceleration(self):
        self.a = self.cohesion(cohDist).mult(cohWeight)
        self.a = self.a.add(self.separation(sepDist).mult(sepWeight))
        self.a = self.a.add(self.alignment(aligDist).mult(aligWeight))
        self.a = self.a.add(self.wallInteraction())

    def act(self):
        self.setAcceleration()
        self.v = self.v.add(self.a) # new velocity
        self.limitSpeed()
        self.r = self.r.add(self.v) # new position
        self.setDirection(int(math.degrees(self.v.getDirection())))
        self.setLocation(Location(int(self.r.x), int(self.r.y)))

# global section 
def populateTrees(number):
    blockSize = 70
    treesPerBlock = 10
    for block in range(number // treesPerBlock):
        x = getRandomNumber(800 // blockSize) * blockSize
        y = getRandomNumber(600 // blockSize) * blockSize
        for t in range(treesPerBlock):
            dx = getRandomNumber(blockSize)
            dy = getRandomNumber(blockSize)
            addActor(Tree(), Location(x + dx, y + dy))
                
def generateBirds(number):
    for i in range(number):
        addActorNoRefresh(Bird(), getRandomLocation(), 
                                  getRandomDirection())
    onAct()  # Initialize birdPositions, birdVelocities
     
def onAct():
    global birdPositions, birdVelocities
    # Update bird positions and velocities
    birdPositions = []
    birdVelocities = []
    for b in getActors(Bird):
        birdPositions.append(b.getPosition())
        birdVelocities.append(b.getVelocity())
 
def getRandomNumber(limit):
    return random.randint(0, limit-1)

# coupling constants 
cohDist = 100
cohWeight = 0.01
aligDist = 30
aligWeight = 1
sepDist = 30
sepWeight = 0.2
wallDist = 20
wallWeight = 2
maxSpeed = 20
minSpeed = 10
startVelocity = 10
numberTrees = 100
numberBirds = 50

birdPositions  = []
birdVelocities  = []

makeGameGrid(800, 600, 1, False)
registerAct(onAct)
setSimulationPeriod(10)
setBgColor(Color.blue)
setTitle("Swarm Simulation")
show()
populateTrees(numberTrees)
generateBirds(numberBirds)
doRun()
► In Zwischenablage kopieren

 

 

ESPRESSO AUTOMAT

 

 

Im täglichen Leben machst du Bekanntschaft mit vielen Geräten und Maschinen, die du als Automaten auffassen kannst. Dazu gehören Getränkeautomaten, Waschautomaten, Geldautomaten, usw. Als Ingenieur und Informatiker entwickelst du einen solchen Automaten mit der klaren Vorstellung, dass dieser ausgehend von einem aktuellen Zustand schrittweise in einen Nachfolgezustand übergeht, der von Sensordaten und der Betätigung von Tasten und Schaltern abhängt.
 

Du entwickelst hier einen Espresso-Automaten, der 3 Zustände besitzt: Er kann ausgeschaltet (OFF), betriebsbereit (STANDBY) und am Kaffeepumpen (WORKING) sein. Zur Bedienung stehen 4 Drucktasten für die Funktionen Einschalten (turnOn), Ausschalten (turnOff), Kaffeepumpe einschalten (work), Kaffeepumpe ausschalten (stop) zur Verfügung.

Anschaulicher kannst du die Funktion der Kaffee-Maschine mit einem Automatengraph darstellen. Dabei stellst du die Zustände mit einem Kreis und die Übergänge als Übergangspfeile dar, die du mit den Eingaben/Ausgaben anschreibst.

 

Programm:

#Espresso.py
from gamegrid import *

def pressEvent(e):
    global state
    loc = toLocationInGrid(e.getX(), e.getY())
    if loc == Location(1, 2): # off
        state = "OFF"
        led.show(0)
        coffee.hide()
    elif loc == Location(2, 2): # on
        if state == "OFF":
            state = "STANDBY"
            led.show(1)
    elif loc == Location(4, 2): # stop
        if state == "WORKING":
            state = "STANDBY"
            coffee.hide()
    elif loc == Location(5, 2): # work
        if state == "STANDBY":
            state = "WORKING"
            coffee.show()
    setTitle("State: " + str(state))
    refresh()
        
state = "OFF"
makeGameGrid(7, 11, 50, None, "sprites/espresso.png", False, 
             mousePressed = pressEvent)
show()
setTitle("State: " + str(state))
led = Actor("sprites/lightout.gif", 2)
addActor(led, Location(3, 3))
coffee = Actor("sprites/coffee.png")
addActor(coffee, Location(3, 6))
coffee.hide()
refresh()
► In Zwischenablage kopieren