Skip to content

Commit

Permalink
Add MPG reward (#931)
Browse files Browse the repository at this point in the history
Add an MPG reward
  • Loading branch information
eugenevinitsky authored May 18, 2020
1 parent 7398f50 commit 3154f26
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 1 deletion.
14 changes: 14 additions & 0 deletions flow/core/kernel/vehicle/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,20 @@ def get_num_not_departed(self):
"""
raise NotImplementedError

def get_fuel_consumption(selfself, veh_id, error=-1001):
"""Return the mpg / s of the specified vehicle.
Parameters
----------
veh_id : str or list of str
vehicle id, or list of vehicle ids
error : any, optional
value that is returned if the vehicle is not found
Returns
-------
float
"""

def get_speed(self, veh_id, error=-1001):
"""Return the speed of the specified vehicle.
Expand Down
12 changes: 11 additions & 1 deletion flow/core/kernel/vehicle/traci.py
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,8 @@ def _add_departed(self, veh_id, veh_type):
tc.VAR_EDGES,
tc.VAR_POSITION,
tc.VAR_ANGLE,
tc.VAR_SPEED_WITHOUT_TRACI
tc.VAR_SPEED_WITHOUT_TRACI,
tc.VAR_FUELCONSUMPTION
])
self.kernel_api.vehicle.subscribeLeader(veh_id, 2000)

Expand Down Expand Up @@ -370,6 +371,8 @@ def _add_departed(self, veh_id, veh_type):
self.kernel_api.vehicle.getLaneIndex(veh_id)
self.__sumo_obs[veh_id][tc.VAR_SPEED] = \
self.kernel_api.vehicle.getSpeed(veh_id)
self.__sumo_obs[veh_id][tc.VAR_FUELCONSUMPTION] = \
self.kernel_api.vehicle.getFuelConsumption(veh_id)

# make sure that the order of rl_ids is kept sorted
self.__rl_ids.sort()
Expand Down Expand Up @@ -533,6 +536,13 @@ def get_num_not_departed(self):
"""See parent class."""
return self.num_not_departed

def get_fuel_consumption(self, veh_id, error=-1001):
"""Return fuel consumption in gallons/s."""
ml_to_gallons = 0.000264172
if isinstance(veh_id, (list, np.ndarray)):
return [self.get_fuel_consumption(vehID, error) for vehID in veh_id]
return self.__sumo_obs.get(veh_id, {}).get(tc.VAR_FUELCONSUMPTION, error) * ml_to_gallons

def get_previous_speed(self, veh_id, error=-1001):
"""See parent class."""
if isinstance(veh_id, (list, np.ndarray)):
Expand Down
106 changes: 106 additions & 0 deletions flow/core/rewards.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,3 +330,109 @@ def energy_consumption(env, gain=.001):
power += M * speed * accel + M * g * Cr * speed + 0.5 * rho * A * Ca * speed ** 3

return -gain * power


def veh_energy_consumption(env, veh_id, gain=.001):
"""Calculate power consumption of a vehicle.
Assumes vehicle is an average sized vehicle.
The power calculated here is the lower bound of the actual power consumed
by a vehicle.
"""
power = 0

M = 1200 # mass of average sized vehicle (kg)
g = 9.81 # gravitational acceleration (m/s^2)
Cr = 0.005 # rolling resistance coefficient
Ca = 0.3 # aerodynamic drag coefficient
rho = 1.225 # air density (kg/m^3)
A = 2.6 # vehicle cross sectional area (m^2)
speed = env.k.vehicle.get_speed(veh_id)
prev_speed = env.k.vehicle.get_previous_speed(veh_id)

accel = abs(speed - prev_speed) / env.sim_step

power += M * speed * accel + M * g * Cr * speed + 0.5 * rho * A * Ca * speed ** 3

return -gain * power


def miles_per_megajoule(env, veh_ids=None, gain=.001):
"""Calculate miles per mega-joule of either a particular vehicle or the total average of all the vehicles.
Assumes vehicle is an average sized vehicle.
The power calculated here is the lower bound of the actual power consumed
by a vehicle.
Parameters
----------
env : flow.envs.Env
the environment variable, which contains information on the current
state of the system.
veh_ids : [list]
list of veh_ids to compute the reward over
gain : float
scaling factor for the reward
"""
mpj = 0
counter = 0
if veh_ids is None:
veh_ids = env.k.vehicle.get_ids()
elif not isinstance(veh_ids, list):
veh_ids = [veh_ids]
for veh_id in veh_ids:
speed = env.k.vehicle.get_speed(veh_id)
# convert to be positive since the function called is a penalty
power = -veh_energy_consumption(env, veh_id, gain=1.0)
if power > 0 and speed >= 0.0:
counter += 1
# meters / joule is (v * \delta t) / (power * \delta t)
mpj += speed / power
if counter > 0:
mpj /= counter

# convert from meters per joule to miles per joule
mpj /= 1609.0
# convert from miles per joule to miles per megajoule
mpj *= 10**6

return mpj * gain


def miles_per_gallon(env, veh_ids=None, gain=.001):
"""Calculate mpg of either a particular vehicle or the total average of all the vehicles.
Assumes vehicle is an average sized vehicle.
The power calculated here is the lower bound of the actual power consumed
by a vehicle.
Parameters
----------
env : flow.envs.Env
the environment variable, which contains information on the current
state of the system.
veh_ids : [list]
list of veh_ids to compute the reward over
gain : float
scaling factor for the reward
"""
mpg = 0
counter = 0
if veh_ids is None:
veh_ids = env.k.vehicle.get_ids()
elif not isinstance(veh_ids, list):
veh_ids = [veh_ids]
for veh_id in veh_ids:
speed = env.k.vehicle.get_speed(veh_id)
gallons_per_s = env.k.vehicle.get_fuel_consumption(veh_id)
if gallons_per_s > 0 and speed >= 0.0:
counter += 1
# meters / gallon is (v * \delta t) / (gallons_per_s * \delta t)
mpg += speed / gallons_per_s
if counter > 0:
mpg /= counter

# convert from meters per gallon to miles per gallon
mpg /= 1609.0

return mpg * gain

0 comments on commit 3154f26

Please sign in to comment.