Lektion 10: Trafiksimulering
Denna lektion innehåller Obligatorisk uppgift 5 (OU5) som består av fyra deluppgifter
Moment: | Objektorienterad design och implementation. Simulering. Flera samverkande klasser. |
Uppskattad arbetstid: | Schemalagd handledningstid inkl redovisning: 12 timmar. Utöver det räkna med eget arbete med lika många timmar. |
Arbetssätt: | Arbeta gärna tillsammans med någon, men skriv egen kod. Diskutera med varandra
Tips: Använd debuggern |
Redovisning: | Obligatorisk redovisning enligt anvisningar på kurssidan.
Notera att den pythonkod du redovisar skall följa kodningsreglerna Speciellt:
|
Backup: | När du arbetar på egen dator måste du se till att det löpande görs backup på de filer (py-filer) som du skapar under kursens gång. Om du har filerna enbart lagrade på din dator finns risk att allt försvinner vid ett datorhaveri eller vid stöld. |
Samarbete, fusk och plagiat: |
|
Simuleringar
Ett stort användningsområde för datorer är simuleringar d.v.s. att man skapar en datormodell av någon process (i vid bemärkelse) som man vill studera. Det kan röra sig om en modell för vädret eller klimatet, för hur snödrivor bildas kring olika byggnader, för trafikflödet i ett gatunät eller för en värld med sköldpaddor som föds, äter, lever och dör.
Meningen med modellen är att man skall kunna göra förutsägelser om vad som händer om man ändrar olika parametrar (släpper ut mer koldioxid, ändrar byggnadens form, gör en rondell eller ger sköldpaddorna mer mat ...).
Det är i regel väsentligt billigare att experimentera med en datormodell än att göra det i verkligheten (bygga en eller flera olika rondeller) eller att göra det med fysiska modeller (bygga modellhus och blåsa potatismjöl på dem i en vindtunnel).
När man bygger modeller så måste man i regel förenkla och bortse från många detaljer som man inte tror har någon eller åtminstone bara liten effekt.
Ett sätt att göra simuleringar är att dela upp tiden i ett antal diskreta tidssteg. Man utgår från ett starttillstånd och stegar sig sedan fram i tiden och noterar vad som händer i varje tidssteg:
Ibland kan man veta exakt vad som sker i varje steg men oftast har man bara approximationer. Dessutom kan det finnas ett visst mått av slump som man får approximera med någon sannolikhet.
Problembeskrivning
Antag att vi skall simulera ett trafikflöde genom en korsning. Exempelvis följande:
Korsningen Kungsängsleden/Valsätravägen och Dag Hammarskölds väg![]() |
Trafik kommer från öster (in). Skall vidare västerut (W) eller söderut (S).
![]() |
Program skall skrivas som ska simulera trafikflödet i olika typer av trafiksystem. Ett trafiksystem består, i vårt fall, av körfält (oftast kallat filer), trafiksignaler och köer. Vägar byggs upp av filer men vi kommer inte ha några vägobjekt.
Exempel 1
En väg med en trafiksignal:
Exempel 2
En väg med en svängfil och två ljussignaler:
Exempel 3
En korsning:
Korsningen kontrolleras alltså av de fyra ljussignaler s1, s2, s3 och s4.
Ett problem i denna typ av korsningar är att fordon som kommer från E
och vill svänga vänster mot S
i korsningen blir blockerade
av fordon som kommer från W
vilket i sin tur blockerar fordon
som vill köra rakt fram.
Exempel 4
För att lösa problemet kan man bygga svängfiler för fordon som kommer från
E
respektive W
och som skall vänster i korsningen d.v.s.
man vill ha en korsning av detta utseende:

