Está en la página 1de 10

AMDAR

June 19, 2021

1 AMDAR
Aircraft Meteorological Data Relay (AMDAR, por su sigla en inglés) consisten en reportes au-
tomáticos hechos por sensores instalados a bordo de algunas aeronaves. Los datos de estos sensores
son procesados por la computadora de vuelo para luego ser enviados de manera inmediata vía radio
HF, VHF y/o satélite.
Una vez en tierra, los datos se transmiten a los Servicios Meteorológicos e Hidrológicos Nacionales
(SMHN) , donde se procesan, controlan y transmiten al Global Telecommunication System (GTS,
por su sigla en inglés) de la Organización Meteorológica Mundial (OMM). AMDAR

1.1 Imports
[1]: import pandas as pd
import numpy as np
from glob import glob
import geopandas as gpd
import matplotlib.pyplot as plt
from scipy import stats

1.1.1 importm Chile extend

[2]: world = gpd.read_file(gpd.datasets.get_path('naturalearth_lowres'))


chile = world[world.name=='Chile']
chile.boundary.plot();

1
1.1.2 Read and filter AMDAR data
[ ]: #read all avaiable data in src folder keep only between (-5 and 5 °C) and␣
,→useful columns

files = glob('src/*.zip')
df = (pd.concat([pd.read_csv(file, sep=';')
.query('-5 <= temperaturaAire <= 5') for file in files])
.drop(columns=['faseDelVuelo','aeropuertoOrigen','aeropuertoDestino',
'numeroSecuencia','identificadorAeronave']).sort_index()
)
# keep only inside chile data
gdf = gpd.overlay(gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(df.longitud,␣
,→df.latitud),

crs='EPSG:4326'), chile, how='intersection')


# set time as index
gdf.index = pd.to_datetime(gdf['momento'])
gdf = gdf.
,→drop(columns=['momento','pop_est','continent','name','iso_a3','gdp_md_est'])

[ ]: #save data to gpkg and csv for later use


gdf.to_file('amdar_chile.gpkg', driver="GPKG")
gdf.to_csv('amdar_chile.csv')

2
1.2 Análisis Exploratorio
1.2.1 read data from csv (much faster)

[3]: df = pd.read_csv('amdar_chile.csv')
gdf = gpd.GeoDataFrame(df, geometry=gpd.points_from_xy(df.longitud,df.latitud),␣
,→crs='EPSG:4326')

gdf.index = pd.to_datetime(gdf['momento'])
gdf = gdf.drop(columns=['momento'])
gdf.head()

[3]: numeroDeVuelo latitud longitud altitudPresion \


momento
2020-04-01 00:01:07 0OQRTN0Q -33.250 -71.067 4830
2019-07-01 00:00:18 GMXRSURA -33.017 -70.800 2177
2018-08-01 00:00:25 IIUBTJZA -32.850 -70.783 2953
2019-04-01 00:00:29 COYDYTBA -19.050 -70.267 5176
2017-12-01 00:00:35 KMDTPZZA -24.083 -70.400 5423

direccionViento intensidadViento temperaturaAire \


momento
2020-04-01 00:01:07 279.0 23.32610 -3.15
2019-07-01 00:00:18 357.0 15.55070 2.85
2018-08-01 00:00:25 350.0 31.10140 -0.15
2019-04-01 00:00:29 301.0 7.77536 -2.15
2017-12-01 00:00:35 256.0 15.55070 -4.15

humedadRelativa geometry
momento
2020-04-01 00:01:07 NaN POINT (-71.06700 -33.25000)
2019-07-01 00:00:18 NaN POINT (-70.80000 -33.01700)
2018-08-01 00:00:25 NaN POINT (-70.78300 -32.85000)
2019-04-01 00:00:29 NaN POINT (-70.26700 -19.05000)
2017-12-01 00:00:35 NaN POINT (-70.40000 -24.08300)

1.2.2 plot data in Chile

[4]: ax = chile.boundary.plot(figsize=(8, 12));


gdf.plot(ax=ax, color='k', markersize=0.5);

3
4
1.2.3 Zonas de interés (Aeropuertos)

[5]: zones = {
'arica': (-18.66, -19.28),
'calama': (-22, -23.4),
'antofa': (-23.6, -24.58),
'copiapo': (-27.4, -28.5),
'coquimbo': (-29.1, -31.1),
'santiago': (-32.1, -34.4),
'conce': (-35.7, -37.5),
'temuco': (-37.9, -39.8),
'osorno': (-39.9, -41),
'puerto_montt': (-41, -42.3),
'coyhaique': (-45.2, -46),
'punta_arenas': (-52, -53.2)
}

1.2.4 plot a zone

[6]: zone = 'santiago'


lat = zones[zone] #(-32.5, -33.5)
ax = chile.boundary.plot(figsize=(6, 6))
ax.set(ylim=(lat[1], lat[0]), xlim=(-72.5, -69.5))
gdf[gdf['latitud'].between(lat[1], lat[0])].plot(ax=ax, color='k', markersize=1.
,→5);

