def findStopsGlobalForRTK(track, std_max=2e-2, duration=5, downsampling=1, verbose=True): """Find stop points in a track based on maximal size of a stop and minimal time duration Two parameters: - Maximal size of a stop (as the standard deviation per axis, in ground units) - Minimal time duration (in seconds) Use downsampling parameter > 1 to speed up the process. Default is set for precise RTK GNSS survey (2 cm for 5 sec) """ # If down-sampling is required if downsampling > 1: track = track.copy() track **= track.size() / downsampling # --------------------------------------------------------------------------- # Computes cost matrix as : # Cij = 0 if sqrt(0.33*(std_x^2 + std_y^2 + std_Z^2)) > std_max # Cij = 0 if time duration between pi and p-1 is < duration # Cij = (j-i)**2 = square of the number of points of segment otherwise # --------------------------------------------------------------------------- C = np.zeros((track.size(), track.size())) RANGE = range(track.size() - 2) if verbose: print("Minimal enclosing circles computation:") RANGE = progressbar.progressbar(RANGE) for i in RANGE: for j in range(i + 1, track.size() - 1): if track[i].distanceTo(track[j - 1]) > 3 * std_max: C[i, j] = 0 break if track[j - 1].timestamp - track[i].timestamp <= duration: C[i, j] = 0 continue portion = track.extract(i, j - 1) varx = portion.operate(Operator.Operator.VARIANCE, "x") vary = portion.operate(Operator.Operator.VARIANCE, "y") varz = portion.operate(Operator.Operator.VARIANCE, "z") C[i, j] = math.sqrt(varx + vary + varz) C[i, j] = (C[i, j] < std_max) * (j - i)**2 C = C + np.transpose(C) # --------------------------------------------------------------------------- # Computes optimal partition with dynamic programing # --------------------------------------------------------------------------- segmentation = optimalPartition(C, MODE_SEGMENTATION_MAXIMIZE, verbose) stops = Track() TMP_RADIUS = [] TMP_MEAN_X = [] TMP_MEAN_Y = [] TMP_MEAN_Z = [] TMP_IDSTART = [] TMP_IDEND = [] TMP_STD_X = [] TMP_STD_Y = [] TMP_STD_Z = [] TMP_DURATION = [] TMP_NBPOINTS = [] for i in range(len(segmentation) - 1): portion = track.extract(segmentation[i], segmentation[i + 1] - 1) radius = C[segmentation[i], segmentation[i + 1]] if radius == 0: continue xm = portion.operate(Operator.Operator.AVERAGER, "x") ym = portion.operate(Operator.Operator.AVERAGER, "y") zm = portion.operate(Operator.Operator.AVERAGER, "z") xv = portion.operate(Operator.Operator.VARIANCE, "x") yv = portion.operate(Operator.Operator.VARIANCE, "y") zv = portion.operate(Operator.Operator.VARIANCE, "z") pt = portion[0].position.copy() pt.setX(xm) pt.setY(ym) pt.setZ(zm) stops.addObs(Obs(pt, portion[0].timestamp)) TMP_RADIUS.append(math.sqrt(xv + yv + zv)) TMP_MEAN_X.append(xm) TMP_MEAN_Y.append(ym) TMP_MEAN_Z.append(zm) TMP_STD_X.append(xv**0.5) TMP_STD_Y.append(yv**0.5) TMP_STD_Z.append(zv**0.5) TMP_IDSTART.append(segmentation[i] * downsampling) TMP_IDEND.append((segmentation[i + 1] - 1) * downsampling) TMP_NBPOINTS.append(segmentation[i + 1] - segmentation[i]) TMP_DURATION.append(portion.duration()) if stops.size() == 0: return stops stops.createAnalyticalFeature("radius", TMP_RADIUS) stops.createAnalyticalFeature("mean_x", TMP_MEAN_X) stops.createAnalyticalFeature("mean_y", TMP_MEAN_Y) stops.createAnalyticalFeature("mean_z", TMP_MEAN_Z) stops.createAnalyticalFeature("id_ini", TMP_IDSTART) stops.createAnalyticalFeature("id_end", TMP_IDEND) stops.createAnalyticalFeature("sigma_x", TMP_STD_X) stops.createAnalyticalFeature("sigma_y", TMP_STD_Y) stops.createAnalyticalFeature("sigma_z", TMP_STD_Z) stops.createAnalyticalFeature("duration", TMP_DURATION) stops.createAnalyticalFeature("nb_points", TMP_NBPOINTS) stops.operate(Operator.Operator.QUAD_ADDER, "sigma_x", "sigma_y", "rmse") stops.base = track.base return stops
def findStopsGlobal(track, diameter=20, duration=60, downsampling=1, verbose=True): """Find stop points in a track based on two parameters: Maximal size of a stop (as the diameter of enclosing circle, in ground units) and minimal time duration (in seconds) Use downsampling parameter > 1 to speed up the process""" # If down-sampling is required if downsampling > 1: track = track.copy() track **= track.size() / downsampling # --------------------------------------------------------------------------- # Computes cost matrix as : # Cij = 0 if size of enclosing circle of pi, pi+1, ... pj-1 is > diameter # Cij = 0 if time duration between pi and p-1 is < duration # Cij = (j-i)**2 = square of the number of points of segment otherwise # --------------------------------------------------------------------------- C = np.zeros((track.size(), track.size())) RANGE = range(track.size() - 2) if verbose: print("Minimal enclosing circles computation:") RANGE = progressbar.progressbar(RANGE) for i in RANGE: for j in range(i + 1, track.size() - 1): if track[i].distance2DTo(track[j - 1]) > diameter: C[i, j] = 0 break if track[j - 1].timestamp - track[i].timestamp <= duration: C[i, j] = 0 continue C[i, j] = 2 * minCircle(track.extract(i, j - 1))[1] C[i, j] = (C[i, j] < diameter) * (j - i)**2 C = C + np.transpose(C) # --------------------------------------------------------------------------- # Computes optimal partition with dynamic programing # --------------------------------------------------------------------------- segmentation = optimalPartition(C, MODE_SEGMENTATION_MAXIMIZE, verbose) stops = Track() TMP_RADIUS = [] TMP_MEAN_X = [] TMP_MEAN_Y = [] TMP_MEAN_Z = [] TMP_IDSTART = [] TMP_IDEND = [] TMP_STD_X = [] TMP_STD_Y = [] TMP_STD_Z = [] TMP_DURATION = [] TMP_NBPOINTS = [] for i in range(len(segmentation) - 1): portion = track.extract(segmentation[i], segmentation[i + 1] - 1) C = minCircle(portion) if (C[1] > diameter / 2) or (portion.duration() < duration): continue stops.addObs(Obs(C[0], portion.getFirstObs().timestamp)) TMP_RADIUS.append(C[1]) TMP_MEAN_X.append(portion.operate(Operator.Operator.AVERAGER, "x")) TMP_MEAN_Y.append(portion.operate(Operator.Operator.AVERAGER, "y")) TMP_MEAN_Z.append(portion.operate(Operator.Operator.AVERAGER, "z")) TMP_STD_X.append(portion.operate(Operator.Operator.STDDEV, "x")) TMP_STD_Y.append(portion.operate(Operator.Operator.STDDEV, "y")) TMP_STD_Z.append(portion.operate(Operator.Operator.STDDEV, "z")) TMP_IDSTART.append(segmentation[i] * downsampling) TMP_IDEND.append((segmentation[i + 1] - 1) * downsampling) TMP_NBPOINTS.append(segmentation[i + 1] - segmentation[i]) TMP_DURATION.append(portion.duration()) if stops.size() == 0: return stops stops.createAnalyticalFeature("radius", TMP_RADIUS) stops.createAnalyticalFeature("mean_x", TMP_MEAN_X) stops.createAnalyticalFeature("mean_y", TMP_MEAN_Y) stops.createAnalyticalFeature("mean_z", TMP_MEAN_Z) stops.createAnalyticalFeature("id_ini", TMP_IDSTART) stops.createAnalyticalFeature("id_end", TMP_IDEND) stops.createAnalyticalFeature("sigma_x", TMP_STD_X) stops.createAnalyticalFeature("sigma_y", TMP_STD_Y) stops.createAnalyticalFeature("sigma_z", TMP_STD_Z) stops.createAnalyticalFeature("duration", TMP_DURATION) stops.createAnalyticalFeature("nb_points", TMP_NBPOINTS) stops.operate(Operator.Operator.QUAD_ADDER, "sigma_x", "sigma_y", "rmse") stops.base = track.base return stops