def derive(self, gnds=S('Grounded'), pitch=P('Pitch'), roll=P('Roll')): decks = [] for gnd in gnds: # The fourier transform for pitching motion... p = pitch.array[gnd.slice] if np.all(p.mask): continue n = float(len(p)) # Scaling the result to be independet of data length. fft_p = np.abs(np.fft.rfft(p - moving_average(p))) / n # similarly for roll r = roll.array[gnd.slice] if np.all(r.mask): continue fft_r = np.abs(np.fft.rfft(r - moving_average(r))) / n # What was the maximum harmonic seen? fft_max = np.ma.max(fft_p + fft_r) # Values of less than 0.1 were on the ground, and 0.34 on deck for the one case seen to date. if fft_max > 0.2: decks.append(gnd.slice) if decks: self.create_sections(decks)
def derive(self, gnds=S('Grounded'), pitch=P('Pitch'), roll=P('Roll')): decks = [] for gnd in gnds: # The fourier transform for pitching motion... p = pitch.array[gnd.slice] if np.all(p.mask): continue n = float( len(p)) # Scaling the result to be independet of data length. fft_p = np.abs(np.fft.rfft(p - moving_average(p))) / n # similarly for roll r = roll.array[gnd.slice] if np.all(r.mask): continue fft_r = np.abs(np.fft.rfft(r - moving_average(r))) / n # What was the maximum harmonic seen? fft_max = np.ma.max(fft_p + fft_r) # Values of less than 0.1 were on the ground, and 0.34 on deck for the one case seen to date. if fft_max > 0.2: decks.append(gnd.slice) if decks: self.create_sections(decks)
def derive(self, alt_rad=P('Altitude Radio'), alt_aal=P('Altitude AAL'), alt_baro=P('Altitude STD Smoothed'), gog=M('Gear On Ground')): # If we have no Altitude Radio we will have to fall back to Altitude AAL if not alt_rad: self.array = alt_aal.array return # When was the helicopter on the ground? gear_on_grounds = np.ma.clump_masked(np.ma.masked_equal(gog.array, 1)) # Find and eliminate short spikes (15 seconds) as these are most likely errors. short_spikes = slices_find_small_slices(gear_on_grounds, time_limit=20, hz=gog.hz) for _slice in short_spikes: gog.array[_slice.start:_slice.stop] = 0 # Remove slices shorter than 15 seconds as these are most likely created in error. gear_on_grounds = slices_remove_small_slices(gear_on_grounds, time_limit=20, hz=gog.hz) # Compute the half period which we will need. hp = int(alt_rad.frequency*ALTITUDE_AGL_SMOOTHING) // 2 # We force altitude AGL to be zero when the gear shows 'Ground' state alt_agl = moving_average(np.maximum(alt_rad.array, 0.0) * (1 - gog.array.data), window=hp*2+1, weightings=None) # Refine the baro estimates length = len(alt_agl)-1 baro_sections = np.ma.clump_masked(np.ma.masked_greater(alt_agl, ALTITUDE_AGL_TRANS_ALT)) for baro_section in baro_sections: begin = max(baro_section.start - 1, 0) end = min(baro_section.stop + 1, length) start_diff = alt_baro.array[begin] - alt_agl[begin] stop_diff = alt_baro.array[end] - alt_agl[end] if start_diff is not np.ma.masked and stop_diff is not np.ma.masked: diff = np.linspace(start_diff, stop_diff, end-begin-2) alt_agl[begin+1:end-1] = alt_baro.array[begin+1:end-1]-diff elif start_diff is not np.ma.masked: alt_agl[begin+1:end-1] = alt_baro.array[begin+1:end-1] - start_diff elif stop_diff is not np.ma.masked: alt_agl[begin+1:end-1] = alt_baro.array[begin+1:end-1] - stop_diff else: pass low_sections = np.ma.clump_unmasked(np.ma.masked_greater(alt_agl, 5)) for both in slices_and(low_sections, gear_on_grounds): alt_agl[both] = 0.0 ''' # Quick visual check of the altitude agl. import matplotlib.pyplot as plt plt.plot(alt_baro.array, 'y-') plt.plot(alt_rad.array, 'r-') plt.plot(alt_agl, 'b-') plt.show() ''' self.array = alt_agl
def derive(self, alt_rad=P('Altitude Radio'), alt_aal=P('Altitude AAL'), alt_baro=P('Altitude STD Smoothed'), gog=M('Gear On Ground')): # If we have no Altitude Radio we will have to fall back to Altitude AAL if not alt_rad: self.array = alt_aal.array return # When was the helicopter on the ground? gear_on_grounds = np.ma.clump_masked(np.ma.masked_equal(gog.array, 1)) # Find and eliminate short spikes (15 seconds) as these are most likely errors. short_spikes = slices_find_small_slices(gear_on_grounds, time_limit=15, hz=gog.hz) for slice in short_spikes: gog.array[slice.start:slice.stop] = 0 # Remove slices shorter than 15 seconds as these are most likely created in error. gear_on_grounds = slices_remove_small_slices(gear_on_grounds, time_limit=15, hz=gog.hz) # Compute the half period which we will need. hp = int(alt_rad.frequency*ALTITUDE_AGL_SMOOTHING)//2 # We force altitude AGL to be zero when the gear shows 'Ground' state alt_agl = moving_average(np.maximum(alt_rad.array, 0.0) * (1 - gog.array.data), window=hp*2+1, weightings=None) # Refine the baro estimates length = len(alt_agl)-1 baro_sections = np.ma.clump_masked(np.ma.masked_greater(alt_agl, ALTITUDE_AGL_TRANS_ALT)) for baro_section in baro_sections: begin = max(baro_section.start - 1, 0) end = min(baro_section.stop + 1, length) start_diff = alt_baro.array[begin] - alt_agl[begin] stop_diff = alt_baro.array[end] - alt_agl[end] if start_diff is not np.ma.masked and stop_diff is not np.ma.masked: diff = np.linspace(start_diff, stop_diff, end-begin-2) alt_agl[begin+1:end-1] = alt_baro.array[begin+1:end-1]-diff elif start_diff is not np.ma.masked: alt_agl[begin+1:end-1] = alt_baro.array[begin+1:end-1] - start_diff elif stop_diff is not np.ma.masked: alt_agl[begin+1:end-1] = alt_baro.array[begin+1:end-1] - stop_diff else: pass low_sections = np.ma.clump_unmasked(np.ma.masked_greater(alt_agl, 5)) for both in slices_and(low_sections, gear_on_grounds): alt_agl[both] = 0.0 ''' # Quick visual check of the altitude agl. import matplotlib.pyplot as plt plt.plot(alt_baro.array, 'y-') plt.plot(alt_rad.array, 'r-') plt.plot(alt_agl, 'b-') plt.show() ''' self.array = alt_agl
def derive(self, torq_max=P('Eng (*) Torque Max'), torq_min=P('Eng (*) Torque Min')): diff = (torq_max.array - torq_min.array) window = 5 # 5 second window self.array = moving_average(diff, window=window)
def derive(self, gl=M('Gear (L) On Ground'), gr=M('Gear (R) On Ground'), vert_spd=P('Vertical Speed'), torque=P('Eng (*) Torque Avg'), ac_series=A('Series'), collective=P('Collective')): if gl and gr: delta = abs((gl.offset - gr.offset) * gl.frequency) if 0.75 < delta or delta < 0.25: # If the samples of the left and right gear are close together, # the best representation is to map them onto a single # parameter in which we accept that either wheel on the ground # equates to gear on ground. self.array = np.ma.logical_or(gl.array, gr.array) self.frequency = gl.frequency self.offset = gl.offset return else: # If the paramters are not co-located, then # merge_two_parameters creates the best combination possible. self.array, self.frequency, self.offset = merge_two_parameters( gl, gr) return elif gl or gr: gear = gl or gr self.array = gear.array self.frequency = gear.frequency self.offset = gear.offset elif vert_spd and torque: vert_spd_limit = 100.0 torque_limit = 30.0 if ac_series and ac_series.value == 'Columbia 234': vert_spd_limit = 125.0 torque_limit = 22.0 collective_limit = 15.0 vert_spd_array = align( vert_spd, torque) if vert_spd.hz != torque.hz else vert_spd.array collective_array = align( collective, torque) if collective.hz != torque.hz else collective.array vert_spd_array = moving_average(vert_spd_array) torque_array = moving_average(torque.array) collective_array = moving_average(collective_array) roo_vs_array = runs_of_ones( abs(vert_spd_array) < vert_spd_limit, min_samples=1) roo_torque_array = runs_of_ones(torque_array < torque_limit, min_samples=1) roo_collective_array = runs_of_ones( collective_array < collective_limit, min_samples=1) vs_and_torque = slices_and(roo_vs_array, roo_torque_array) grounded = slices_and(vs_and_torque, roo_collective_array) array = np_ma_zeros_like(vert_spd_array) for _slice in slices_remove_small_slices(grounded, count=2): array[_slice] = 1 array.mask = vert_spd_array.mask | torque_array.mask array.mask = array.mask | collective_array.mask self.array = nearest_neighbour_mask_repair(array) self.frequency = torque.frequency self.offset = torque.offset else: vert_spd_array = align( vert_spd, torque) if vert_spd.hz != torque.hz else vert_spd.array # Introducted for S76 and Bell 212 which do not have Gear On Ground available vert_spd_array = moving_average(vert_spd_array) torque_array = moving_average(torque.array) grounded = slices_and( runs_of_ones(abs(vert_spd_array) < vert_spd_limit, min_samples=1), runs_of_ones(torque_array < torque_limit, min_samples=1)) array = np_ma_zeros_like(vert_spd_array) for _slice in slices_remove_small_slices(grounded, count=2): array[_slice] = 1 array.mask = vert_spd_array.mask | torque_array.mask self.array = nearest_neighbour_mask_repair(array) self.frequency = torque.frequency self.offset = torque.offset else: # should not get here if can_operate is correct raise NotImplementedError()
def derive(self, gl=M('Gear (L) On Ground'), gr=M('Gear (R) On Ground'), vert_spd=P('Vertical Speed'), torque=P('Eng (*) Torque Avg'), ac_series=A('Series'), collective=P('Collective')): if gl and gr: delta = abs((gl.offset - gr.offset) * gl.frequency) if 0.75 < delta or delta < 0.25: # If the samples of the left and right gear are close together, # the best representation is to map them onto a single # parameter in which we accept that either wheel on the ground # equates to gear on ground. self.array = np.ma.logical_or(gl.array, gr.array) self.frequency = gl.frequency self.offset = gl.offset return else: # If the paramters are not co-located, then # merge_two_parameters creates the best combination possible. self.array, self.frequency, self.offset = merge_two_parameters(gl, gr) return elif gl or gr: gear = gl or gr self.array = gear.array self.frequency = gear.frequency self.offset = gear.offset elif vert_spd and torque: vert_spd_limit = 100.0 torque_limit = 30.0 if ac_series and ac_series.value == 'Columbia 234': vert_spd_limit = 125.0 torque_limit = 22.0 collective_limit = 15.0 vert_spd_array = align(vert_spd, torque) if vert_spd.hz != torque.hz else vert_spd.array collective_array = align(collective, torque) if collective.hz != torque.hz else collective.array vert_spd_array = moving_average(vert_spd_array) torque_array = moving_average(torque.array) collective_array = moving_average(collective_array) roo_vs_array = runs_of_ones(abs(vert_spd_array) < vert_spd_limit, min_samples=1) roo_torque_array = runs_of_ones(torque_array < torque_limit, min_samples=1) roo_collective_array = runs_of_ones(collective_array < collective_limit, min_samples=1) vs_and_torque = slices_and(roo_vs_array, roo_torque_array) grounded = slices_and(vs_and_torque, roo_collective_array) array = np_ma_zeros_like(vert_spd_array) for _slice in slices_remove_small_slices(grounded, count=2): array[_slice] = 1 array.mask = vert_spd_array.mask | torque_array.mask array.mask = array.mask | collective_array.mask self.array = nearest_neighbour_mask_repair(array) self.frequency = torque.frequency self.offset = torque.offset else: vert_spd_array = align(vert_spd, torque) if vert_spd.hz != torque.hz else vert_spd.array # Introducted for S76 and Bell 212 which do not have Gear On Ground available vert_spd_array = moving_average(vert_spd_array) torque_array = moving_average(torque.array) grounded = slices_and(runs_of_ones(abs(vert_spd_array) < vert_spd_limit, min_samples=1), runs_of_ones(torque_array < torque_limit, min_samples=1)) array = np_ma_zeros_like(vert_spd_array) for _slice in slices_remove_small_slices(grounded, count=2): array[_slice] = 1 array.mask = vert_spd_array.mask | torque_array.mask self.array = nearest_neighbour_mask_repair(array) self.frequency = torque.frequency self.offset = torque.offset else: # should not get here if can_operate is correct raise NotImplementedError()
def derive(self, vert_spd=P('Vertical Speed'), torque=P('Eng (*) Torque Avg'), ac_series=A('Series'), collective=P('Collective')): vert_spd_limit = 100.0 torque_limit = 30.0 if ac_series and ac_series.value == 'Columbia 234': vert_spd_limit = 125.0 torque_limit = 22.0 collective_limit = 15.0 vert_spd_array = align( vert_spd, torque) if vert_spd.hz != torque.hz else vert_spd.array collective_array = align( collective, torque) if collective.hz != torque.hz else collective.array vert_spd_array = moving_average(vert_spd_array) torque_array = moving_average(torque.array) collective_array = moving_average(collective_array) roo_vs_array = runs_of_ones(abs(vert_spd_array) < vert_spd_limit, min_samples=1) roo_torque_array = runs_of_ones(torque_array < torque_limit, min_samples=1) roo_collective_array = runs_of_ones( collective_array < collective_limit, min_samples=1) vs_and_torque = slices_and(roo_vs_array, roo_torque_array) grounded = slices_and(vs_and_torque, roo_collective_array) array = np_ma_zeros_like(vert_spd_array) for _slice in slices_remove_small_slices(grounded, count=2): array[_slice] = 1 array.mask = vert_spd_array.mask | torque_array.mask array.mask = array.mask | collective_array.mask self.array = nearest_neighbour_mask_repair(array) self.frequency = torque.frequency self.offset = torque.offset else: vert_spd_array = align( vert_spd, torque) if vert_spd.hz != torque.hz else vert_spd.array # Introducted for S76 and Bell 212 which do not have Gear On Ground available vert_spd_array = moving_average(vert_spd_array) torque_array = moving_average(torque.array) grounded = slices_and( runs_of_ones(abs(vert_spd_array) < vert_spd_limit, min_samples=1), runs_of_ones(torque_array < torque_limit, min_samples=1)) array = np_ma_zeros_like(vert_spd_array) for _slice in slices_remove_small_slices(grounded, count=2): array[_slice] = 1 array.mask = vert_spd_array.mask | torque_array.mask self.array = nearest_neighbour_mask_repair(array) self.frequency = torque.frequency self.offset = torque.offset