TEMPO

Cómo Funciona TEMPO y Resolución Temporal

TEMPO utiliza espectroscopía UV-visible para medir gases desde el espacio. En esta lección entenderemos el principio básico y cómo aprovechar la ventaja horaria.

Principio: Espectroscopía de Absorción

Los gases absorben luz en longitudes de onda específicas, como "huellas dactilares" únicas.

Concepto básico:

  1. Sol emite luz de todos los colores
  2. Gases en atmósfera absorben colores específicos
  3. TEMPO mide qué colores faltan
  4. Calcula cuánto gas hay

Huellas Espectrales

Cada gas absorbe luz en rangos diferentes:

GasLongitud de ondaColorPor qué importa
NO₂400-450 nmAzul-violetaAbsorción fuerte, fácil detectar
O₃255 nm (UV) + 600 nm (naranja)UV + NaranjaDos bandas permiten separar troposfera/estratosfera
HCHO340 nmUV-AMás débil, requiere procesamiento

Esto explica por qué TEMPO opera en rango UV-Visible (290-740 nm): los gases de interés absorben luz ahí.

Ley de Beer-Lambert (Simplificada)

La base matemática:

I=I0eσnLI = I_0 \cdot e^{-\sigma \cdot n \cdot L}

En palabras simples:

  • Más gas = menos luz transmitida
  • TEMPO mide la luz que falta
  • Calcula concentración del gas
Columna Vertical

TEMPO mide la columna vertical total de gas (superficie → espacio), no concentración a nivel del suelo.

Unidades: moléculas/cm² (columna completa)

De Luz a Datos: El Pipeline

NASA hace el procesamiento complejo por ti. Entender el pipeline te ayuda a usar los datos correctamente.

Niveles de Productos

Para desarrolladores:

NivelQué contiene¿Usar en tu app?
L0/L1ADatos crudos❌ No
L1BRadiancias calibradas❌ No (muy técnico)
L2Concentraciones de gasesSÍ - USA ESTE
L3Grillas diarias/mensuales✅ Sí (para análisis histórico)
No Necesitas Implementar Procesamiento

NASA proporciona productos L2 listos para usar. Como desarrollador, trabajas directamente con:

  • Columnas de NO₂ (molec/cm²)
  • Columnas de O₃ (DU)
  • Columnas de HCHO (molec/cm²)

No necesitas implementar algoritmos de espectroscopía.

Control de Calidad

Los productos L2 incluyen banderas de calidad (quality flags).

Quality Flags

1interface TempoPixel {
2  no2_column: number;
3  cloud_fraction: number;
4  quality_flag: number; // 0 = alta, 1 = media, 2 = baja
5}
6
7function shouldUseData(pixel: TempoPixel): boolean {
8  // Filtrar baja calidad
9  if (pixel.quality_flag > 1) {
10    return false; // Descarta
11  }
12
13  // Filtrar alta cobertura de nubes
14  if (pixel.cloud_fraction > 0.7) {
15    return false; // Las nubes bloquean la vista
16  }
17
18  return true; // OK para usar
19}
20

En tu app: Siempre filtra datos con quality_flag > 1 para evitar valores erróneos.

Precisión de TEMPO

Incertidumbres Esperadas

ProductoPrecisión (píxel individual)Precisión (promedio espacial)
NO₂ troposférico~0.5 × 10¹⁵ molec/cm²~0.3 × 10¹⁵ molec/cm²
O₃ total~3%~1-2%
O₃ troposférico~20%~10%
HCHO~1 × 10¹⁶ molec/cm²~0.5 × 10¹⁶ molec/cm²

Tip: Promediar múltiples píxeles mejora la precisión.

Resolución Temporal: La Ventaja de TEMPO

TEMPO observa cada hora desde aproximadamente 8 AM hasta 10 PM hora local.

Cobertura Temporal por Ubicación

UbicaciónPrimera ObsÚltima ObsObs/Día
New York (EST)08:0022:0014
Los Angeles (PST)07:0021:0014
Ciudad de México08:3022:3014

Capturando el Ciclo Diurno

La variación hora por hora revela patrones importantes.

Ciclo Típico de NO₂ en Ciudad

1def simulate_no2_diurnal_cycle(hour_local):
2    """
3    Ciclo diurno típico de NO₂ en ciudad
4    Retorna: Columna NO₂ en 10¹⁵ molec/cm²
5    """
6    # Background base
7    background = 2.0
8
9    # Pico matutino (7-9 AM)
10    if 7 <= hour_local <= 9:
11        morning_peak = 6.0
12    else:
13        morning_peak = 0
14
15    # Pico vespertino (5-7 PM)
16    if 17 <= hour_local <= 19:
17        evening_peak = 7.0
18    else:
19        evening_peak = 0
20
21    # Mínimo diurno (mezcla vertical)
22    if 12 <= hour_local <= 15:
23        mixing_reduction = -1.5
24    else:
25        mixing_reduction = 0
26
27    return max(0.5, background + morning_peak + evening_peak + mixing_reduction)
28
29# Simular día completo
30for hour in range(8, 23):
31    no2 = simulate_no2_diurnal_cycle(hour)
32    print(f"{hour:02d}:00 - NO₂: {no2:.2f} × 10¹⁵ molec/cm²")
33

