Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Driver profiling sim #30

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions simulation/Ring Road Drivers.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
Names,Average Velocity (km/h),Total Time Elapsed (min),Power Expenditure (W),Percentage of time following recommended speed,Behaviour Score,Emergency Preparedness Score,Enjoyment Score
Raymond,31.39,4.78,145.79,52.5,Moderate,2,4
Kathryn,27.21,5.51,94.23,81.32,Safe,1,5
Robert,28.48,5.27,105.87,75.86,Safe,3,1
Steven,28.07,5.34,100.44,87.78,Safe,2,2
David,32.47,4.62,155.87,39.74,Reckless,3,4
Timothy,29.88,5.02,122.29,59.26,Moderate,5,3
Sandra,31.83,4.71,149.44,48.1,Reckless,1,2
Jeremy,28.41,5.28,103.15,71.91,Safe,5,2
David,34.2,4.39,178.49,31.08,Reckless,2,4
Lisa,25.79,5.82,79.08,89.47,Safe,1,5
Jesus,28.1,5.34,103.61,80.9,Safe,5,3
Sheila,30.52,4.92,129.26,43.75,Reckless,5,3
Kathy,27.03,5.55,88.33,90.43,Safe,1,3
Amy,27.46,5.46,97.1,70.11,Safe,4,5
Karyn,29.34,5.11,114.33,82.95,Safe,2,1
Donna,29.63,5.06,121.32,60.98,Moderate,3,1
Derrick,29.69,5.05,122.92,56.63,Moderate,2,3
Chris,29.63,5.06,121.21,56.63,Moderate,5,3
Lois,30.52,4.92,132.06,51.25,Moderate,1,4
Brad,29.34,5.11,113.36,53.09,Moderate,5,2
Matthew,26.81,5.6,90.74,89.58,Safe,1,4
Russell,31.21,4.81,141.06,46.25,Reckless,4,5
Jeff,27.78,5.4,96.55,83.7,Safe,1,4
Len,35.16,4.27,204.7,16.9,Reckless,2,2
John,29.44,5.1,115.13,67.06,Moderate,1,1
Elizabeth,30.79,4.87,137.6,46.84,Reckless,4,1
Emily,26.69,5.62,86.5,86.96,Safe,4,5
Aaron,29.0,5.17,114.39,68.18,Moderate,3,4
Arnold,28.94,5.18,113.55,59.04,Moderate,4,1
Annalee,27.45,5.47,94.39,89.47,Safe,3,1
251 changes: 251 additions & 0 deletions simulation/driversim.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
import pandas as pd
import matplotlib.pyplot as plt
import simpy
import random
import names

#simulating driver data
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use triple quotes for documenting multiple lines code logic or field descriptions.
For single line comments the # is fine, and add a space after the # and then write the comment.

#1 time unit = 1 min
#things to consider:
#stop lights - currently have "crosswalks", how do we consider stoplights?
#speed limits - how to consider speed limits? split up the route into different parts then combining the data?
#picking the best driver?

class Route:
#distance - set distance in km
#recommended_speed - in km/h
#maxstop - max # of stops
#deltat - time increment in minutes
def __init__(self, route_name, distance, recommended_speed, maxstop, deltat):
self.route_name = route_name
self.distance = distance
self.recommended_speed = recommended_speed
self.maxstop = maxstop
self.deltat = deltat

class Driver:
#drivers - number of drivers
#inc - speed increment in km/h
drivers = 0
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great use of static variables :)

inc = 0
all_velocities = []
all_times = []
all_pwr_exp = []
all_safe_time = []
all_behaviour_scores = []
all_eps = []
all_enjoyment_score = []

def __init__(self, env, route, inc):
#driverID - driver number
#driver_stats - array containing name, avg velocity, time elapsed, power expenditure, % of time following
#recommended speed (safe time), behaviour score, emergency preparedness score, enjoyment score
#name - randomly generated name
#mass - weight of person, in kg
#eps - emergency preparedness score from 1 to 5
#enjoy - enjoyment score from 1 to 5
#distance_left - distance left to travel in km
self.env = env
self.driverID = self.drivers
self.driver_stats = []
self.name = names.get_first_name()
self.mass = random.randint(40,100)
self.eps = random.randint(1,5)
self.enjoy = random.randint(1,5)
self.distance_left = route.distance
Driver.inc = inc

#powerexp - power expenditure calculated by kinetic energy/time in Watts
#time_elapsed - time it took to complete route in minutes
#current_speed - keep track of current speed in km/h
#avg_speed - average speed over time in km/h
#behaviour_score - "Safe" >= 70%, "Moderate" >= 50%, "Reckless" < 50%
#safetime - % time at recommended speed
#stops - number of stops made
self.power_exp = 0
self.time_elapsed = 0
self.current_speed = 0
self.avg_speed = 0
self.behaviour_score = 0
self.safetime = 0
self.stops = 0

#speeds - for calculating safe time
self.speeds = []
self.speedtimes = []

def update_values(self, route, time_elapsed):
self.time_elapsed = time_elapsed
#km/(min/60 -> hours)
self.avg_speed = route.distance/(self.time_elapsed/60)
#car weighs ~1000kg
#power exp per hour
self.power_exp = 0.5*(self.mass + 1000)*pow(self.avg_speed/3.6,2)/(self.time_elapsed*60)

#calculate percentage of time within recommended speed (can be changed)
sum_safe = 0
for i in range (-2,2):
sum_safe += self.speeds.count(route.recommended_speed+i*Driver.inc)
self.safetime = min(100,round(sum_safe/len(self.speeds),4) * 100)