Denna korsning har alltså svängfiler kontrollerade av signalerna vid s2 och s5.
En typisk fråga är då hur långa svängfilerna ska göras för att undvika att köerna på dessa växer in i de andra filerna.
Datormodell
Ett trafiksystem ska byggas upp av två generella komponenter:
trafikljus (klassen Light
) och körfält (klassen Lane
).
Det innehåller också ett varierande antal fordonsobjekt (klassen Vehicle
).
Vi kommer också behöva köer men sådana representeras enkelt med listor.
Vidare används klassen
Destinations
för att simulera ankomster av fordon till systemet.
- Klassen
Destinations
får du färdig - Klassen
Vehicle
får du också färdig - Klassen
Lane
får du närapå färdig, en metod skall modifieras. - Klassen
Light
skall du skriva.
Klassen Destinations
Denna klass används för att simulera ankomster av nya fordon till trafiksystemet.
Varje anrop till dess step
-metod returnerar antingen None
,
som anger att inget fordon kom i detta steg,
eller en destination ('W'
eller 'S'
).
Klassen skulle kunna baseras på uppmätta eller uppskattade intensiteter vid olika tidpunkter på dygnet men i vårt fall returnerar den en förutbestämd sekvens. Detta gör det enklare att förutsäga resultatet och därmed också kontrollera att programmet är korrekt.
Klassen är helt given och behöver inte ändras. Den kan hämtas här: fDestinations.py. I denna fil finns även kod för att testa klassen..
Övn 1: Testkör denna fil, för att se hur klassen Destinations fungerar.
- Du ser att ett objekt av klassen Destinations alltid ger samma sekvens av värden 'W', 'S' eller None mha metoden
step
. - Läs igenom koden till klassen.
Klassen Vehicle
Klassen Vehicle
är mycket enkel.
Dess uppgift är bara att hålla reda på när fordonet skapades och vart det ska.
Ett fordon behöver alltså inte veta var det är, inte titta på signaler och
inte kunna se andra fordon. Fordonen kan betraktas som pjäser som flyttas
av "någon annan".
Klassen är helt given och skall ej ändras. Koden (definitionen) finns i samma fil som klassen Lane
. Se längre ned.
Klassen Lane
En fil är en struktur som innehåller ett antal fordon och ett antal tomrum.
Fordonen kan bara komma in i början
och lämna i slutet av filen d.v.s. filen är som ett "rör":

Anmärkning: I fortsättningen använder vi ordet fil eller fil-objekt för att beteckna ett körfält och datafil eller Python-fil för att beteckna filer i datorns filsystem.
Klassen Lane
är given, bortsett från en metod som skall skrivas klart. I övrigt skall den inte ändras.
Klassen kan hämtas här: fVehicleAndLane_Stud.py. I denna fil finns även klassen
Vehicle
samt kod för att testa dessa båda klasser. (Kommentarerna i filen ser kanske lite konstiga ut för tecknen å, ä och ö, men när du laddar ned filen och öppnar
den i exvis Thonny visas dessa tecken som normalt.)
Övn 2: Testkör denna fil, för att se hur klasserna Vehicle och Lane fungerar.
- Du ser att koden börjar med att skapa en fil som initialt är tom (består av tio positioner) och skriver först ut:
[..........]
En pkt betyder att positionen i filen är ledig. - Vartannat tidssteg skapas ett fordon som kommer in från höger och läggs in i filen. Efter några tidssteg ser det ut så här:
[..N.S.S.S.]
Det betyder att det finns fyra fordon i filen, en med destination N och tre med destination S. - Du ser att koden löpande skriver ut:
Number in lane: 99
dvs hur många fordon som finns i filen. Att koden alltid skriver ut 99 beror på att metodennumber_in_lane()
ej är korrekt. Att modifiera denna, utgör uppgift A. - Vart 3:e tidssteg lämnar ett fordon filen (dess 1:a position) och då görs en utskrift, exvis:
out: Vehicle(N, 0)
Vilket betyder att fordonet med destination N som skapades vid tiden 0 lämnar. Om det inte finns något fordon i filens 1:a position skrivs följande ut:
out: None - Läs igenom koden till respektive klass för att förstå vad den gör.
Uppgift A: Modifiera metoden number_in_lane
i klassen Lane
Du skall modifiera metoden så att den beräknar och returnerar korrekt värde, se beskrivning ovan.
Uppgift B: Skriva klassen Light
Klassen används för att representera trafiksignaler.
Se diskussion och specifikation av klassen.
Filen fLight_Stud.py finns att hämta som
innehåller ett minimalt skal till klassen Light
och kod som testar klassen om/när den är färdig.
Klassen skall du skriva färdigt så att den passar specifikationen och den kod som testar den.
(Kommentarerna i filen ser kanske lite konstiga ut för tecknen å, ä och ö, men när du laddar ned filen och öppnar
den i exvis Thonny visas dessa tecken som normalt.)
Klassen TrafficSystem
Denna klass definierar ett specifikt trafiksystem. Den håller reda på vilka filer och vilka signaler som ingår och hur fordonen ska flyttas genom systemet.
För att t.ex. representera systemet i exempel 1 behövs två filer och en signal:


Exempel 1
Det som skall representeras är följande:
d.v.s. ett system med två filer och en trafiksignal. Till systemet hör också en kö av inkommande fordon, till höger.
Detta görs av klassenTrafficSystem1
som finns färdig att hämta från: fTrafficSystem1_Stud.py, förutom en metod som skall modifieras, se uppgift C.
Filen innehåller också kod som testar klassen TrafficSystem1
. (Kommentarerna i filen ser kanske lite konstiga ut för tecknen å, ä och ö, men när du laddar ned filen och öppnar
den i exvis Thonny visas dessa tecken som normalt.)
Övn 3: Testkör denna fil, för att se hur trafiksystemet fungerar.
- Du ser att koden för varje tidssteg skriver ut en beskrivning av hur trafiksystemet ser ut. Vid tiden 0 ser det ut så här:
0: ( 0) [.....](G)[.....] []
vilket betyder: vid tiden 0, är det sammanlagt 0 fordon i de båda filerna, inga fordon i den första filen, trafikljuset visar Grönt, inga fordon i den andra filen och inga fordon i kön. - Vid tiden 6 ser det ut så här:
6: ( 0) [....S](G)[SSSSW] []
vilket betyder: vid tiden 6, är det sammanlagt 0 fordon i de båda filerna, ett fordon i den första filen, trafikljuset visar Grönt, fem fordon i den andra filen och inga fordon i kön. Det bör givetvis vara sammanlagt 6 st fordon, vilket tyder på ett fel i koden, nämligen i metodennumber_in_system
i klassenTrafficSystem1
. Den metoden skall returnera det totala antalet fordon som för ögonblicket är i systemet. Ändra metoden, detta är uppgift C. - Vid tiden 9 ser det ut så här:
9: ( 0) [.SSS.](R)[SSWSS] ['S']
vilket betyder: vid tiden 9, är det sammanlagt 0 fordon i de båda filerna, tre fordon i den första filen, trafikljuset visar Rött, fem fordon i den andra filen och ett fordon i kön. Det bör givetvis vara sammanlagt 9 st fordon, men det beror ju som sagt på ett fel i metodennumber_in_system
. - Läs igenom koden i klassen
TrafficSystem1
för att förstå vad den gör.
Uppgift C: Modifiera metoden number_in_system
i klassen TrafficSystem1
Se beskrivning i ovan text. Notera att metoden skall utnyttja andra lämpliga metoder för att lösa dess uppgift, om sådana finns.
Bekräfta att det fungerar genom att köra testkoden i fTrafficSystem1_Stud.py.
När metoden fungerar, gå vidare med övning 4.Övn 4: Testa trafiksystemet genom att ändra trafikljusets rytm.
- Om det hela tiden är grönt ljus bör fordonen löpa helt fritt genom systemet.
- Om det oftare är rött än grönt bör kön av fordon växa kontinuerligt.
Uppgift D: Det andra trafiksystemet
Det som skall representeras är följande:
Börja med göra en kopia av din python-fil fTrafficSystem1_stud.py
(det fungerande första systemet). Döp kopian till fTrafficSystem2_Stud.py
eftersom detta program skall simulera det andra systemet. I filen, byt klassens namn TrafficSystem1
till TrafficSystem2
.
Trafiksystemet ska således bestå av tre filer (lane
, lane_west
och
lane_south
)
och ljussignalerna light_west
och light_south
(tidigare kallade s1 och s2) samt en inkommande kö av fordon vid E:

