PDA

Ver la Versión Completa : Datos Meteorológicos


gluglu
06-05-2007, 13:28:07
Estimados Compañeros del Foro :

Aquí os dejo mi versión de la lectura e interpretación de los datos meteorológicos obtenidos a traves del ftp de tgftp.nws.noaa.gov

Antes de pasar al código en sí mismo expongo las características particulares del código así como los componentes a incluir en el Form.

1. Leo los datos a partir de un TThread (METAR) creado para tal finalidad que se va a ejecutar cada cierto intervalo de tiempo, según viene definido en un componente adicional TTimer. En el ejemplo el intervalo está puesto a 600000, es decir, cada 10 minutos. Para saber si ha transcurrido el intervalo de 10 minuts establecido para volver a leer datos del FTP, hago uso de la propiedad Tag del propio TTimer.

2. Los datos del FTP se obtienen a través de un IdFTP de los componentes Indy.

3. En mi caso particular, muestro los datos en una barra de estado que a su vez contiene dos TLabels para la temperatura (LabelStMet1 y LabelStMet2), siendo LabelStMet2.Caption := 'ºC' un label fijo. El valor absoluto de la temperatura en grados centígrados se mostrará en el LabelStMet1.

4. Para mostrar el estado del cielo hago uso de dos TLabels adicionales (LabelStMet3 y LabelStMet4), que también se encuentran en la barra de estado al lado de la temperatura que me mostrarán símbolos obtenidos del juego de caracteres de font 'Wingdings 2' y 'Webdings'.

No puedo mostrar aquí los símbolos correspondientes, pero expongo los valores de caracteres que he utilizado en cada caso:

Cielo Despejado : Wingdings2 Chr(208)
Cielo Parcialmente Cubierto : Webdings Chr(158)
Cielo Casi Cubierto : Webdings Chr(157)
Cielo Totalmente Cubierto : Webdings Chr(235)

Lluvia : Webdings Chr(234)
Tormenta : Webdings Chr(154)
Nieve : Webdings Chr(233)

Al no tener un símbolo para Nubes y Claros, hago uso de los dos labels anteriormente expuestos, uno con el Cielo Despejado y otro con Cielo Totalmente Cubierto, predominando claramente el del Cielo Despejado por delante del Cielo Totalmente Cubierto. De esta manera consigo el efecto deseado de un sol grande delante de una nube pequeña.

5. La localización para el ejemplo es Málaga (código OACI = LEMG). Cada cual debería coger el aeropuerto de referencia más cercano a su localización. Más abajo os dejo la página para consultar tanto los códigos de aeropuertos españoles, como de cualquier aeropuerto del mundo.

En mi caso particular grabo la lectura del FTP en el directorio principal de mi disco duro C:. Se puede hacer de otras muchas maneras, por ejemplo también con un TMemoryStream, en vez de grabarlo a un fichero almacenado en el disco duro. Lo que pasa es que necesito ese fichero en mi disco duro para otros fines posteriores. (Aunque podreis ver que en el código incluido se borra al final).

6. La hora expresada en los METAR siempre es hora UTC. Por lo tanto si se quiere convertir en hora oficial de cada localización habrá que saber el Huso horario correspondiente y si tiene o no horario de verano en la fecha de lectura. Estos datos yo los tengo grabados en otra base de datos particular, pero a fines de ejemplo creí más conveniente eliminar dicho código e indicar directamente que en este caso he sumado 2 horas a la hora obtenida del FTP (Málaga = GMT+1 y hay que añadirle a la fecha de hoy el adelante de +1 hora por el horario de verano).

7. El viento se expresa en el METAR con velocidad en nudos (KT) y en grados según la dirección desde donde provenga el viento. La conversión se ha hecho a Km/h (KT x 1852), y la dirección de viento se ha convertido de grados a puntos cardinales. La aproximación a cada punto cardinal principal es de +- 20º. Así obtenemos direcciones de viento tales como N, NE, E, SE, S, SW, W, y NW.

8. El METAR también refleja además si el viento es mantenido o existen rachas de viento (gusts). Si en el METAR se añade la letra 'G' de rachas de viento, estas se muestran en el texto final detrás de la velocidad del viento mantenido y su dirección, entre paréntesis y en Km/h.

