Wenn ich vor Sonnenaufgang gehe, trage ich zwei Taschenlampen mit; Jeder hat eine Akkulaufzeit von etwa 5 Stunden und die Wanderung dauert etwa eine Stunde. Ich versuche, die gleiche Taschenlampe zu verwenden, bis sie leer ist, und etwa jeden fünften Tag kann ich während des Spaziergangs das Licht wechseln. Die alte Lampe wird aufgeladen und ich versuche mich daran zu erinnern, welche ich am nächsten Tag verwenden soll. Dieser Plan funktioniert eigentlich ziemlich gut, auch wenn ich am nächsten Tag vergesse, das Licht auszuschalten.
Aber was würde passieren, wenn ich jeden Tag zufällig eine Taschenlampe auswähle? Wie oft würde ich damit rechnen, zwei 15-minütige Lichter zu haben und in der zweiten Hälfte des Spaziergangs kein Licht? Die beigefügte JSL ist eine Simulation, die versucht, die Frage zu beantworten; Sehen wir uns zunächst die Antwort an:
The red dots below 0 show where the two flashlights both failed, and how badlyDie roten Punkte unter 0 zeigen, wo und wie stark die beiden Taschenlampen ausgefallen sind
In der Titelleiste steht, dass es sich bei dieser Simulation um zwei Lampen handelte, eine mit einer Akkulaufzeit von mehr als 4 Stunden und die andere mit einer Akkulaufzeit von mehr als 5 Stunden. An den meisten Tagen verbleiben noch mehrere Stunden im Lichterpaar. Die JSL beginnt mit einer Benutzerfunktion, machbar , da der Code unten wiederverwendet wird, um ein weiteres Diagramm zu erstellen.
maketable = function({capacity},// an array with the battery capacities expressed as time
{dt,charge,ontime,today,remainingWalkTime,message,light,usage,deadBatteries},//localsDer erste Satz von {geschweiften Klammern} enthält den Parameter für die Funktion. Kapazität , eine kleine Matrix mit der Stundenkapazität jeder Taschenlampe. Der zweite Satz enthält die lokalen Variablen für die Funktion; Wenn die JSL, die die Funktion aufruft, zufällig dieselben Variablennamen verwendet, werden die Variablen des Aufrufers von dieser Funktion nicht geändert.
charge = capacity; // charge[] tracks the remaining charge
// expression that computes random on time for flashlight
ontime = Expr(
As Date( In Hours( Min( 2, Max( .5, Random Normal( 1, .1 ) ) ) ) ) // usually about 1-hour walk
);
// table to collect results
dt = New Table( "Light Schedule",
Add Rows( 1 ),
New Column( "day", Numeric, "Ordinal", Format( "m/d/y", 10 ), Input Format( "m/d/y" ), Set Values( {1feb2020} ) ),
New Column( "hoursAvailable", Numeric, "Continuous", Format( "hr:m", 12 ), Set Values( {sum(charge)} ) ),
New Column( "notes", Character, Set Values( {"Two fully charged lights"} ), Set Display Width( 500 ) ),
Set Label Columns( :notes )
);Oben werden die Akkus durch das Kopieren zunächst vollständig aufgeladen Kapazität hinein Aufladung . Dann wird ein Ausdruck zugewiesen pünktlich , was die Verteilung meiner Gehzeiten darstellt ... eine Stunde, mehr oder weniger. Und schlussendlich, dt wird auf eine neue Datentabelle festgelegt, die diese Funktion schließlich an den Aufrufer zurückgibt. Die Tabelle enthält eine Tageszählerspalte, eine Spalte, die anzeigt, wie viele Stunden nach dem Spaziergang im Taschenlampenlicht zur Verfügung standen, und eine Spalte mit computergenerierten Notizen darüber, was passiert ist.
// run the simulation for about 10 years
For( today = 2feb2020, today <= 2dec2029, today += In Days( 1 ),
remainingWalkTime = ontime; // gets a new random duration for the length of an early morning walk
message = Format( remainingWalkTime, "hr:m" ) || " --"; // total walk duration
While( remainingWalkTime > 0 & Sum( charge ) > 0, // also give up when there are no charged lights remaining
// choosing randomly might be too slow if there are many uncharged lights, but there are only 2 or 3...
light = Random Integer( N Rows( capacity ) ); // choose from available lights
If( charge[light] > 0, // if it is a charged light, use it
usage = Min( remainingWalkTime, charge[light] ); // only take what is needed, up to available charge
remainingWalkTime -= usage;
charge[light] -= usage;
message ||= " light " || Char( light ) || "(" || Format( usage, "hr:m" ) || ")";
);
);Der erste Teil der Simulationsschleife oben durchläuft die Tage von 2020 bis 2030. (Die Datumsangaben werden eigentlich nur zur Beschriftung des Diagramms verwendet; die Dauer beträgt etwa 10*365 Tage ... Sie werden später etwa 3500 Zeilen in der Tabelle sehen.) verbleibendeGehzeit wird auf etwa eine Stunde eingestellt und wird zum Anfangswert für Nachricht , das etwas mehr Text enthält, der zu den Notizen für den Tag wird. Innerhalb der For-Schleife gibt es eine While-Schleife, die zufällig eine Taschenlampe für einen Teil des Spaziergangs auswählt. Die For-Schleife wählt so lange Taschenlampen aus, bis die Wanderung beendet ist oder keine Taschenlampen mehr mit Restladung vorhanden sind. Das gewählte Licht ist entweder aufgebraucht oder reicht aus, um den Spaziergang zu beenden. Anschließend wird die Meldung aktualisiert, um anzugeben, welches Licht wie lange verwendet wurde.
// update data table
dt << addrows( 1 );
If( remainingWalkTime > 0,
Row State() = Color State( "red" );
// the next line makes the charge go below zero on the first battery;
// that makes column 1 have negative numbers, and makes the graph do
// a better job of visualizing how long the walk in the dark lasted.
message ||= " walked in the dark(" || Format( remainingWalkTime, "hr:m" ) || ")";
charge[1] -= remainingWalkTime;
remainingWalkTime = 0; // maybe the sun is coming up
);
dt:day = today;
dt:hoursAvailable = sum(charge);
dt:notes = message;
// recharge any dead batteries
deadBatteries = Loc( charge <= 0 );
charge[deadBatteries] = capacity[deadBatteries];
message ||= " recharged" || Char( deadBatteries );
);Der letzte Teil der Simulation oben fügt der Tabelle eine Zeile zur Darstellung hinzu Heute , färbt es rot, falls vorhanden verbleibendeGehzeit übrig bleibt, und setzt die Tag , Stunden verfügbar , Und Anmerkungen für die neue Zeile. Abschließend werden die Batterien wieder aufgeladen; Die loc Die Funktion findet die Indizes oder Positionen in der Ladungsmatrix, die unter Null gefallen sind. Anschließend wird der Ladewert nur für diese Standorte auf den Kapazitätswert zurückgesetzt.
dt; // return value
);
Und das (oben) beendet die Funktion; Der Wert der letzten Anweisung wird an den Aufrufer zurückgegeben. dt Für sich genommen ist es eine wirklich einfache Aussage, die Folgendes ergibt: dt . Sie können auch die Return-Funktion verwenden: return(dt); irgendwo in der Funktion.
// the following line determines how many flashlights are in the simulation
capacity = matrix({In Hours( 4.3 ),In Hours( 5.6 )}); // one battery is much older, less capacity.
dt = maketable(capacity);
// graph the results
dt << Graph Builder(
Size( 1388, 500 ),
Show Control Panel( 0 ),
Show Legend( 0 ),
Variables( X( :day ), Y( :hoursAvailable ) ),
Elements( Points( X, Y, Legend( 9 ) ) ),
SendToReport(
Dispatch( {}, "Graph Builder", OutlineBox, {Set Title( title="h:m battery capacities: "; for(icap=1,icap<=nRows(capacity),icap+=1,title||=format(capacity[icap],"hr:m")||" ";); title )} ),
Dispatch({},"day",ScaleBox, {Format( "m/d/y", 10 ), Min( 3660681600 ), Max( 3976300800 ), Interval( "Year" ), Inc( 2 ), Minor Ticks( 0 )}),
Dispatch( {}, "graph title", TextEditBox, {Set Text( "Available flashlight time at end of walk" )} ),
Dispatch( {}, "Y title", TextEditBox, {Set Text( "Hours:Minutes" )} ),
Dispatch( {}, "400", LegendBox, {Set Title( "" )} )
)
);Rufen Sie schließlich oben an machbar mit einem Kapazität das definiert zwei Batterien. Der dt Links vom = befindet sich eine globale Variable, der das Ergebnis der Funktion rechts vom = zugewiesen wird. Der dt in der Funktion befindet sich in der lokalen Liste am Anfang der Funktion und ändert die globale nicht dt . Sobald die Datentabelle erstellt ist, kann der Graph Builder das Diagramm erstellen (ganz oben). Schreiben Sie kein Graph Builder-Skript von Grund auf! Verwenden Sie die GUI, um das Gewünschte zu erhalten, und speichern Sie dann das Skript. Ich habe dieses bearbeitet, um den benutzerdefinierten Gliederungstitel mit den Batteriekapazitäten hinzuzufügen.
Die vom Graph Builder (oben) verwendete Tabelle sieht folgendermaßen aus:
Output from maketable() function showing (negative) hours and notesAusgabe der Funktion maketable() mit (negativen) Stunden und Notizen
Da maketable() ein Argument für die Kapazität der Batterien benötigt, kann ich es mehrmals ausführen. Ich habe nicht wirklich vor, zusätzliche Taschenlampen mitzunehmen, aber ich möchte wissen, wie viele Taschenlampen mit welcher Kapazität das Problem am besten lösen. Hier ist eine JSL, die maketable aus einer Schleife aufruft und eine weitere Tabelle mit Antworten aus den von maketable zurückgegebenen Tabellen sammelt:
// make a table-of-tables; use from 1 to 10 flashlights with batteries from 1/16 to 32 hours
dtreport = New Table( "lights",
New Column( "nBats", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [] ) ),
New Column( "batSize", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [] ) ),
New Column( "nfailures", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [] ) ),
New Column( "darkHours", Numeric, "Continuous", Format( "Best", 12 ), Set Values( [] ) )
);
dtreport ist die Datentabelle, die die aggregierten Antworten enthält.
For( nLights = 1, nLights <= 10, nLights += 1,
For( batLife = 1 / 16, batLife <= 32, batLife *= 2,
dt = maketable( Repeat( inhours(batLife), nLights ) );
Oben durchläuft ein Schleifenpaar 100 Kombinationen, wodurch eine neue entsteht dt jedes Mal.
// count the failures and duration of failures
remaining = dt[0, "hoursAvailable"];
failures = Loc( remaining < 0 );
nfail = N Rows( failures );
darkSum = As Date( -Sum( remaining[failures] ) );
dtreport<<ADDROWS></ADDROWS>
Über, übrig packt die Stunden verfügbar Spalte als Matrix, damit ich sie verwenden kann loc() erneut, um die zu finden Misserfolge.Ich habe die Anzahl der Ausfälle und die Gesamtzeit der Ausfälle ausprobiert und in der Grafik ähnliche Ergebnisse erhalten. Fügen Sie eine Zeile hinzu dtreport Tabelle und füllen Sie sie aus.
Close( dt, "nosave" );
)
);
Schließen Sie die dt-Tabellen in der Schleife, wenn sie nicht mehr benötigt werden, damit nicht 100 Fenster geöffnet sind.
Nun sieht die soeben erstellte Tabelle so aus:
.0625 hour will probably never be enough, even with 10 flashlights0,0625 Stunden werden wahrscheinlich nie ausreichen, selbst mit 10 Taschenlampen
Ich kann sehen, dass mehr Lichter und bessere Batterien hilfreich sind. Die JSL (aus der grafischen Benutzeroberfläche des Graph Builders gespeichert) sieht folgendermaßen aus
dtreport<<GRAPH builder=""></GRAPH>
Und die resultierende Grafik:
More flashlights or more batteries keeps me out of the darkMehr Taschenlampen oder mehr Batterien halten mich von der Dunkelheit fern
Das Konturdiagramm zeigt die Ergebnisse der 100 Simulationen; Es scheint, dass drei Taschenlampen mit einer Kapazität von 17 Stunden oder vier mit einer Kapazität von 8 Stunden ausreichen könnten. Aber mit nur zwei Taschenlampen, der zufälligen Auswahl eines Lichts und dem Aufladen nur, wenn es leer ist, gibt es möglicherweise keine Kapazität, um das Licht anzuhalten.