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

Add MPG reward #931

Merged
merged 4 commits into from
May 18, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
13 changes: 13 additions & 0 deletions flow/core/kernel/vehicle/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,19 @@ 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
90 changes: 90 additions & 0 deletions flow/core/rewards.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,3 +330,93 @@ 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.
Copy link
Collaborator

Choose a reason for hiding this comment

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

add description of parameters and returns

"""
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
Copy link
Collaborator

Choose a reason for hiding this comment

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

do you have a reference especially for some of the coefficients (e.g., Cr)? if yes, you can add it to the docstring

Copy link
Member Author

Choose a reason for hiding this comment

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

No, they're from Joy and are custom values


return -gain * power


def miles_per_megajoule(env, veh_id=None, gain=.001):
"""Calculate miles per mega-joule of either a particular vehicle or the total average of all the vehilces.
Assumes vehicle is an average sized vehicle.
The power calculated here is the lower bound of the actual power consumed
by a vehicle.
Copy link
Collaborator

Choose a reason for hiding this comment

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

params, returns?

"""
mpj = 0
counter = 0
if not isinstance(veh_id, list):
speed = env.k.vehicle.get_speed(veh_id)
Copy link
Collaborator

Choose a reason for hiding this comment

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

what happens if veh_id is None?

Copy link
Member Author

Choose a reason for hiding this comment

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

that'd be a higher up error. I can add an assert

# 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:
# meters / joule is (v * \delta t) / (power * \delta t)
mpj = speed / power
else:
for veh_id in env.k.vehicle.get_ids():
Copy link
Collaborator

Choose a reason for hiding this comment

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

shouldn't you iterate over vehicle.get_ids() if veh_id is None? here veh_id can be a list, shouldn't you iterate over veh_id list?

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_id=None, gain=.001):
"""Calculate mpg of either a particular vehicle or the total average of all the vehilces.
Assumes vehicle is an average sized vehicle.
The power calculated here is the lower bound of the actual power consumed
by a vehicle.
Copy link
Collaborator

Choose a reason for hiding this comment

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

params and returns?

"""
mpg = 0
counter = 0
if not isinstance(veh_id, list):
speed = env.k.vehicle.get_speed(veh_id)
Copy link
Collaborator

Choose a reason for hiding this comment

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

same, if veh_id is None?

gallons_per_s = env.k.vehicle.get_fuel_consumption(veh_id)
if gallons_per_s > 0 and speed >= 0.0:
# meters / gallon is (v * \delta t) / (gallons_s * \delta t)
mpg = speed / gallons_per_s
else:
for veh_id in env.k.vehicle.get_ids():
Copy link
Collaborator

Choose a reason for hiding this comment

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

same

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