Output típico:

  • 08:00 - NO₂: 8.0 (pico AM) 🔴
  • 12:00 - NO₂: 0.5 (mínimo) 🟢
  • 18:00 - NO₂: 9.0 (pico PM) 🔴
  • 22:00 - NO₂: 2.0 (descenso) 🟡

Ciclo Típico de O₃

El ozono muestra un patrón diferente:

  • Mañana (8-12h): O₃ bajo, formación comienza
  • Tarde (12-18h): O₃ alcanza pico máximo
  • Noche: O₃ desciende (sin luz solar)
Uso en Tu App

Comprender ciclos diurnos permite:

  • Timing de alertas: "O₃ alcanzará nivel insalubre en 2 horas"
  • 🚗 Política de transporte: Reducir tráfico en horas críticas
  • 📊 Validación: Verificar si modelos capturan variación horaria

Detección de Eventos

La resolución horaria permite detectar y rastrear eventos de contaminación.

Tipos de Eventos Detectables

1. Incendios Forestales

  • Plumas de humo detectables por aumento de HCHO
  • Seguimiento hora por hora de movimiento
  • Predicción de llegada a ciudades

2. Episodios de Ozono

  • Formación matutina visible
  • Pico vespertino cuantificado
  • Predicción 2-4h adelante

3. Inversiones Térmicas

  • Acumulación nocturna
  • Ruptura matinal observable
  • Patrón vertical capturado

Ejemplo: Tracking Simple de Pluma

1interface PlumeObservation {
2  timestamp: Date;
3  centroid_lat: number;
4  centroid_lon: number;
5  hcho_column: number;
6}
7
8function trackPlumeMovement(observations: PlumeObservation[]) {
9  if (observations.length < 2) return null;
10
11  const first = observations[0];
12  const last = observations[observations.length - 1];
13
14  // Distancia simple (aproximación)
15  const lat_diff = last.centroid_lat - first.centroid_lat;
16  const lon_diff = last.centroid_lon - first.centroid_lon;
17  const distance_km = Math.sqrt(lat_diff**2 + lon_diff**2) * 111;
18
19  // Tiempo transcurrido
20  const hours = (last.timestamp.getTime() - first.timestamp.getTime()) / (1000 * 60 * 60);
21
22  return {
23    velocity_kmh: distance_km / hours,
24    direction: lon_diff > 0 ? 'Este' : 'Oeste',
25    distance_traveled: distance_km,
26    hours_elapsed: hours
27  };
28}
29
30// Ejemplo
31const observations = [
32  { timestamp: new Date('2025-10-02T14:00'), centroid_lat: 19.5, centroid_lon: -99.1, hcho_column: 3e16 },
33  { timestamp: new Date('2025-10-02T16:00'), centroid_lat: 19.6, centroid_lon: -98.9, hcho_column: 2.5e16 }
34];
35
36const movement = trackPlumeMovement(observations);
37console.log(`Pluma se mueve a ${movement.velocity_kmh} km/h hacia el ${movement.direction}`);
38
Cuándo Usar Este Análisis

Tracking de plumas es útil para:

  • 🔥 Incendios forestales (alertar ciudades en trayectoria)
  • 🏭 Releases industriales accidentales
  • 🌋 Erupciones volcánicas

Para monitoreo urbano simple, no necesitas este nivel de complejidad.

Conexión con el Challenge de NASA

La resolución horaria es tu ventaja competitiva:

Casos de Uso Prácticos

1. Dashboard en Tiempo Real

1// Actualizar cada hora automáticamente
2setInterval(async () => {
3  const latestData = await fetchTEMPOLatest();
4  updateDashboard(latestData);
5}, 3600000); // 1 hora
6

2. Alertas Inteligentes

1function predictNextHour(last6hours: HourlyData[]): string {
2  const recent_no2 = last6hours.slice(-3).map(h => h.no2);
3  const trend = (recent_no2[2] - recent_no2[0]) / 2;
4
5  if (trend > 2e15) {
6    return "⚠️ NO₂ subiendo rápido - tráfico aumentando";
7  } else if (trend < -2e15) {
8    return "✅ NO₂ bajando - calidad mejorando";
9  }
10  return "➡️ NO₂ estable";
11}
12

3. Comparaciones Temporales

  • Hoy vs ayer a la misma hora
  • Día de semana vs fin de semana
  • Antes/después de políticas ("Hoy No Circula")

4. Visualizaciones Efectivas

  • Gráficos de línea mostrando últimas 12 horas
  • Animaciones de evolución horaria
  • Mapas de calor temporales

Ejemplo Simple para Implementar

1interface HourlyTrend {
2  hour: number;
3  no2: number;
4  o3: number;
5  trend: 'rising' | 'falling' | 'stable';
6}
7
8function analyzeTrend(data: HourlyTrend[]): string {
9  const last3hours = data.slice(-3);
10
11  const no2_trend = last3hours[2].no2 - last3hours[0].no2;
12
13  if (no2_trend > 3e15) {
14    return "🔴 NO₂ aumentando rápidamente - posible evento de tráfico o industrial";
15  } else if (no2_trend < -3e15) {
16    return "🟢 NO₂ disminuyendo - condiciones mejorando";
17  }
18
19  return "🟡 Condiciones estables";
20}
21

No necesitas ML complejo - tendencias simples son muy efectivas.

Próximos Pasos

En la siguiente lección discutiremos las limitaciones de TEMPO: qué no puede medir, cuándo no hay datos, y cómo diseñar una arquitectura robusta que combine múltiples fuentes.