Tutorial 3 - Datos solares y climatológicos#

Este es un tutorial para utilizar las librerías:

  • pvlib para determinar ángulos solares y niveles de irradiación solar.

  • meteostat para determinar condiciones climáticas.

Para mayor información de las funciones de este tutorial, revisar la documentación oficial de pvlib y meteostat

Definir localización y tiempo de estudio#

Antes de cualquier estudio debemos definir la localización y tiempo de estudio.

Latitud, longitud y altitud del sitio#

Como sugerencia, recomendamos usar google earth. para determinar las coordenadas y altitud del sitio. Esta información se encuentra en la esquina inferior derecha. Otra alternativa es revisar las coordenadas en la dirección web del sitio.

Por ejemplo, consideramos las coordenadas del Edificio A del campus de Peñalolén de la Universidad Adolfo Ibañez.

Según esta información, el edificio se encuentre en las coordeandas 33.485° S, 70.518°O, y a una altura de 890.867 m

# Definimos latitud y longitud del lugar
lat, lon = -33.485, -70.518

# Altitud (en metros)
alt = 890.86619233

Zonas horaria#

Para identificar la zona horaria podemos usar la función pytz.country_timezones.

Nota La librería pytz viene incluída dentro del paquete de instalación de pvlib y, por lo tanto, no requiere instalación.

import pytz

pytz.country_timezones('CL')
['America/Santiago', 'America/Punta_Arenas', 'Pacific/Easter']

En Chile, la zona horaria es America/Santiago en casi todo el territorio, excepto en Punta Arenas e Isla de Pascua.

tz_uai = 'America/Santiago'

La lista completa de zonas horarias se encuentra disponible en Wikipedia

Otra alternativa es usar la librería timezonefinder para identificar zonas horarias basadas en coordenadas de latitud y longitud.

from timezonefinder import TimezoneFinder

tz_uai = TimezoneFinder().timezone_at(lat=lat, lng=lon)

print('La zona horaria en la UAI es:', tz_uai)
La zona horaria en la UAI es: America/Santiago

Tiempo de estudio#

Una vez definida la ubicación, debemos definir el intervalo de tiempo para nuestro estudio. Las librerías pvlib y meteostat utilizan distintos formatos para definir el intervalo de tiempo. Sin embargo, algo común en ambas es la definición de la fecha de comienzo y termino en formato datetime.

En este tutorial, consideraremos el periodo comprendido entre el 21 y 22 de diciembre del 2022

from datetime import datetime

start_date = datetime(year = 2022, month = 12, day = 21, hour = 0, minute = 0)
end_date   = datetime(year = 2022, month = 12, day = 22, hour = 0, minute = 0)

print(start_date)
print(end_date)
2022-12-21 00:00:00
2022-12-22 00:00:00

La frecuencia entre este intervalo será en horas. Sin embargo, la definición de esto es particular para cada librería.

Estimación de ángulos solares e irradiación (pvlib)#

Inicializar localización y tiempo de estudio en pvlib#

Para inicializar la localización usamos la función pvlib.location.Location(). Esta función crea un objeto Location que utilizaremos después para determinar los ángulos solares e irradiación solar.

from pvlib.location import Location

loc_pvlib = Location(latitude  = lat, 
                     longitude = lon, 
                     tz        = tz_uai,
                     altitude  = alt)

Luego, debemos definir el intervalo de tiempo. Usamos la función data_range de pandas para generar un arreglo con las fechas para la zona horaria correspondiente.

import pandas as pd

time_study = pd.date_range(start = start_date, 
                           end   = end_date, 
                           freq  = 'H', 
                           tz    = tz_uai)
