def find_lineup_no_optimization(set1, set2): """ Find the approximate offset between two GPS data sets without range start optimization. This algorithm first identifies a primary data set and a secondary one based on which starts later. The offset is then applied to the secondary data set. After mapping the timestamps to the corresponding points from each set, it finds the optimal offset using the later start time of the two sets as the starting point. Requires checking of more values in the set to obtain an accurate offset, compared to the optimized version. Args: set1: GpsDataSet object set2: GpsDataSet object Returns: Tuple of two datetimes, the start time for set 1 and for set 2 given the calculated offset. If no lineup is found, it will return None. """ set1_start_time = set1.gps_data_list[0].time set2_start_time = set2.gps_data_list[0].time if set1_start_time > set2_start_time: later_start_time = utils.round_time(set1_start_time) primary_set = set1 secondary_set = set2 else: later_start_time = utils.round_time(set2_start_time) primary_set = set2 secondary_set = set1 # create dicts that map rounded times to points primary_time_points_mapping = create_time_to_points_mapping(primary_set) secondary_time_points_mapping = create_time_to_points_mapping( secondary_set) offset_range_length = 200 # how many offsets to check so, for 200, check offsets (-100,100) point_checking_range_length = 200 # points to check around each offset, for 200, check points (-100,100) # find best offset optimal_offset = find_optimal_offset(primary_time_points_mapping, secondary_time_points_mapping, later_start_time, offset_range_length, point_checking_range_length) print(optimal_offset) if optimal_offset is None: print( "no optimal line-up for these two data sets; check if correct files are being used" ) return (None, None) if primary_set == set1: print("Optimal offset: set 2 is %s seconds from set 1" % optimal_offset) return (later_start_time, later_start_time + timedelta(seconds=optimal_offset)) else: print("Optimal offset: set 1 is %s seconds from set 2" % optimal_offset) return (later_start_time + timedelta(seconds=optimal_offset), later_start_time)
def test_round_time_rounds_to_nearest_second(self): unrounded_time = datetime(2020, 7, 7, 18, 46, 36, 883732, tzinfo=timezone.utc) rounded_time = datetime(2020, 7, 7, 18, 46, 37, tzinfo=timezone.utc) result = utils.round_time(unrounded_time) self.assertEqual(rounded_time, result)
def get_availability(self): """ Calculate the availability of wear captured gps data Returns: Percentile of wear captured gps data by compared gpsdataset """ if self.availability: return self.availability if not self.starting_time_1 and not self.starting_time_2: return 0 total_timestamps = 0 available_timestamps = 0 start_time = utils.round_time(max(self.starting_time_1, self.starting_time_2)) end_time = utils.round_time(min(self.ending_time_1, self.ending_time_2)) total_seconds = int((end_time-start_time).total_seconds()) for timestamp in [start_time + timedelta(seconds=x) for x in range(total_seconds)]: if timestamp in self.offset_mapping_1 and timestamp in self.offset_mapping_2: available_timestamps += 1 return round(available_timestamps / total_seconds, 4)*100
def create_time_to_points_mapping(dataset, offset=0): """ Map timestamp to points from the dataset. Args: dataset: GpsDataSet offset: int, seconds of offset to apply to timestamps Returns: Dictionary that goups dataset points by seconds timestamp in the following format: {DateTime: [GpsData,], ...} """ time_points_mapping = {} for point in dataset.gps_data_list: rounded_time = utils.round_time(point.time) + timedelta(seconds=offset) if rounded_time in time_points_mapping: time_points_mapping[rounded_time].append(point) else: time_points_mapping[rounded_time] = [point] return time_points_mapping
def find_lineup(set1, set2): """ Optimized algorithm to find the approximate time offset between two GPS data sets. This algorithm assigns the data set that starts later as primary and the other one as secondary. The offset is then applied to the secondary data set. After mapping the timestamps to the corresponding points from each set, it finds the range that has the most overlapping timestamps between the two sets and then finds the optimal offset using the middle of that range as the starting point. Args: set1: GpsDataSet object set2: GpsDataSet object Returns: Tuple of two datetimes, the start time for set 1 and for set 2 given the calculated offset. If no lineup is found, it will return None. """ # find primary data set (the one with the later start time) set1_start_time = set1.gps_data_list[0].time set2_start_time = set2.gps_data_list[0].time set1_end_time = set1.gps_data_list[-1].time set2_end_time = set2.gps_data_list[-1].time if set1_start_time > set2_start_time: later_start_time = utils.round_time(set1_start_time) primary_set = set1 secondary_set = set2 else: later_start_time = utils.round_time(set2_start_time) primary_set = set2 secondary_set = set1 # create dict that maps rounded times to points primary_time_points_mapping = create_time_to_points_mapping(primary_set) secondary_time_points_mapping = create_time_to_points_mapping( secondary_set) # how many offsets to check so, for 50, check offsets (-25,25); should be even offset_range_length = 50 # points to check around each offset, for 100, check points (-50,50); should be even point_checking_range_length = 100 # span length is total length of the span of points to check around the offsets span_length = offset_range_length + point_checking_range_length range_start = utils.round_time(max( set1_start_time, set2_start_time)) - timedelta(seconds=span_length) range_end = utils.round_time(min(set1_end_time, set2_end_time)) range_optimization_size = offset_range_length best_range_start = find_best_data_range(primary_time_points_mapping, secondary_time_points_mapping, range_optimization_size, range_start, range_end) # find best offset starting at the middle of range with most valid points range_middle = best_range_start + timedelta( seconds=range_optimization_size // 2) optimal_offset = find_optimal_offset(primary_time_points_mapping, secondary_time_points_mapping, range_middle, offset_range_length, point_checking_range_length) if optimal_offset is None: print( "no optimal line-up for these two data sets; check if correct files are being used" ) return (None, None) if primary_set == set1: print("Optimal offset: set 2 is %s seconds from set 1" % optimal_offset) return (later_start_time, later_start_time + timedelta(seconds=optimal_offset)) else: print("Optimal offset: set 1 is %s seconds from set 2" % optimal_offset) return (later_start_time + timedelta(seconds=optimal_offset), later_start_time)