Skip to content
Open
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
.direnv/
__pycache__/
.idea/
.ipynb_checkpoints/
105 changes: 105 additions & 0 deletions Scatter_Plot_Testing.ipynb

Large diffs are not rendered by default.

362 changes: 362 additions & 0 deletions Traffic Simulation.ipynb

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions car.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

class Car:

def __init__(self, length=5, driver="basic"):
self.location = 0
self.length = length
self.next_car = self
self.driver = driver
self.speed = 0

def update(self, dt, road_length):
self.location = (self.location + self.speed*dt) % road_length
54 changes: 54 additions & 0 deletions driver.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import random


class Driver:

def __init__(self, name="basic", desired_speed=120, decel_chance=.1, accel_rate=2, decel_rate=2):
self.desired_speed = desired_speed/3.6
self.decel_chance = decel_chance
self.accel_rate = accel_rate
self.decel_rate = decel_rate
self.name = name

def __str__(self):
return self.name

def update(self, dt, car, road, speed_limit):
if random.random()*dt < self.decel_chance * road.get_decel_ratio(car.location):
car.speed -= self.decel_rate
elif car.speed < min([self.desired_speed, speed_limit]):
car.speed = min((self.desired_speed, car.speed + self.accel_rate*dt))
front = car.location + car.length/2
next_back = car.next_car.location - car.next_car.length/2
if next_back < front:
next_back += road.length
if next_back - front < self.min_spacing(car):
car.speed = min([car.next_car.speed, car.speed])
return

def min_spacing(self, car):
return car.speed


class Normal_Driver(Driver):

def __init__(self, name="normal", desired_speed=120, decel_chance=.1, accel_rate=2, decel_rate=2):
super().__init__(name, desired_speed, decel_chance, accel_rate, decel_rate)

def min_spacing(self, car):
return 20


class Aggressive_Driver(Driver):

def __init__(self, name="aggressive", desired_speed=140, decel_chance=.05, accel_rate=5, decel_rate=2):
super().__init__(name, desired_speed, decel_chance, accel_rate, decel_rate)


class Commercial_Driver(Driver):

def __init__(self, name="commercial", desired_speed=100, decel_chance=.1, accel_rate=1.5, decel_rate=2):
super().__init__(name, desired_speed, decel_chance, accel_rate, decel_rate)

def min_spacing(self, car):
return car.speed*2
12 changes: 12 additions & 0 deletions road.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

class Road:

def __init__(self, length, deceleration_ratios=[(0, 1)]):
self.length = length * 1000
self.deceleration_ratios = deceleration_ratios

def get_decel_ratio(self, location):
for max_location, ratio in self.deceleration_ratios:
if location < max_location:
return ratio
return 1
71 changes: 71 additions & 0 deletions simulation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import random
import numpy as np
from road import Road
from car import Car
from driver import Driver


class Simulation:

# car_types example = [[1, Car, 5, "basic"]]
def __init__(self, road, drivers, car_types, speed_limit=200, tick_interval=1):
self.road = road
self.speed_limit = speed_limit / 3.6
self.drivers = {str(driver): driver for driver in drivers}
num_cars = int(self.road.length * 30 / 1000)
random.shuffle(car_types)
self.car_list = []
total_cars = 0
for percent_car in car_types:
percent_car[0] = int(percent_car[0] * num_cars)
total_cars += percent_car[0]
for _ in range(num_cars - total_cars):
car_types[random.randint(0, len(car_types) - 1)][0] += 1
for car_count, car_class, car_length, car_driver in car_types:
for _ in range(car_count):
self.car_list.append(car_class(car_length, car_driver))
random.shuffle(self.car_list)
for position, car in enumerate(self.car_list):
car.location = int(position * road.length / total_cars)
car.next_car = self.car_list[(position + 1) % len(self.car_list)]
car.speed = min([self.speed_limit, self.drivers[car.driver].desired_speed])
self.tick_interval = tick_interval

def run(self, time=60):
speeds = np.array([self.current_speeds])
states = np.array([self.current_positions])
times = np.array([0 for _ in range(len(self.car_list))])
for i in range(int(time/self.tick_interval)):
self.update()
speeds = np.vstack((speeds, self.current_speeds))
states = np.vstack((states, self.current_positions))
times = np.vstack((times, [(i + 1) * self.tick_interval for _ in range(len(self.car_list))]))
return (speeds, states, times)

def update(self):
# update speeds
for car in self.car_list:
self.drivers[car.driver].update(self.tick_interval, car, self.road, self.speed_limit)
# move cars
for car in self.car_list:
car.update(self.tick_interval, self.road.length)

@property
def current_positions(self):
return [car.location for car in self.car_list]

@property
def current_speeds(self):
return [car.speed for car in self.car_list]

if __name__ == "__main__":
road = Road(1)
drivers = [Driver()]
car_types = [[1, Car, 5, "basic"]]
sim = Simulation(road, drivers, car_types)
speed_results, location_results, time_results = sim.run(300)
print(speed_results)
input("Press Enter to continue")
print(location_results)
input("Press Enter to continue")
print(time_results)