9. La temperatura del METAR muestra la temperatura en ºC y el punto de rocío. Con este dato (creo poco significativo para la mayoría de la gente, a no ser que practiquemos la nautica ...) podemos obtener la Humedad Relativa mediante la fórmula mostrada por ejemplo en esta página (http://www.jccm.es/edu/ies/cperezpastor/dptos/fq/matcien/humedad.htm).

10. Finalmente la presión atmosférica se muestra en milibares (mb).

Todos estos datos se acumulan en un String que se puede mostrar en cualquier otra parte del form y en el momento que se precise.

Un ejemplo de string resultante es : Málaga 10:00 : 25 Km/h NW 27 ºC 67% 1013 mb

Aquí va el código :

type
TMainform = class(TForm)
...

TMetar = class(TThread)
protected
procedure Execute; override;
public
end;

var
Mainform : TMainform;
Metar : TMetar;

implementation
...

procedure TMainform.FormActivate(Sender: TObject);
begin

Self.OnActivate := nil;

IdFTP1.Host := 'tgftp.nws.noaa.gov';
IdFTP1.Username := 'anonymous';

Timer1.Interval := 600000; // 10 Minutes
Timer1.Tag := 1;
Metar := TMetar.Create(False);
Metar.FreeOnTerminate := True;

end;

procedure TMainform.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
...
Metar.Terminate;
end;

procedure TMainform.Timer1Timer(Sender: TObject);
begin
Timer1.Tag := 1;
end;

procedure TMetar.Execute;
var
Temp : TFileStream;
Aux_METAR : TStringList;
Aux_Temp : String;
Aux_Met : String;
Aux_Val : Integer;
Aux_Val2 : Real;
Aux_Val3 : Integer;
begin

if MainForm.Timer1.Tag = 1 then begin

Temp := TFileStream.Create('C:\LEMG.Met', fmCreate);

try
MainForm.idFTP1.Connect;
MainForm.idFTP1.Get('data/observations/metar/stations/LEMG.TXT', Temp, True);
MainForm.idFTP1.Disconnect;
except
Temp.Free;
Exit;
end;
Temp.Free;

Aux_METAR := TStringList.Create;
Aux_METAR.LoadFromFile('C:\LEMG.Met');

Aux_Temp := IntToStr(StrToInt(Copy(Aux_METAR[0], PosEx('/', Aux_METAR[0], 18)-2, 2)));
MainForm.LabelStMet1.Caption := Aux_Temp;

MainForm.LabelStMet3.Visible := False;
MainForm.LabelStMet4.Visible := False;
if (PosEx('RA', Aux_METAR[0], 18) <> 0) or
(PosEx('SH', Aux_METAR[0], 18) <> 0) or
(PosEx('DZ', Aux_METAR[0], 18) <> 0) then begin
// Rain
MainForm.LabelStMet3.Visible := True;
MainForm.LabelStMet4.Visible := False;
MainForm.LabelStMet3.Caption := 'Û';
end else
if PosEx('SN', Aux_METAR[0], 18) <> 0 then begin
// Snow
MainForm.LabelStMet3.Visible := True;
MainForm.LabelStMet4.Visible := False;
MainForm.LabelStMet3.Caption := 'Ú';
end else
if PosEx('TS', Aux_METAR[0], 18) <> 0 then begin
// Snow
MainForm.LabelStMet3.Visible := True;
MainForm.LabelStMet4.Visible := False;
MainForm.LabelStMet3.Caption := 'Ü';
end else
if PosEx('OVC', Aux_METAR[0], 18) <> 0 then begin
// OverCast
MainForm.LabelStMet3.Visible := True;
MainForm.LabelStMet4.Visible := False;
MainForm.LabelStMet3.Caption := 'Ù';
end else
if PosEx('BKN', Aux_METAR[0], 18) <> 0 then begin
// Broken
MainForm.LabelStMet3.Visible := True;
MainForm.LabelStMet4.Visible := False;
MainForm.LabelStMet3.Caption := 'Ø';
end else
if PosEx('SCT', Aux_METAR[0], 18) <> 0 then begin
// Scatered
MainForm.LabelStMet3.Visible := True;
MainForm.LabelStMet4.Visible := False;
MainForm.LabelStMet3.Caption := '×';
end else
if PosEx('FEW', Aux_METAR[0], 18) <> 0 then begin
// Few
MainForm.LabelStMet3.Visible := True;
MainForm.LabelStMet4.Visible := True;
MainForm.LabelStMet3.Caption := 'Ù';
end else begin
MainForm.LabelStMet3.Visible := False;
MainForm.LabelStMet4.Visible := True;
end;

// Localización y Hora
Aux_Met := 'Malaga ';
Aux_Val := StrToInt(Copy(Aux_METAR[0], PosEx('Z', Aux_METAR[0], 24)-4, 2));
Aux_Val := Aux_Val + 2; // Horario oficial actual GMT+2
if Aux_Val < 10 then
Aux_Temp := '0'+IntToStr(Aux_Val)
else
Aux_Temp := IntToStr(Aux_Val);
Aux_Met := Aux_Met + Aux_Temp + ':' + Copy(Aux_METAR[0], PosEx('Z', Aux_METAR[0], 24)-2, 2) + ' : ';

// Viento
Aux_Val3 := 0;
if Pos('G', Copy(Aux_METAR[0], PosEx('KT', Aux_METAR[0], 24)-5, 5)) <> 0 then begin
Aux_Val3 := StrToInt(Copy(Aux_METAR[0], PosEx('KT', Aux_METAR[0], 24)-2, 2));
Aux_Val := StrToInt(Copy(Aux_METAR[0], PosEx('G', Aux_METAR[0],24)-2, 2));
end
else begin
Aux_Val := StrToInt(Copy(Aux_METAR[0], Pos('KT', Aux_METAR[0])-2, 2));
end;

Aux_Val2 := 1.852 * Aux_Val;
Aux_Temp := FormatFloat('0', Aux_Val2);
Aux_Met := Aux_Met + Aux_Temp + ' Km/h ';

if Aux_Val3 = 0 then
Aux_Val := StrToInt(Copy(Aux_METAR[0], PosEx('KT', Aux_METAR[0], 24)-5, 3))
else
Aux_Val := StrToInt(Copy(Aux_METAR[0], PosEx('G', Aux_METAR[0], 24)-5, 3));

// Dirección del Viento
if Aux_Val <= 20 then Aux_Temp := 'N' else
if Aux_Val <= 70 then Aux_Temp := 'NE' else
if Aux_Val <= 110 then Aux_Temp := 'E' else
if Aux_Val <= 160 then Aux_Temp := 'SE' else
if Aux_Val <= 200 then Aux_Temp := 'N' else
if Aux_Val <= 250 then Aux_Temp := 'SW' else
if Aux_Val <= 290 then Aux_Temp := 'W' else
if Aux_Val <= 340 then Aux_Temp := 'NW' else
Aux_Temp := 'N';
Aux_Met := Aux_Met + Aux_Temp + ' ';

// Rachas de Viento
if Aux_Val3 <> 0 then begin
Aux_Val2 := 1.852 * Aux_Val3;
Aux_Temp := FormatFloat('0', Aux_Val2);
Aux_Met := Aux_Met + '(' + Aux_Temp + ' Km/h) ';
end
else
Aux_Met := Aux_Met + ' ';

// Temperatura
Aux_Temp := IntToStr(StrToInt(Copy(Aux_METAR[0], PosEx('/', Aux_METAR[0], 18)-2, 2)));
if Copy(Aux_METAR[0], PosEx('/', Aux_METAR[0], 18)-3, 1) = 'M' then Aux_Temp := '-'+Aux_Temp;
Aux_Met := Aux_Met + Aux_Temp + ' ºC ';

// Humedad Relativa
Aux_Val := StrToInt(Aux_Temp);
if Copy(Aux_METAR[0], PosEx('/', Aux_METAR[0], 18)+1, 1) = 'M' then
Aux_Temp := '-' + IntToStr(StrToInt(Copy(Aux_METAR[0], PosEx('/', Aux_METAR[0], 18)+2, 2)))
else
Aux_Temp := IntToStr(StrToInt(Copy(Aux_METAR[0], PosEx('/', Aux_METAR[0], 18)+1, 2)));
Aux_Val3 := StrToInt(Aux_Temp);
Aux_Val2 := 100 * Power((112 - (0.1 * Aux_Val) + Aux_Val3) / (112 + (0.9 * Aux_Val)),8);
Aux_Temp := FormatFloat('0', Aux_Val2);
Aux_Met := Aux_Met + Aux_Temp + '% ';

// Presión atmosférica
Aux_Temp := Copy(Aux_METAR[0], Pos('Q', Aux_METAR[0])+1, 4);
Aux_Met := Aux_Met + Aux_Temp + ' mb';

MainForm.LabelPanelMet.Caption := Aux_Met;

DeleteFile('C:\LEMG.Met');
MainForm.Timer1.Tag := 0;

end;

end;


Notas adicionales :

A. Para el cálculo de la humedad relativa es necesario elevar el número obtenido a una potencia, por lo que es necesario incluir en el Uses de nuestro programa la unidad 'Math'

B. El METAR obtenido del FTP indicado, incluye al comienzo la fecha y la hora del mismo, aunque esta venga después codificada dentro del propio código METAR. Por ello hago uso de la función PosEx y considero casi siempre el código de METAR a partir de la posición 28. Por ello también hay que incluir en el Uses de nuestro programa la unidad 'StrUtils'

C. La explicación completa de un METAR la podeis encontrar aqui (http://www.inm.es/web/sup/tiempo/infaero/pdf/Guia_MET.pdf).
En este mismo documento, en el Anexo I vienen todos los códigos de los aeropuertos españoles.

Para obtener los códigos de cualquier otro aeropuerto mundial, yo utilizo esta página (http://www.ogimet.com/indicativos.phtml), que además contiene otros datos muy interesantes acerca de la meteorología obtenida de aeródromos. Su página principal es esta (http://www.ogimet.com/).

Espero os sirva este código. ;)

Saludos a todos.

Edito : He corregido el código para que considere también temperaturas bajo cero (negativas), que no estaba correctamente contemplado.

ArdiIIa
06-05-2007, 14:37:30
Vaya. Un poco tarde...
Esto me hubiera venido de perlas antes del viernes santo... en evitación de rayos ..:D

Sin entrar a valorar el código, el proyecto en sí me parece bueno..

Casimiro Notevi
07-05-2007, 10:01:56
Estupendo, muy completito.