Hallo,
ich baue gerade eine Wettersimulation für mein Terrarium:
-Wind (Ventilationen)
-Nebel
-Regen
-Licht
Nun möchte ich für den Wind gerne naturnahe Schwankungen einbauen. mit
bestimmten Tendenzen.
Morgens und Abends eher kein Wind.
Tagüber darf es auch mal stärker pusten.
Jetzt habe ich ein wenig am PC rumprobiert und im prinzip das hier
gemacht:
1
intrandomWalk(intmoveSize){
2
staticintplace;// variable to store value in random walk - declared static so that it stores
3
// values in between function calls, but no other functions can mess with its value
4
5
place=place+(random(-moveSize,moveSize+1));
6
7
if(place<randomWalkLowRange){// check lower and upper limits
8
place=place+(randomWalkLowRange-place);// reflect number back in positive direction
9
}
10
elseif(place>randomWalkHighRange){
11
place=place-(place-randomWalkHighRange);// reflect number back in negative direction
12
}
13
14
returnplace;
15
}
Das Hat auf dem PC gut funktioniert, ich denke weil die Random Funktion
dort besser ist. Nur auf meinem Atmega(Arduino) ist die Random Funktion
leider mit einer recht starken tendenz belastet. Das fürt zu ständigen
Randbewegungen und dort bleibt es dann auch. Der gesammte bereich wird
nie genutzt. Habt Ihr eine Idee wie ich das besser machen kann? Ohne
Drift in eine bestimmte richtung.
LG,
Florian
jonas biensack schrieb:> Wie sieht dein randomSeed(); aus?Florian Roesner schrieb:> Ist der Nötig?jonas biensack schrieb:> Ich denke schon.
Nein, ist er nicht. der Seed veraendert lediglich die "Startbedingung".
Ohne seed bekommst bei jedem neustart des zufallszahlengenerators die
selben werte, z.B.
1,8,0,348,29,4, usw...
Das ist mit einem statischen seed (also hard gecoded, in etwa seed =
1337) nicht anders, nur das die zahlen jetzt andere sind, als ohne seed.
bei einem neustart des zufallszahlengeneratos mit dem gleichen seed
erhaelts du wieder die selben Zahlen, z.B. 96,111, 350,1,0 usw.
Der Seed sollte bzw. darf keine auswirkung auf das Verhalten des
Zufallszahlengenerators haben, so wie es hier beschrieben wurde.
Florian Roesner schrieb:> Das Hat auf dem PC gut funktioniert
int auf einem PC sind in der Regel 4 Byte gross, auf einem Atmega in der
Regel aber nur 2 Byte. Hast du das bedacht?
Florian Roesner schrieb:> place = place + (random(-moveSize, moveSize + 1));
Wenn movesize negativ ist so wird aus -movesize ein -(-movesize) was das
gleiche ist wie +movesize. ( 10 - (-5) = 15 )
D.h. im schlechtesten falle wird place immer groesser und groesse. Durch
das static wird place auch nie geloescht. Irgendwann kommt ein
ueberlauf...
Sicher das es das ist, was du willst?
Florian Roesner schrieb:> if (place < randomWalkLowRange){> place = place + (randomWalkLowRange - place);> }> else if(place > randomWalkHighRange){> place = place - (place - randomWalkHighRange);> }
Was passiert wenn place genau zwischen randomWalkLowRange und
randomWalkHighRange liegt? sicher das du dann einfach nur place zurueck
geben willst?
Wie sind randomWalkLowRange und randomWalkHighRange definiert?
Florian Roesner schrieb:> Das fürt zu ständigen> Randbewegungen und dort bleibt es dann auch.
Wenn du erstmal am Rand bist, dann bleibst du bei einem Random Walk halt
tendentiell auch in Randnähe. Warum denn nicht?
Oder löst der sich nie mehr vom Rand?
ich finde deinen ansatz komisch.
Mit einem Rauschgenerator für weißen gaussches Rauschen kommst in
Verbindung mit einer Fensterfunktion viel natürlicher weg....
Arduino-Krankheit... vorgefertigtes schränkt die Möglichghkeiten und die
Kreativität ein. Ist halt für kinder und FH-Abslventen ;-)
> Wenn du erstmal am Rand bist, dann bleibst du bei einem Random Walk halt> tendentiell auch in Randnähe. Warum denn nicht?>> Oder löst der sich nie mehr vom Rand?
Es löst sich eher schlecht
> Wie sind randomWalkLowRange und randomWalkHighRange definiert?
in diesem Fall:
randomWalkLowRange = 0;
randomWalkHighRange = 255;
> Wenn movesize negativ ist so wird aus -movesize ein -(-movesize) was das> gleiche ist wie +movesize. ( 10 - (-5) = 15 )
Wird nicht passieren, da ich keine Negativen eingebe ^^
> ich finde deinen ansatz komisch.> Mit einem Rauschgenerator für weißen gaussches Rauschen kommst in> Verbindung mit einer Fensterfunktion viel natürlicher weg....
Muss man halt auch erstmal kennen. Dafür sind solche Orte hier ja da Für
Informationsaustausch, es geht ja nicht alles zu kennen.
Ich schau mir mal das Gauß'sche Rauschen an :)
das Rauschen ist mittelwertfrei und du kannst über die
Standardabweichung die "härte" einstellen. (Wie stark/oft sind die
richtig krassen ausreiser?)
Wenn du das Rauschen etwas tiefpassfilterst, bekommt man recht
zufälliges verhalten hin.
Du kannst dann eine grobe Hüllkurve designen, sodass zu abends und
morgens ruhe hast. also eine art Gaußglocke, oder einen Sinusberg oder
sowas.
Wenn du auf diese Hüllkurve noch etwas rauschen addierst, hast du jeden
tag ein anderes verhalten.
Zum schluss bekommst du:
(Hüllkurve+Rauschen1_Langzeit)*Rauschen2_kurzzeit.
Das weiße gaussche rauschen wird Werte außerhalb deines Wertebereichs
genrieren. Du kannst den Output einfach auf einen bereich begrenzen und
über die standardabweichung z.B. festlegen, dass die werte nur zu 5% der
Zeit gesättigt sind. Das ist alles recht einfach, da es nur von ein paar
Parametern abhöngt die man sehr gut auch per experiment bestimmen kann.
Florian Roesner schrieb:>> Wenn movesize negativ ist so wird aus -movesize ein -(-movesize) was das>> gleiche ist wie +movesize. ( 10 - (-5) = 15 )> Wird nicht passieren, da ich keine Negativen eingebe ^^
Dann mach auch bitte den parameter als unsigned int, nur so als tipp.
Und noch ein tipp:
du solltest place vielleicht initialisieren...
Florian Roesner schrieb:> static int place;
Ich weiss grad nicht wie es bei static variablen ist, aber so
Florian Roesner schrieb:> place = place + (random(-moveSize, moveSize + 1));
addierst du auf irgendeinen wert etwas drauf.
Variablen immer initialisieren, und wenn es nur mit 0 ist. Spart im
schlimmsten falle tage lange fehler suche.
Kaj schrieb:> Variablen immer initialisieren, und wenn es nur mit 0 ist. Spart im> schlimmsten falle tage lange fehler suche.
static (sowie alle globalen Variablen) sind immer mit 0 initialisiert.
In deinen Formeln zur Korrektur von place falls es außerhalb der Range
ist fehlt ein Faktor 2.
Zur Zeit wird der Wert nur auf randomWalkLowRange bzw.
randomWalkHighRange korrigiert und nicht "reflect"ed.
Ein Random-Walk hat nunmal die Tendenz, wegzulaufen. Der Erwartungswert
für die Entfernung nimmt mit der Wurzel der Anzahl Schritte zu. Du
kannst einen noch so guten Zufallsgenerator haben, du wirst immer am
Rand landen.
Die Idee mit der rücktreibenden Kraft finde ich deshalb gut. Du kannst
es z.B. als Kugel in einer Parabel a*x^2 modellieren. Die Kugel erfährt
zufällige Stösse nach links und rechts, aber je weiter sie von x = 0
entfernt ist, desto steiler ist dort die Parabel und desto stärker auch
die rücktreibende Kraft.
Bewegungsgleichung:
Kraft F = a * x + zufälliger Stoss
Geschwindigkeit v = v + F / m
Position x = x + v
Eine Hüllkurve über den Tagesverlauf könnte man implementieren, indem
man a und der Betrag der zufälligen Stösse über den Tagesverlauf
variiert.
Siebzehn Zu Fuenfzehn schrieb:> Wenn die ruecktreibenede Kraft proportional der Auslenkung ist, dann> erhaelt man, ohne Random Walk, einen Sinusgenerator. Also aufpassen
Das ist auch ungefähr, was man haben möchte. Eine Kurve, die periodisch
auf- und ab geht, mit einer hohen Zufälligkeit darin. Man könnte
zusätzlich noch eine Dämpfung/Reibung einbauen. Die Steigung der
Parabel, die Reibung und die Stärke der Stösse sollten viele
Möglichkeiten zum Formen der Kurve ergeben. Anstatt eine Parabel kann
man sich jede andere Rückstellfunktion vorstellen.