def derive(self, pitch=P('Pitch'), climbs=S('Initial Climb')): for climb in climbs: masked_pitch = mask_outside_slices(pitch.array, [climb.slice]) pitch_index = np.ma.argmax( masked_pitch <= -10) or np.ma.argmin(masked_pitch) scaling_factor = abs(masked_pitch[pitch_index]) / 10 window_threshold = -10.00 * scaling_factor min_window_threshold = -8.00 * scaling_factor window_size = 32 window_threshold_step = 0.050 * scaling_factor diffs = np.ma.ediff1d(masked_pitch[climb.slice.start:pitch_index]) diffs_exist = diffs.data.size >= 2 big_diff_index = -1 while diffs_exist: sig_pitch_threshold = window_threshold / window_size for i, d in enumerate(diffs): # Look for the first big negative pitch spike if diffs[slices_int( i, i + window_size)].sum() < window_threshold: # Find the first significant negative value within the # spike and make that the starting point of the phase big_diff_index = np.ma.argmax( diffs[i:i + window_size] < sig_pitch_threshold) + i break # Bail on match or total failure if big_diff_index != -1 or window_size < 2: break # Shrink window size instead of looking for insignificant # spikes and scale window/pitch thresholds accordingly if window_threshold >= min_window_threshold: window_size //= 2 min_window_threshold /= 2 window_threshold /= 2 window_threshold_step /= 2 sig_pitch_threshold *= 2 else: window_threshold += window_threshold_step if big_diff_index != -1: self.create_section( slice(climb.slice.start + big_diff_index, pitch_index)) # Worst case fallback, this should happen extremely rarely # and would trigger all events related to this phase else: self.create_section(slice(climb.slice.start, climb.slice.stop))
def derive(self, pitch=P('Pitch'), climbs=S('Initial Climb')): for climb in climbs: masked_pitch = mask_outside_slices(pitch.array, [climb.slice]) pitch_index = np.ma.argmax(masked_pitch <= -10) or np.ma.argmin(masked_pitch) scaling_factor = abs(masked_pitch[pitch_index]) / 10 window_threshold = -10.00 * scaling_factor min_window_threshold = -8.00 * scaling_factor window_size = 32 window_threshold_step = 0.050 * scaling_factor diffs = np.ma.ediff1d(masked_pitch[climb.slice.start:pitch_index]) diffs_exist = diffs.data.size >= 2 big_diff_index = -1 while diffs_exist: sig_pitch_threshold = window_threshold / window_size for i, d in enumerate(diffs): # Look for the first big negative pitch spike if diffs[i:i+window_size].sum() < window_threshold: # Find the first significant negative value within the # spike and make that the starting point of the phase big_diff_index = np.ma.argmax(diffs[i:i+window_size] < sig_pitch_threshold) + i break # Bail on match or total failure if big_diff_index != -1 or window_size < 2: break # Shrink window size instead of looking for insignificant # spikes and scale window/pitch thresholds accordingly if window_threshold >= min_window_threshold: window_size /= 2; min_window_threshold /= 2; window_threshold /= 2; window_threshold_step /= 2 sig_pitch_threshold *= 2 else: window_threshold += window_threshold_step if big_diff_index != -1: self.create_section(slice(climb.slice.start + big_diff_index, pitch_index)) # Worst case fallback, this should happen extremely rarely # and would trigger all events related to this phase else: self.create_section(slice(climb.slice.start, climb.slice.stop))
def derive(self, num=P('Flight Number'), mobiles=S('Mobile')): # Limit to Mobile sections num_array = mask_outside_slices(num.array, mobiles.get_slices()) # Q: Should we validate the flight number? if num.array.dtype.type is np.string_: value = most_common_value(num_array, threshold=0.45) if value is not None: # Only parse valid ASCII characters try: self.set_flight_attr(re.sub(r'[^\x00-\x7f]', r'', value.decode())) except UnicodeDecodeError: self.set_flight_attr(None) return # Values of 0 are invalid flight numbers array = np.ma.masked_less_equal(num_array, 0) # Ignore masked values compressed_array = array.compressed() _, minvalue = min_value(compressed_array) if minvalue is None or minvalue < 0: self.warning( "'%s' only supports unsigned (positive) values > 0, " "but none were found. Cannot determine flight number", self.name) self.set_flight_attr(None) return # note reverse of value, index from max_value due to bincount usage. value, count = max_value( np.bincount(compressed_array.astype(np.integer))) if count > len(compressed_array) * 0.45: # this value accounts for at least 45% of the values in the array self.set_flight_attr(str(int(value))) else: self.warning("Only %d out of %d flight numbers were the same." " Flight Number attribute will be set as None.", count or 0, len(num.array)) self.set_flight_attr(None) return