#calculate behaviour score (can be changed)
if (self.safetime > 50):
if (self.safetime >= 70):
self.behaviour_score = "Safe"
else:
self.behaviour_score = "Moderate"
else: self.behaviour_score = "Reckless"

self.driver_stats = [self.name, round(self.avg_speed,2), round(self.time_elapsed,2), round(self.power_exp,2),
round(self.safetime,2), self.behaviour_score, self.eps, self.enjoy]

Driver.all_velocities.append(self.driver_stats[1])
Driver.all_times.append(self.driver_stats[2])
Driver.all_pwr_exp.append(self.driver_stats[3])
Driver.all_safe_time.append(self.driver_stats[4])
Driver.all_behaviour_scores.append(self.driver_stats[5])
Driver.all_eps.append(self.driver_stats[6])
Driver.all_enjoyment_score.append(self.driver_stats[7])
return self.driver_stats

def start_car(self, env, route):
#start car
v0 = 0
v1 = route.recommended_speed/3.6
#2.0m/s^2 - average car acceleration
a = 2.0
t = (v1-v0)/a
d = (pow(v1,2)-pow(v0,2))/(2*a)
self.current_speed = route.recommended_speed
self.speeds.append((d/t)*3.6)
self.distance_left -= d/1000

yield self.env.timeout(t/60)

def stop_car(self, env, route):
#stop car
v0 = self.current_speed/3.6
v1 = 0
#2.0m/s^2 - average car acceleration
a = -2.0
t = (v1-v0)/a
d = (pow(v1,2)-pow(v0,2))/(2*a)
self.current_speed = 0
self.speeds.append((d/t)*3.6)
self.distance_left -= d/1000

yield self.env.timeout(t/60)


def move(self, route):
x = random.uniform(0,1)
#40% chance to speed up
if (x >= 0.7):
if (self.current_speed < route.recommended_speed + self.inc*5):
self.current_speed += self.inc
#20% to slow down
elif (x <= 0.3):
if (self.current_speed > route.recommended_speed - self.inc*2):
self.current_speed -= self.inc
#distance remaining calculation
self.distance_left -= (self.current_speed/60)*route.deltat
#keep track of speed based on the set interval
self.speeds.append(self.current_speed)
yield self.env.timeout(route.deltat)

def drive_route(env, driver, route):
start_time = env.now

#actually driving
while (driver.distance_left > 0):
#accelerating from stop
if (driver.current_speed == 0):
yield env.process(driver.start_car(env, route))
#self.speedtime(env.now-start_time)
#drive car
else:
yield env.process(driver.move(route))
#chance of stopping at crosswalks 50%
if (driver.stops < route.maxstop):
if (random.choice([True, False])):
yield env.process(driver.stop_car(env, route))
#let the people cross the street
yield env.timeout(random.randint(3,15)/60)
yield env.process(driver.start_car(env, route))
driver.stops += 1

#time spent
time_elapsed = env.now-start_time
#calculate driver stats
driver.update_values(route, time_elapsed)

def sim_drivers(env, route, num_drivers):
driver_instances =[]
for i in range (num_drivers):
d = Driver(env, route, 3)
env.process(drive_route(env, d, route))
driver_instances.append(d)
return driver_instances


def get_route():

route_name = "Ring Road"
distance = 2.5
recommended_speed = 35
maxstop = 4
deltat = 3/60
num_drivers = 30
'''
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move the triple quotes before the initialization of values.

route_name = input("Input route name: ")
distance = float(input("Input route length in km: "))
recommended_speed = int(input("Input recommended speed in km/h: "))
maxstop = int(input("Input # of crosswalks: "))
deltat = float(input("Input time between speed updates in minutes: "))
num_drivers = int(input("Input number of drivers to simulate: "))
'''
params = [route_name, distance, recommended_speed, maxstop, deltat, num_drivers]
return params

def plot_avg_velocity_vs_time():
plt.figure(1)
plt.scatter(Driver.all_times, Driver.all_velocities)
plt.xlabel('Total time (min)')
plt.ylabel('Average Velocity (km/h)')
plt.title('Average Velocity vs Time')

def plot_behaviour_score():
plt.figure(2)
categories = ["Reckless", "Moderate", "Safe"]
values = [Driver.all_behaviour_scores.count("Reckless"), Driver.all_behaviour_scores.count("Moderate"), Driver.all_behaviour_scores.count("Safe")]
plt.bar(categories, values)
plt.title("Driver Behaviour Scores")

def main():
#gets the same data every time
#can delete to randomize
random.seed(100)
#take in route variables
route_name, distance, recommended_speed, maxstop, deltat, num_drivers = get_route()
route = Route(route_name, distance, recommended_speed, maxstop, deltat)

env = simpy.Environment()
#contains all the drivers
driver_instances = sim_drivers(env,route,num_drivers)
env.run()

#all the different stats
headings = ["Names", "Average Velocity (km/h)", "Total Time Elapsed (min)", "Power Expenditure (W)",
"Percentage of time following recommended speed", "Behaviour Score", "Emergency Preparedness Score",
"Enjoyment Score"]

data = [driver.driver_stats for driver in driver_instances]
df = pd.DataFrame(data, columns=headings)
df.to_csv(f"{route_name} Drivers.csv", index=False)

plot_avg_velocity_vs_time()
plot_behaviour_score()
plt.show()

if __name__ == "__main__":
main()
4 changes: 4 additions & 0 deletions simulation/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pandas
names
simpy
matplotlib
Loading