5
1.2.5 Find Isoterma
[7]: # Define linear fit function
def isot(z, tu=0):
r = np.nan
x, y = z['temperaturaAire'].to_numpy(), z['altitudPresion'].to_numpy()
if x.size > 5: # min 5 points ?
mask = (stats.zscore(y) > -1.25) # remove low points (inversión térmica)
x, y = x[mask], y[mask]
f = np.polyfit(x, y, 1)
r = f[1] + f[0]*tu
return r
# apply it for all zones
res = []
tu = 1
for zone in zones:
lat = zones[zone]
wa = (gdf[gdf.latitud.between(lat[1], lat[0])]

6
.groupby(pd.Grouper(freq='24H', offset='8H', label='right')) # de 8␣
am a 8 pm.
,→

.apply(isot, tu=tu)
)
wa.index = pd.to_datetime(wa.index)
res.append(wa)
res = pd.concat(res, keys= zones, axis=1).round(0)
res.to_excel('amdar_isot.xlsx')
res.head()

C:\Users\ROC\miniconda3\envs\gee\lib\site-
packages\pandas\core\groupby\groupby.py:878: RankWarning: Polyfit may be poorly
conditioned
return func(g, *args, **kwargs)

[7]: arica calama antofa copiapo coquimbo santiago \


momento
2017-10-04 08:00:00 NaN NaN NaN NaN NaN 3142.0
2017-10-05 08:00:00 NaN NaN 4369.0 NaN NaN 2581.0
2017-10-06 08:00:00 NaN NaN NaN NaN NaN NaN
2017-10-07 08:00:00 NaN NaN NaN NaN NaN NaN
2017-10-08 08:00:00 NaN NaN NaN NaN NaN NaN

conce temuco osorno puerto_montt coyhaique \


momento
2017-10-04 08:00:00 NaN NaN NaN NaN NaN
2017-10-05 08:00:00 NaN 1070.0 NaN NaN NaN
2017-10-06 08:00:00 NaN NaN NaN NaN NaN
2017-10-07 08:00:00 NaN NaN NaN NaN NaN
2017-10-08 08:00:00 NaN NaN NaN NaN NaN

punta_arenas
momento
2017-10-04 08:00:00 NaN
2017-10-05 08:00:00 1157.0
2017-10-06 08:00:00 NaN
2017-10-07 08:00:00 NaN
2017-10-08 08:00:00 NaN

1.2.6 Plot fit temp vs altitud


[8]: zone = 'santiago'
d1, d2 = '2020-07-03', '2020-07-04'
lat = zones[zone]
wa = pd.DataFrame(gdf[gdf['latitud'].between(lat[1], lat[0])]).sort_index()
wa = wa.loc[f'{d1} 08:00:00':f'{d2} 08:00:00']
wa = wa[stats.zscore(wa.altitudPresion) > -1.25] # remove low points (inversión␣
,→térmica)

7
x, y = wa['temperaturaAire'], wa['altitudPresion']
f = np.polyfit(x, y, 1)
fit = np.poly1d(f)
ax = wa.plot(kind='scatter', x='temperaturaAire', y='altitudPresion',
c=wa.index.hour, colorbar=True, cmap='viridis_r')
xp = np.linspace(-5, 5)
ax.plot(xp, fit(xp), 'r-');

1.2.7 Compare AMDAR with Quinta Normal


Import data
[9]: file = r'amdar_isot.xlsx'
df = pd.read_excel(file, parse_dates=True,
index_col=0, header=0)['santiago'].resample('D').mean()
#read quinta normal pd, tmin, tmax data
hi = pd.read_excel('330020_Quinta_Normal_Santiago.xlsx',
'ts', index_col=0, header=0).loc[str(df.index[0]):,␣
,→['pd','tmin','tmax']].query('pd > 10')

df = pd.concat([hi,df], axis=1).dropna(how='any', axis=0).rename({'santiago':


,→'lnt'}, axis=1)

df

[9]: pd tmin tmax lnt


2017-10-04 35.5 9.0 17.7 3142.0
2018-05-29 13.0 10.5 14.9 2978.0
2018-06-09 22.5 8.7 15.3 3272.0

8
2018-06-10 12.9 5.1 13.9 2370.0
2018-07-05 35.2 5.2 15.7 2099.0
2018-09-17 17.1 8.5 18.4 3117.0
2019-06-12 14.4 1.8 17.8 2432.0
2019-06-28 11.0 4.9 10.9 2659.0
2019-07-21 11.9 6.8 7.6 3098.0
2020-06-11 16.1 -0.6 12.2 2871.0
2020-06-23 17.3 7.5 13.5 1916.0
2020-06-29 31.8 8.2 11.1 2725.0
2020-07-04 42.8 5.1 9.4 2616.0
2020-07-21 17.5 6.3 11.8 2341.0

Calc isot quinta normal


[10]: tu = 1 #temp umbral
gt = 5.5/1000 # grad termico
he = 530 # altura estacion
k = 3 # coeficiente k
df['tind'] = 1/k*(df.tmax + (k-1)*df.tmin)
df['lnt_QN'] = he + ((df.tind - tu)/gt).astype(int)
df['tind'] = df['tind'].round(1)
df = df.rename(columns={'lnt':'lnt_AMDAR'})

Compare plot
[11]: df[['lnt_AMDAR','lnt_QN']].plot();

9
Abs mean diff
[13]: (df['lnt_AMDAR'] - df['lnt_QN']).abs().mean()

[13]: 786.7142857142857

10

También podría gustarte