from ppodd.core import *
import numpy as np
def add_hdg_offset(hdg, hdg_offset):
"""function takes care of angle calculations and substracts 360 if
hdg is greater than 360 and adds 360 if angle is smaller than 0.
"""
result = np.array(hdg) + hdg_offset
result[np.where(result > 360.)] += -360.
result[np.where(result < 0.)] += 360.
return result
def correct_tas_rvsm(tas_rvsm, dit, tas_scale_factor=None):
"""
Correcting true airspeed measurement for temperature effect.
dit is the deiced temperature measurements.
see: http://en.wikipedia.org/wiki/Airspeed
:param tas_rvsm: True Air Speed from the flight computer
:param dit: deiced temperature
:param tas_scale_factor: Correction factor for the true air speed
"""
if not tas_scale_factor:
tas_scale_factor = 0.9984
mach = tas_rvsm / (661.4788 * 0.514444) / np.sqrt(dit/288.15)
delta_tas = 4.0739 - (32.1681 * mach) + (52.7136 * (mach**2))
tas = (tas_rvsm - delta_tas) * tas_scale_factor
return tas
def calc_noturb_wspd(tas_rvsm, hdg_gin, gspd_north, gspd_east, dit, hdg_offset=None, tas_scale_factor=None):
"""
Calculates u and v as the aircraft does it
see: http://delphiforfun.org/programs/Math_Topics/WindTriangle.htm
http://www.pilotfriend.com/training/flight_training/nav/calcs.htm
"""
if hdg_offset:
hdg = add_hdg_offset(hdg_gin, hdg_offset)
else:
hdg = hdg_gin
if not tas_scale_factor:
tas_scale_factor = 0.9984
#adjust tas_rvsm for temperature effects
tas = correct_tas_rvsm(tas_rvsm, dit, tas_scale_factor=tas_scale_factor)
air_spd_east = np.cos(np.deg2rad(hdg - 90.)) * tas
air_spd_north = np.sin(np.deg2rad(hdg - 90.)) * tas
u = gspd_east - air_spd_east
v = air_spd_north + gspd_north
return (u, v)
def calc_noturb_flag(tas_rvsm, hdg_gin, veln_gin, vele_gin, tat_di_r, roll_gin, roll_threshold=None):
"""
uses the flags for the variables that are used to calculate the
noturb winds. noturb wind speeds are invalid in turns. This is taken care of
by flagging those values using a roll_threshold (default=1.5)
"""
if not roll_threshold:
roll_threshold = 1.5
tas_rvsm_flag = np.max(tas_rvsm.flag, axis=1)
hdg_gin_flag = np.max(hdg_gin.flag, axis=1)
gspd_north_flag = np.max(veln_gin.flag, axis=1)
gspd_east_flag = np.max(vele_gin.flag, axis=1)
dit_flag = np.max(tat_di_r.flag, axis=1)
#flag all data points 3, that exceed roll_threshold
roll_flag = np.where(np.abs(roll_gin) < roll_threshold,
roll_gin*0,
roll_gin*0+3)
flag_data = np.column_stack((tas_rvsm_flag,
hdg_gin_flag,
gspd_north_flag,
gspd_east_flag,
dit_flag,
roll_flag))
flag_data = np.max(flag_data, axis=1)
flag_data[flag_data < 0] = 3
flag_data[flag_data > 3] = 3
return flag_data
[docs]class noturb_windvectors(cal_base):
"""
Calculation of windvectors that do not rely on the turbulence probe in the
radom of the aircraft. The data are especially useful in icing conditions,
when the pressure sensors in the radom are blocked by ice and no tub
:INPUTS:
| VELE_GIN
| VELN_GIN
| HDG_GIN
| TAT_DI_R
| TAS_RVSM
| ROLL_GIN
tas_scale_factor = 0.9984
:FLAGGING:
The flag is inherited from the input variables. The flag is determined by
choosing the worst flag from the input variables. In addition to this a roll
angle threshold is used, which is set to 1.5 degrees. All values with an
absolute roll angle greater than this are flagged "3".
"""
def __init__(self, dataset):
#print(' *** ADD NOTURB WINDVECTORS - INIT ***')
self.input_names=['VELE_GIN',
'VELN_GIN',
'HDG_GIN',
'TAT_DI_R',
'TAS_RVSM',
'ROLL_GIN']
self.outputs=[parameter('U_NOTURB',
units='m s-1',
frequency=1,
long_name='Eastward wind component derived from aircraft instruments and GIN',
standard_name='eastward_wind'),
parameter('V_NOTURB',
units='m s-1',
frequency=1,
long_name='Northward wind component derived from aircraft instruments and GIN',
standard_name='northward_wind')]
self.version=1.00
cal_base.__init__(self,dataset)
def process(self):
#TODO: move the two calibration coefficients to the flight-cst file
hdg_offset = 0.35
tas_scale_factor = 0.9984
d = self.dataset
match = d.matchtimes(['TAS_RVSM', 'HDG_GIN', 'VELN_GIN', 'VELE_GIN', 'TAT_DI_R'])
tas_rvsm = d['TAS_RVSM'].data.ismatch(match)
hdg_gin = d['HDG_GIN'].data.ismatch(match)
veln_gin = d['VELN_GIN'].data.ismatch(match)
vele_gin = d['VELE_GIN'].data.ismatch(match)
tat_di_r = d['TAT_DI_R'].data.ismatch(match)
roll_gin = d['ROLL_GIN'].data.ismatch(match)
u_noturb_data, v_noturb_data = calc_noturb_wspd(tas_rvsm,
hdg_gin,
veln_gin,
vele_gin,
tat_di_r,
hdg_offset=hdg_offset,
tas_scale_factor=tas_scale_factor)
flag_data = calc_noturb_flag(tas_rvsm, hdg_gin, veln_gin, vele_gin, tat_di_r, roll_gin)
u_noturb_data = np.mean(u_noturb_data, axis=1)
v_noturb_data = np.mean(v_noturb_data, axis=1)
u_noturb = flagged_data(u_noturb_data, tas_rvsm.times, flag_data)
v_noturb = flagged_data(v_noturb_data, tas_rvsm.times, flag_data)
self.outputs[0].data = u_noturb
self.outputs[1].data = v_noturb