ah, there are speeds low enough to round off to zero distance when applied with the timestep. systematically get rid of EPSILON_SPEED.

This commit is contained in:
Dustin Carlino 2019-02-03 16:48:04 -08:00
parent bfd0465a3d
commit 7b045146da
6 changed files with 30 additions and 27 deletions

View File

@ -1,4 +1,4 @@
use crate::trim_f64;
use crate::{trim_f64, EPSILON_DIST};
use serde_derive::{Deserialize, Serialize};
use std::{cmp, f64, fmt, ops};
@ -207,6 +207,12 @@ pub struct Speed(f64);
impl Speed {
pub const ZERO: Speed = Speed::const_meters_per_second(0.0);
// Is a speed effectively zero based on the timestep?
// TODO Probably better to tweak the rounding so that uselessly tiny speeds round to 0.
pub fn is_zero(self, timestep: Duration) -> bool {
self * timestep <= EPSILON_DIST
}
pub fn meters_per_second(value: f64) -> Speed {
if !value.is_finite() {
panic!("Bad Speed {}", value);

View File

@ -7,7 +7,7 @@ use crate::transit::TransitSimState;
use crate::view::{AgentView, WorldView};
use crate::{
AgentID, CarID, CarState, DrawCarInput, Event, ParkedCar, ParkingSpot, Tick, TripID,
VehicleType,
VehicleType, TIMESTEP,
};
use abstutil;
use abstutil::{deserialize_btreemap, serialize_btreemap, Error};
@ -97,7 +97,7 @@ impl Car {
) -> Result<Action, Error> {
if self.parking.is_some() {
// TODO right place for this check?
assert!(self.speed <= kinematics::EPSILON_SPEED);
assert!(self.speed.is_zero(TIMESTEP));
return Ok(Action::WorkOnParking);
}
@ -377,9 +377,8 @@ impl Car {
if self.dist_along > dist {
panic!("{} overshot! Wanted to stop at {} along {}, but at {}. Speed is {}. This last step, they chose {}, with their max being {}, and consequently traveled {}", self.id, dist, lane, self.dist_along, self.speed, accel, self.vehicle.max_deaccel, dist_traveled);
}
if self.dist_along == dist && self.speed > Speed::ZERO {
// TODO Don't panic, because some other car did this with no consequence...
error!("{} stopped right where they want to, but with a final speed of {}. This last step, they chose {}, with their max being {}", self.id, self.speed, accel, self.vehicle.max_deaccel);
if self.dist_along == dist && !self.speed.is_zero(TIMESTEP) {
panic!("{} stopped right where they want to, but with a final speed of {}. This last step, they chose {}, with their max being {}", self.id, self.speed, accel, self.vehicle.max_deaccel);
}
}
}
@ -538,7 +537,7 @@ impl DrivingSimState {
let waiting = self
.cars
.values()
.filter(|c| c.speed <= kinematics::EPSILON_SPEED)
.filter(|c| c.speed.is_zero(TIMESTEP))
.count();
(waiting, self.cars.len())
}
@ -906,10 +905,10 @@ impl DrivingSimState {
),
state: if c.debug {
CarState::Debug
} else if c.speed > kinematics::EPSILON_SPEED {
CarState::Moving
} else {
} else if c.speed.is_zero(TIMESTEP) {
CarState::Stuck
} else {
CarState::Moving
},
vehicle_type: c.vehicle.vehicle_type,
on: c.on,
@ -978,7 +977,7 @@ impl DrivingSimState {
if let Some(queue) = self.queues.get(&Traversable::Lane(*l)) {
for (_, car) in &queue.cars_queue {
let c = &self.cars[car];
if c.speed <= kinematics::EPSILON_SPEED {
if c.speed.is_zero(TIMESTEP) {
stuck_cars += 1;
} else {
moving_cars += 1;

View File

@ -1,6 +1,5 @@
use crate::kinematics;
use crate::view::WorldView;
use crate::{AgentID, CarID, Event, PedestrianID, Tick};
use crate::{AgentID, CarID, Event, PedestrianID, Tick, TIMESTEP};
use abstutil;
use abstutil::{deserialize_btreemap, serialize_btreemap, Error};
use geom::Duration;
@ -257,7 +256,7 @@ impl StopSign {
let should_promote = if ss.get_priority(req.turn) == TurnPriority::Stop {
// TODO and the agent is at the end? maybe easier than looking at their speed
// TODO with lane-changing, somebody could cut in front of them when they're stopped.
view.get_speed(req.agent) <= kinematics::EPSILON_SPEED
view.get_speed(req.agent).is_zero(TIMESTEP)
} else {
true
};

View File

@ -6,8 +6,6 @@ use rand::Rng;
use rand_xorshift::XorShiftRng;
use serde_derive::{Deserialize, Serialize};
pub const EPSILON_SPEED: Speed = Speed::const_meters_per_second(0.000_1);
// http://pccsc.net/bicycle-parking-info/ says 68 inches, which is 1.73m
const MIN_BIKE_LENGTH: Distance = Distance::const_meters(1.7);
const MAX_BIKE_LENGTH: Distance = Distance::const_meters(2.0);
@ -308,13 +306,14 @@ pub fn results_of_accel_for_one_tick(
* (actual_time.inner_seconds() * actual_time.inner_seconds()),
);
assert_ge!(dist, Distance::ZERO);
let mut new_speed = initial_speed + (accel * actual_time);
// Handle some floating point imprecision
if new_speed < Speed::ZERO && new_speed >= EPSILON_SPEED * -1.0 {
new_speed = Speed::ZERO;
let new_speed = initial_speed + (accel * actual_time);
// Deal with floating point imprecision.
if new_speed < Speed::ZERO && new_speed.is_zero(TIMESTEP) {
(dist, Speed::ZERO)
} else {
assert_ge!(new_speed, Speed::ZERO);
(dist, new_speed)
}
assert_ge!(new_speed, Speed::ZERO);
(dist, new_speed)
}
fn accel_to_cover_dist_in_one_tick(dist: Distance, speed: Speed) -> Acceleration {

View File

@ -1,9 +1,9 @@
use crate::driving::{Action, Intent};
use crate::kinematics;
use crate::kinematics::Vehicle;
use crate::parking::ParkingSimState;
use crate::transit::TransitSimState;
use crate::view::AgentView;
use crate::TIMESTEP;
use crate::{Event, ParkingSpot, Tick};
use geom::{Acceleration, Distance, EPSILON_DIST};
use map_model::{
@ -78,7 +78,7 @@ impl Router {
transit_sim: &mut TransitSimState,
rng: &mut XorShiftRng,
) -> Option<Action> {
if self.path.isnt_last_step() || view.speed > kinematics::EPSILON_SPEED {
if self.path.isnt_last_step() || !view.speed.is_zero(TIMESTEP) {
return None;
}

View File

@ -1,7 +1,7 @@
use crate::runner::TestRunner;
use geom::{Distance, Speed, EPSILON_DIST};
use sim::kinematics::{results_of_accel_for_one_tick, Vehicle, EPSILON_SPEED};
use sim::Tick;
use sim::kinematics::{results_of_accel_for_one_tick, Vehicle};
use sim::{Tick, TIMESTEP};
#[allow(clippy::unreadable_literal)]
pub fn run(t: &mut TestRunner) {
@ -86,7 +86,7 @@ fn test_accel_to_stop_in_dist(vehicle: Vehicle, orig_dist_left: Distance, orig_s
}
if dist_left <= EPSILON_DIST {
println!(" Result: speed {}, dist_left {}", speed, dist_left);
if speed > EPSILON_SPEED {
if !speed.is_zero(TIMESTEP) {
panic!("Finished, but going too fast");
}
return;