def populate_trip_stop_information(trip_id, stops): """ Given a GTFS trip ID, populates information about each stop in that trip into the database. Returns total length of the trip in meters. """ cumulative_dist = 0.0 prev_stop_loc = None for i, gstop in enumerate(stops): stop_loc = gstop['stop_lat'], gstop['stop_lon'] stop_arrive = gstop['arrival_time_seconds'] stop_depart = gstop['departure_time_seconds'] stop_seq = gstop['stop_sequence'] if prev_stop_loc is None: prev_stop_dist = None sched_travel_time = None else: prev_stop_dist = gis.distance_meters(prev_stop_loc, stop_loc) cumulative_dist += prev_stop_dist if prev_stop_depart is None: sched_travel_time = stop_arrive - prev_stop_arrive else: sched_travel_time = stop_arrive - prev_stop_depart db.export_trip_stop_information(trip_id, stop_seq, i, prev_stop_dist, cumulative_dist, sched_travel_time) prev_stop_loc = stop_loc prev_stop_arrive = stop_arrive prev_stop_depart = stop_depart return cumulative_dist
def populate_trip_stop_information(trip_id,stops): """ Given a GTFS trip ID, populates information about each stop in that trip into the database. Returns total length of the trip in meters. """ cumulative_dist = 0.0 prev_stop_loc = None for i,gstop in enumerate(stops): stop_loc=gstop['stop_lat'],gstop['stop_lon'] stop_arrive=gstop['arrival_time_seconds'] stop_depart = gstop['departure_time_seconds'] stop_seq = gstop['stop_sequence'] if prev_stop_loc is None: prev_stop_dist = None sched_travel_time = None else: prev_stop_dist = gis.distance_meters(prev_stop_loc,stop_loc); cumulative_dist += prev_stop_dist if prev_stop_depart is None: sched_travel_time = stop_arrive - prev_stop_arrive else: sched_travel_time = stop_arrive - prev_stop_depart db.export_trip_stop_information(trip_id,stop_seq, i, prev_stop_dist,cumulative_dist, sched_travel_time); prev_stop_loc = stop_loc prev_stop_arrive = stop_arrive prev_stop_depart = stop_depart return cumulative_dist
def findLaunchTime(self,tol=50): """ Finds the time that the bus moved tol meters from start point. If there is no shape data, then the start point is the first point in the dataset. Otherwise, the start point is defined by the first point in the shape. In this case, we first find the time that the bus arrived at the start point, then search for the launch from there. """ if self.segment.shape: arrived = False begin_pt = self.segment.shape.points[0]; else: arrived = True begin_pt = self.interpolation[0][:2]; for i,interp_pt in enumerate(self.interpolation): dist = gis.distance_meters(begin_pt,interp_pt[:2]); #print i,"dist:",dist if not arrived and dist <= tol: print "arrived at",interp_pt[2],"(%d steps)..."%(i,), arrived = True elif arrived and dist > tol: print "launched at",interp_pt[2] return interp_pt[2]; return None
def calcDistance(lation1,lation2): """ Caclulate distance between two lat lons in meters """ return gis.distance_meters( map(float,lation1), map(float,lation2) )
def measureDistanceFromGTFSTrip(self,trip_id, offset_seconds=0, penalize_gps_oob=True, penalize_gtfs_oob=True): """ Given a GTFS Trip ID and an offset in seconds, returns (distance, oob_frac) where dist measures the distance of this trip from that one as described below, and oob_frac is the fraction of scheduled stops (out of total number of stops) whose times are outside the time window of this GPS segment. The penalize_xxx_oob parameters are used to indicate whether to penalize for special out-of-bounds cases. See below for details. Let n = # of timepoints for the GTFS trip For each timepoint T_i in the GTFS trip, let G(T_i) = location of GTFS scheduled stop at T_i B(T_i) = location of GPS signal at T_i+offset_seconds Then this function will return as the distance Sqrt( 1/n * Sum over i=1:n of Distance[G(T_i),B(T_i)]**2 ) Note that the normalization factor of 1/n is necessary to prevent favoring of shorter routes. Typically the offset will be set to 86400 (24 hours) in cases where the GTFS trip is a "late night" (after midnight) schedule which means its times will be greater than 86400 (in seconds). The 'penalize_xxx_oob' parameters are used to determine what special treatment will be given to cases where bounding time window of the GPS trip is not well-matched to that of the GTFS trip. (That is, whether or not to penalize periods of time where the gtfs or gps data is "out of bounds" of the other). This breaks down into two basic cases: 1. Periods of time where GPS data exists but the GTFS schedule does not. That is, the GPS data is out of bounds of the GTFS time window. 2. Periods of time where the GTFS trip has schedule data but the GPS trip does not. That is, the GPS trip starts after the GTFS schedule, and/or it ends before the GTFS schedule, and so the GTFS data is out of bounds of the GPS time window. If penalize_gtfs_oob is False, then for periods where the GTFS trip exists but the GPS trip does not, the GTFS is truncated to match the GPS time window. Otherwise, it is not truncated. If penalize_gps_oob is False, then for periods where the GPS trip exists but the GTFS trip does not, the GPS trip is truncated to match the GTFS time window. Otherwise, it is not truncated. The costs for non-truncated out-of-bound segments are handled as follows: - For timepoints T_i where GTFS exists and GPS does not, the distance between them is measured as though the GPS was found at the location of its first (or last) point. That is, if there is a GTFS timepoint before the beginning of the GPS trip, we use the first point in the GPS trip; if there is a GTFS timepoint after the end of the GPS trip, we use the last point in the GPS trip. - For cases where GPS exists and GTFS does not, we fabricate evenly spaced time points T_k for k = 1 to n, where n = (GTFS_stops / GTFS_time) * GPS_OOB_time GTFS_time = time span of GTFS trip GTFS_stops = number of stops in GTFS trip GPS_OOB_time = amount of time GPS trip exists before/after GTFS trip For each of this times T_k the GTFS location is calculated as for the GPS trip in the case above. This is used, for example, in a case where the GPS signal was turned on several minutes late into the trip, the trip can match very well with the GTFS schedule during that time the signal is alive, but during the beginning of the GTFS schedule there is no data. In other cases, the GPS signal has been turned on several minutes early, before it has even arrived at the beginning of its route. You may wish to penalize this kind of behavior, or ignore it. WARNING: if penalize_gtfs_oob=False and penalize_gps_oob=False, then the distance returned from this route with a GTFS trip with no overlap in time will be 0! """ schedule = GTFSBusSchedule(trip_id,offset=offset_seconds); #'bounding boxes' of our time interval and of the GTFS trip's time interval bbox = self.getRouteTimeInterval(); sched_bbox = schedule.getRouteTimeInterval(); oob_count = 0 #count of gtfs stop times that are out of bounds vstops = 0 #number of virtual stops that we penalized for ret = 0.0 if penalize_gps_oob: ## To penalize for being too far outside the GTFS window, ## we need to calculate a number of "virtual stops" for which ## we were outside of that window, based on the number of stops ## the GTFS schedule makes in its time window. ## For each of these virtual stops, we penalize the square of ## the distance from our position at that time, to the closest- ## in-time position of the GTFS trip. # We use the total number of stops in the GTFS schedule divided # by the length in time of the schedule to approximate how many # virtual stops we should penalize for. stops_per_time = len(schedule.interpolation)/float(sched_bbox[1] -sched_bbox[0]) # If we start before the GTFS trip if bbox[0] < sched_bbox[0]: # oob_box is the out-of-bounds window oob_box=( bbox[0] , min(sched_bbox[0],bbox[1]) ) # oob_time is the time spent out of bounds oob_time = oob_box[1] - oob_box[0] # loc1 is the starting location of the GTFS trip loc1 = schedule.interpolation[0][:2]; # n is the number of 'virtual stops' we're penalizing for n = int( stops_per_time * oob_time ); for i in range(n): T_i = bbox[0] + i * float(oob_time)/n loc2 = self.getLocationAtTime(T_i); if not loc2: print "ERROR SOMETHING IS TERRIBLY WRONG" ret += gis.distance_meters(loc2[:2],loc1)**2 vstops += n # If we end after the GTFS trip if bbox[1] > sched_bbox[1]: # oob_box is the out-of-bounds window oob_box=( max(sched_bbox[1],bbox[0]) , bbox[1] ) # oob_time is the time spent out of bounds oob_time = oob_box[1] - oob_box[0] # loc1 is the ending location of the GTFS trip loc1 = schedule.interpolation[-1][:2] # n is the number of 'virtual stops' to penalize for n = int( stops_per_time * oob_time ); for i in range(n): T_i = bbox[1] - i * float(oob_time)/n loc2 = self.getLocationAtTime(T_i); if not loc2: print "ERROR SOMETHING IS TERRIBLY WRONG 2" ret += gis.distance_meters(loc2[:2],loc1)**2 vstops += n ## Now check along the GTFS route for i,pt in enumerate(schedule.interpolation): stoptime = pt[2] #- offset_seconds myloc = self.getLocationAtTime(stoptime); if myloc is None: # then GTFS is out of bounds of GPS time window oob_count += 1 if penalize_gtfs_oob: # so penalize for it, if we're supposed to if stoptime < bbox[0]: myloc = self.interpolation[0] else: myloc = self.interpolation[-1] if myloc: ret += gis.distance_meters( myloc[:2], pt[:2] )**2 ret = math.sqrt( ret/(len(schedule.interpolation)+vstops) ) print " Matching id",trip_id,"start time:", print schedule.interpolation[0][2], #-offset_seconds, print " distance: %9.2f OOB count: %2d/%2d"%(ret,oob_count, len(schedule.interpolation)) return ret,float(oob_count)/len(schedule.interpolation)