Det kan vara snyggt att ha korta körfiler efter (till vänster om) signalerna så att man ser hur fordonen passerar.
Vid punkten E
finns det en kö (ej utritad).
Vid ett tidssteg kan en eller flera av följande saker hända i denna ordning:
-
Ett fordon från vardera
lane_west
ochlane_south
passerar sin signal (om den är grön). -
Filerna
lane_west
ochlane_south
stegas. -
Ett fordon omedelbart till höger om
X
flyttas tilllane_west
ellerlane_south
beroende på dess destination (W
ellerS
). Om platsen på destinationsfilen inte är ledig står fordonet kvar och delningspunkten räknas som blockerad. -
Fordonen på
lane
stegas. -
Ett fordon anländer till systemet vid punkten
E
och ställs i kön. -
Om sista platsen i
lane
är ledig och det finns fordon i kön tas första från kön till sista platsen ilane
. - Ljussignalerna stegas.
En simulering består alltså av en tidsstegning där ovanstående saker händer.
Det är lämpligt att momenten, precis som i verkligheten, utförs i den ordning de står ovan. Det kan vara praktiskt att låta din step
-metod i sin tur anropa olika metoder du själv introducerar för att ta hand om olika delar. Det kan minska mängden upprepad kod i step
och göra den mer överskådlig.
Observera att klasserna Vehicle
, Lane
och Light
inte ska behöva
ändras - endast TrafficSystem
behöver göras om.
Indata till en simulering
Programmet styrs av följande indata:
-
takten som fordon anländer till
E
, -
andelen fordon som skall svänga d.v.s. ha
S
som destination, - längderna på filerna och
- ljussignalernas karakteristik (period och grönperiod).
De två första värdena varierar vanligen med tiden.
Detta hanteras av klassen Destination
.
I verkliga simuleringar skulle klassen producera fordon enligt uppmätta intensiteter men, för att
ni ska få kontrollerbara resultat, ger denna version samma sekvens varje gång.
Värdena i de två sista punkterna, d.v.s. längderna på filerna och ljussignalernas karakteristik, får du bestämma själv. Prova dock nedanstående och jämför med den statistik som visas längre ner.
Resultat av en körning
- När programmet körs skall det löpande göras utskrifter enligt följande så att man ser vad som händer:
Ögonblicksbilder av systemet fås med hjälp av
snapshot
.Exempel på sekvenser av ögonblicksbilder med ovan givna indata:
Tidssteg 0-5:0: ( 0)(G) [........] [...........] [] (G) [........] 1: ( 1)(G) [........] [..........S] [] (G) [........] 2: ( 2)(G) [........] [.........SS] [] (G) [........] 3: ( 3)(G) [........] [........SSS] [] (G) [........] 4: ( 4)(G) [........] [.......SSSS] [] (R) [........] 5: ( 5)(G) [........] [......SSSSS] [] (R) [........]Förklaring: I tidssteg 5 (ovan), är det sammanlagt 5 st fordon i systemet, trafikljuset för W-filen visar grönt, trafikljuset för S-filen visar rött. Alla fem fordonen har destinationen S.
Tidsteg 19-25:19: (19)(G) [.....W..] [SWWSWSSSWSW] [] (R) [SSSSS.SS] 20: (20)(R) [....W...] [WWSWSSSWSWW] [] (R) [SSSSSSSS] 21: (21)(R) [...W...W] [WSWSSSWSWWS] [] (R) [SSSSSSSS] 22: (22)(R) [..W...WW] [SWSSSWSWWSW] [] (R) [SSSSSSSS] 23: (23)(R) [.W...WW.]*[SWSSSWSWWSW] ['W'] (R) [SSSSSSSS] 24: (23)(R) [W...WW..]*[SWSSSWSWWSW] ['W'] (R) [SSSSSSSS] 25: (24)(R) [W..WW...]*[SWSSSWSWWSW] ['W', 'S'] (R) [SSSSSSSS]Om det i ett tidssteg råder "blockering", dvs att ett fordon ej kan röra sig frånlane
till en av de andra filerna, så skall detta synas vid utskriften. Låt detta indikeras av*
-tecknet vid delningspunkten mellan filerna. I de tre sista stegen (23-25) är delningspunkten blockerad (indikeras av*
-tecknet) och dessutom finns det först ett och sedan två fordon i kön. -
Statistik innehållande:
- Genomsnittliga, minimala och maximala tider (antal tidssteg) för fordon att passera respektive ljussignal (väst/syd).
-
Andel tidssteg som delningspunkten
X
varit blockerad, se figuren ovan. Med blockerad menas att det inte går flytta ett fordon från filenlane
på grund av att sista platsen i dess destinationsfil är upptagen. -
Andel tidssteg som det funnits fordon i kön vid startpunkten (
E
).
Samla tiderna för fordon som lämnar systemet i två list-objekt, ett för vardera utgång, och använd dessa för att ta fram statistiken. Använd antingen skriv en egen kod med statistik-metoder (och lägg i en fil) eller använd pythons standard-modul statistics där finns bl.a. funktionerna
min
,max
,mean
ochmedian
Statistiken skall skrivas ut av metoden
print_statistics
iTrafficSystem2
. Metoden skall kunna anropas när som helst under simuleringen. Exempel på utskrift med ovanstående indata.Statistics after 100 timesteps: Created vehicles: 48 In system : 8 At exit West South Vehicles out: 21 19 Minimal time: 20 21 Maximal time: 38 53 Mean time : 27.6 39.3 Median time : 27.0 43.0 Blocked : 18.0% Queue : 14.0%
Innan du redovisar
- Se till att din pythonkod du redovisar skall följa kodningsreglerna
- Du skall förstå och kunna förklara även den givna koden, inte bara den du skrivit själv.
- Kontrollera att all efterfrågad statistik finns med och att resultaten är korrekta!
- Se till att programmet producerar utskrifter enligt ovanstående exempel.
Här följer några helt frivilliga övningar för den som har tid och tycker det är kul
Dessa görs lämpligen efter att du fått OU5 godkänd. De frivilliga övningarna skall ej redovisas.- Om kön kontinuerligt växer inträffar något vi kanske kan kalla trafikinfarkt. Ett sätt att åstadkomma detta är att ändra trafikljusens periodicitet. Lägg till någon typ av felhantering på lämplig plats i koden som "larmar" när kön håller på att bli för lång. Bestäm själv om trafiksystemet skall åtgärda det på något sätt, annat än att bara "larma".
- Med konstruktorn i klassen
TrafficSystem2
skapas alltid samma trafiksystem. Vi gör det med satsen:
ts = TrafficSystem2()
Det har fixa värden för filernas längder och trafikljusens periodicitet. Vi kan säga att det med konstruktorn skapas ett standardmässigt trafiksystem. Konstruktorn har inga parametrar med vilka man kan påverka det hela. Det skapas alltid är samma objekt. Men om man istället definierar konstruktorn med parametrar som har defaultvärden ges möjlighet till att skapa olika objekt. Exempel:light_period = 14 # periodlängden för båda trafikljusen west_green = 6 # gröntiden för trafikljuset som styr west-filen south_green = 4 # gröntiden för trafikljuset som styr south-filen # Skapa ett trafiksystem med följande egenskaper för de två trafikljusen. ts = TrafficSystem3(light_period, west_green, south_green)
Angående parametrar med defaultvärden, se föreläsningen om funktioner (Fö3).Skapa en ny klass
TrafficSystem3
som är en kopia avTrafficSystem2
, men där den nya klassen har två konstruktorer. Den ena skall vara standardkonstruktorn (frånTrafficSystem2
). Den andra konstruktorn skall vara en där man ger parametrar som styr filernas längder och trafikljusens periodicitet. Skapa ett trafiksystem med satsen:
ts = TrafficSystem3(...)
.
Testkör och se att det fungerar. - Klassen
Destinations
skapar alltid samma flöde av fordon. Ändra konstruktorn i klassenDestinations
så att man kan skapa ett annorlunda flöde. Det kan ex.vis göras beroende av slumpen. - Det vore väl elegant om trafiksystemet visualiserades med grafik istället.
Fundera på om och hur metoden
snapshot
även kunde rita en bild över trafiksystemet. Bara fundera..., ty det är ett mycket stort jobb.
Dölj style3dev.css för att bli av med annoteringarna!