/tmp/ipykernel_15455/3236446658.py:3: FutureWarning: 'H' is deprecated and will be removed in a future version, please use 'h' instead.
  time_study = pd.date_range(start = start_date,

Para verificar, usamos print para imprimir cada elemento del arreglo times.

for i in range(len(time_study)):
    print(time_study[i])
2022-12-21 00:00:00-03:00
2022-12-21 01:00:00-03:00
2022-12-21 02:00:00-03:00
2022-12-21 03:00:00-03:00
2022-12-21 04:00:00-03:00
2022-12-21 05:00:00-03:00
2022-12-21 06:00:00-03:00
2022-12-21 07:00:00-03:00
2022-12-21 08:00:00-03:00
2022-12-21 09:00:00-03:00
2022-12-21 10:00:00-03:00
2022-12-21 11:00:00-03:00
2022-12-21 12:00:00-03:00
2022-12-21 13:00:00-03:00
2022-12-21 14:00:00-03:00
2022-12-21 15:00:00-03:00
2022-12-21 16:00:00-03:00
2022-12-21 17:00:00-03:00
2022-12-21 18:00:00-03:00
2022-12-21 19:00:00-03:00
2022-12-21 20:00:00-03:00
2022-12-21 21:00:00-03:00
2022-12-21 22:00:00-03:00
2022-12-21 23:00:00-03:00
2022-12-22 00:00:00-03:00

Estimar ángulos solares (get_solarposition)#

Para acceder a los ángulos solares usamos la función get_solarposition del objeto loc_pvlib. Esta función crea un dataframe con los ángulos solares

sol_pos = loc_pvlib.get_solarposition(times = time_study)
sol_pos.head()
apparent_zenith zenith apparent_elevation elevation azimuth equation_of_time
2022-12-21 00:00:00-03:00 118.310953 118.310953 -28.310953 -28.310953 206.108725 2.160758
2022-12-21 01:00:00-03:00 122.292222 122.292222 -32.292222 -32.292222 190.845847 2.140015
2022-12-21 02:00:00-03:00 122.881072 122.881072 -32.881072 -32.881072 174.524133 2.119271
2022-12-21 03:00:00-03:00 119.976535 119.976535 -29.976535 -29.976535 158.754981 2.098524
2022-12-21 04:00:00-03:00 114.043325 114.043325 -24.043325 -24.043325 144.812625 2.077775

En este curso, solo usaremos:

  • 'apperent_zenith': ángulo cenital solar aparente (con corrección por el índice de refracción)

  • 'apperent_elevation': ángulo de elevación solar aparente (con corrección por el índice de refracción)

  • 'azimuth': ángulo acimutal solar

import matplotlib.pyplot as plt
import matplotlib.dates as mdates

fig, ax = plt.subplots()
ax.plot(time_study, sol_pos['apparent_zenith'],'o:r', label=r'Zenith ($\theta_s$)')
ax.plot(time_study, sol_pos['azimuth'],'o:b', label=r'Azimuth ($\phi_s$)')

ax.set_xlabel('tiempo (horas)')
ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M', tz = tz_uai))
ax.set_ylabel('Ángulo (grados)')
plt.legend()
plt.show()
../../_images/80120bf042771307c8c4f87d93fde299a5aa8f338ddaff55d78fab672a22ce8b.png

Estimar irradiación solar (get_clearsky)#

Para acceder a la irradiación solar usamos la función get_clearsky del objeto loc_pvlib. Esta función crea un dataframe con los niveles de irradiación horizontal global (ghi), normal directa (dni) y horizontal difusa (dhi), calculados en base al modelo de Ineichen y Perez (2022).`

sol_irr = loc_pvlib.get_clearsky(times = time_study)
sol_irr.head()
ghi dni dhi
2022-12-21 00:00:00-03:00 0.0 0.0 0.0
2022-12-21 01:00:00-03:00 0.0 0.0 0.0
2022-12-21 02:00:00-03:00 0.0 0.0 0.0
2022-12-21 03:00:00-03:00 0.0 0.0 0.0
2022-12-21 04:00:00-03:00 0.0 0.0 0.0
fig, ax = plt.subplots()
ax.plot(time_study, sol_irr['ghi'],'o:r', label=r'GHI')
ax.plot(time_study, sol_irr['dni'],'o:b', label=r'DNI')
ax.plot(time_study, sol_irr['dhi'],'o:g', label=r'DHI')

ax.set_xlabel('tiempo (horas)')
ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M', tz = tz_uai))
ax.set_ylabel('Irradiación solar ($\mathrm{W/m^2}$)')
plt.legend()
plt.show()
../../_images/140e50b3f2fcbefa6570251032c193cb2d1115359e7e5252fc43b0fdaf5564c8.png

Estimación de condiciones ambientales (meteostat)#

Inicializar localización y tiempo de estudio en meteostat#

Lo primero que debemos hacer es inicializar la localización usando la función meteostat.Point(). Esta función crea un objeto que generará la información meteorologica a través de la interpolación de datos de estaciones meterológicas cercanas.

import meteostat

loc_meteo = meteostat.Point(lat=lat, 
                            lon=lon, 
                            alt= alt)

Luego, para extraer los datos horarios, utilizamos la función meteostat.Hourly indicando la ubicación del objeto Point, el inicio (start), el término (end) y la zona horaria (timezone) del periodo donde queremos extraer los datos.

La función entregará un objeto, el cual podemos convertir a un dataframe usando .fetch()

from meteostat import Hourly

# Creamos un objeto con las condiciones climáticas
meteo_data = Hourly(loc      = loc_meteo,   # localización
                    start    = start_date,  # inicio
                    end      = end_date,    # término
                    timezone = tz_uai)      # zona horaria

# convertimos a dataframe
meteo_data = meteo_data.fetch() 
FutureWarning: Support for nested sequences for 'parse_dates' in pd.read_csv is deprecated. Combine the desired columns with pd.to_datetime after parsing instead.
FutureWarning: 'H' is deprecated and will be removed in a future version, please use 'h' instead.

De este dataframe identificamos:

  • temp: Temperatura ambiente (°C)

  • dwpt: Temperatura de punto de rocío (°C)

  • rhum: Humedad relativa (%)

  • prcp: Precipitación total en una hora (mm)

  • snow: Nieve acumulada (mm)

  • wdir: Dirección del viento (°)

  • wspd: Velocidad promedio del viento (km/h)

  • pres: Presión atmosférica (hPa)

meteo_data['temp']
time
2022-12-21 00:00:00-03:00    16.1
2022-12-21 01:00:00-03:00    16.1
2022-12-21 02:00:00-03:00    15.4
2022-12-21 03:00:00-03:00    14.4
2022-12-21 04:00:00-03:00    15.0
2022-12-21 05:00:00-03:00    14.7
2022-12-21 06:00:00-03:00    14.5
2022-12-21 07:00:00-03:00    13.9
2022-12-21 08:00:00-03:00    13.5
2022-12-21 09:00:00-03:00    18.5
2022-12-21 10:00:00-03:00    20.5
2022-12-21 11:00:00-03:00    22.5
2022-12-21 12:00:00-03:00    25.5
2022-12-21 13:00:00-03:00    26.5
2022-12-21 14:00:00-03:00    29.5
2022-12-21 15:00:00-03:00    29.5
2022-12-21 16:00:00-03:00    30.5
2022-12-21 17:00:00-03:00    29.5
2022-12-21 18:00:00-03:00    28.5
2022-12-21 19:00:00-03:00    26.5
2022-12-21 20:00:00-03:00    24.5
2022-12-21 21:00:00-03:00    21.5
2022-12-21 22:00:00-03:00    17.1
2022-12-21 23:00:00-03:00    16.4
2022-12-22 00:00:00-03:00    15.4
Freq: h, Name: temp, dtype: float64
fig, ax = plt.subplots()
ax.plot(time_study, meteo_data['temp'],'o:r')

ax.set_xlabel('tiempo (horas)')
ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M', tz = tz_uai))
ax.set_ylabel('Temperatura (°C)')
ax.set_title('Temperatura ambiente (lat, lon = %.1f°, %.1f°)' % (lat, lon))
plt.show()
../../_images/c1c5cff33beec4f0e6a130169762a0aafd776cb40da27ec2180f5a25b37728aa.png