Guía de clase (Google Colab): notebook para calcular y graficar ηd y ηp durante un día de secado

Objetivos

  1. Replicar el caso del Apéndice 7 y extenderlo a serie horaria.
  2. Generar datos horarios plausibles (insolación, T, HR, caudal) a partir de prompts sugeridos.
  3. Calcular y graficar eficiencias del sistema (ηd) y de captación (ηp) por hora y acumuladas.

Estructura del notebook

  1. Portada y objetivos.
  2. Parámetros base del Apéndice 7.
  3. Utilidades psicrométricas y energéticas.
  4. Generación de perfiles horarios (con prompts).
  5. Cálculo horario de ηd y ηp.
  6. Gráficas y análisis.
  7. Sensibilidades rápidas.
  8. Conclusiones.

1) Portada (Markdown)

# Secado solar — Eficiencias horarias (ηd, ηp)
Caso base: Apéndice 7 de *Solar Dryers*. Extensión a perfil horario en un día.

2) Parámetros base (código, bien documentado)

# Parámetros “macro” del caso
Mi_kg   = 100.0     # masa inicial
wi_bh   = 0.80      # humedad inicial base húmeda
wf_bh   = 0.05      # humedad final base húmeda
A_m2    = 15.0      # área del colector
dias    = 3.0       # duración del secado (Apéndice 7)
Lv_funC = lambda T: 2501.0 - 2.361*T   # kJ/kg (aprox) en función de T (°C)

# Cálculo del agua total a evaporar (W_total)
Md_kg = Mi_kg*(1-wi_bh)                     # masa seca
Mf_kg = Md_kg/(1-wf_bh)                     # masa final
W_total_kg = Mi_kg - Mf_kg                  # agua a remover total
W_total_kg

3) Utilidades psicrométricas (código y explicación)

import math
import numpy as np
import pandas as pd

def esat_Pa(T_C):
    """Presión de vapor de saturación (Pa). Fórmula tipo Tetens/Magnus, 0–50 °C."""
    return 0.61078 * math.exp((17.2694*T_C)/(T_C+237.3)) * 1000.0

def omega(Pv_Pa, P_atm_Pa=101325.0):
    """Razón de humedad ω = kg_vapor/kg_aire_seco."""
    return 0.62198 * Pv_Pa / max(P_atm_Pa - Pv_Pa, 1e-6)

def omega_from_T_RH(T_C, RH_frac, P_atm_Pa=101325.0):
    """ω a partir de T y HR."""
    return omega(RH_frac*esat_Pa(T_C), P_atm_Pa)

4) Generación de perfiles horarios

4.1 Prompts sugeridos (péguense en el chatbot dentro de Colab o Codespaces)

Prompt A — Insolación y horario solar efectivo

Genera una serie horaria para un día despejado de 6:00 a 18:00 con paso 1 h de irradiación global en el plano del colector [MJ/m²·h], con forma campana (máximo al mediodía) y suma aproximada 20 MJ/m²·día. Devuélvelo como lista de 13 valores desde la hora 6 a 18.

Prompt B — Temperatura y HR ambiente

Propón perfiles horarios plausibles de temperatura ambiente [°C] y humedad relativa [%] de 6:00 a 18:00 en clima cálido-húmedo, con T subiendo 26→34 °C y HR bajando 85→60 %. Entrega dos listas sincronizadas de 13 valores.

Prompt C — Temperatura de secado y caudal

Considerando un colector solar, fija T_aire_secado [°C] ~ T_amb + 8 °C con tope 45 °C y un caudal constante V=0.5 m³/s. Devuelve la lista de T_secado de 6:00 a 18:00.

4.2 Cargar o simular datos (si no usan prompts)

# Rango horario: 6 a 18 (13 puntos)
horas = np.arange(6, 19)
n = len(horas)

# Insolación horaria [MJ/m2·h] con forma aproximada
I_h = np.array([0.3, 0.8, 1.3, 1.8, 2.2, 2.6, 2.8, 2.6, 2.2, 1.6, 1.0, 0.6, 0.2])
I_day_total = I_h.sum()  # ≈ 20 MJ/m2·día

# Temperatura ambiente y HR propuestas
T_amb = np.array([26,27,28,29,30,31,32,33,34,34,33,31,29], dtype=float)
HR    = np.array([85,83,80,78,75,72,70,68,66,64,63,62,60], dtype=float)/100.0

# Temperatura de secado (ambiente + 8 °C, tope 45 °C)
T_sec = np.minimum(T_amb + 8.0, 45.0)

# Otros parámetros
V_m3s   = 0.5        # caudal
rho_air = 1.28       # kg/m3
P_atm   = 101325.0   # Pa
dt_s    = 3600.0     # 1 hora

5) Cálculo horario de eficiencias

5.1 Balance de masa de vapor por hora y “pick-up”

Idea: el aire recoge humedad hasta un máximo teórico. Tomamos:

  • ω_in(h) desde T_amb, HR(h).
  • ω_sat(h) a T_sec(h).
  • Suponemos que el aire sale con ω_out = min(ω_in + Δω_capacidad, ω_sat).
  • Δω_real = ω_out − ω_in.
  • Masa aire seco en 1 h: m_da = ρ * V * Δt.
  • Agua evaporada hora h: dW(h) = m_da * Δω_real.
# Razones de humedad
w_in  = np.array([omega_from_T_RH(T_amb[i], HR[i], P_atm) for i in range(n)])
w_sat = np.array([omega(esat_Pa(T_sec[i]), P_atm)         for i in range(n)])

# Capacidad teórica por hora: m_da * (w_sat - w_in)
m_da_h = rho_air * V_m3s * dt_s * np.ones(n)  # kg aire ~ aire seco (aprox)
cap_teor_h = m_da_h * np.maximum(w_sat - w_in, 0.0)

# Evaporación real por hora: aquí dos opciones
# Opción 1: Limitada por capacidad del aire (psicrométrica)
dW_psic_h = cap_teor_h.copy()

# Opción 2: Proporcional a la energía solar de la hora (distribución por insolación)
E_req_total_MJ = Lv_funC(T_sec.mean()) * W_total_kg / 1000.0
frac_I = I_h / I_h.sum()
dW_ener_h = frac_I * W_total_kg

# Selección del método base para ηp: psicrométrico
dW_h = dW_psic_h.copy()

# Para no exceder W_total_kg en un día, se puede escalar:
scale = min(1.0, W_total_kg / dW_h.sum()) if dW_h.sum() > 0 else 1.0
dW_h *= scale

W_dia = dW_h.sum()
W_dia

5.2 Eficiencia de captación por hora y acumulada

Definición (hora a hora): [ _{p,h} = ] Acumulada de 6:00→t: [ _{p,acum}(t) = ]

den_p_h = m_da_h * np.maximum(w_sat - w_in, 1e-12)
eta_p_h = dW_h / den_p_h
eta_p_h = np.clip(eta_p_h, 0.0, 1.0)

eta_p_acum = np.cumsum(dW_h) / np.cumsum(den_p_h)

5.3 Eficiencia del sistema por hora y acumulada

Hora h: [ _{d,h} = ] Acumulada: [ _{d,acum}(t) = ]

Lv_h_kJkg = np.array([Lv_funC(T_sec[i]) for i in range(n)])
E_evap_h_MJ = dW_h * Lv_h_kJkg / 1000.0          # MJ
E_solar_h_MJ = I_h * A_m2                        # MJ
eta_d_h = np.divide(E_evap_h_MJ, E_solar_h_MJ, out=np.zeros(n), where=E_solar_h_MJ>0)

eta_d_acum = np.cumsum(E_evap_h_MJ) / np.maximum(np.cumsum(E_solar_h_MJ), 1e-12)

6) Tablas y gráficas

import matplotlib.pyplot as plt

df = pd.DataFrame({
    "hora": horas,
    "I_h_MJm2h": I_h,
    "T_amb_C": T_amb,
    "HR_frac": HR,
    "T_sec_C": T_sec,
    "w_in": w_in,
    "w_sat": w_sat,
    "m_da_kg": m_da_h,
    "dW_h_kg": dW_h,
    "eta_p_h": eta_p_h,
    "eta_p_acum": eta_p_acum,
    "eta_d_h": eta_d_h,
    "eta_d_acum": eta_d_acum
})
df.round(4)
# Graficar eficiencias horarias
plt.figure()
plt.plot(horas, eta_d_h, marker='o', label='ηd hora')
plt.plot(horas, eta_p_h, marker='s', label='ηp hora')
plt.xlabel("Hora del día")
plt.ylabel("Eficiencia [-]")
plt.title("Eficiencias horarias")
plt.legend()
plt.grid(True)
plt.show()

# Graficar eficiencias acumuladas
plt.figure()
plt.plot(horas, eta_d_acum, marker='o', label='ηd acumulada')
plt.plot(horas, eta_p_acum, marker='s', label='ηp acumulada')
plt.xlabel("Hora del día")
plt.ylabel("Eficiencia acumulada [-]")
plt.title("Eficiencias acumuladas")
plt.legend()
plt.grid(True)
plt.show()

7) Sensibilidades rápidas

  • Cambiar V_m3s (caudal) y observar efecto sobre ηp.
  • Limitar ω_out estrictamente a ω_sat y comparar.
  • Sustituir dW_h = dW_ener_h para ver ηd cuando la evaporación sigue a la radiación.
  • Variar T_sec y revisar cambio en Lv y ηd.

Ejemplo de conmutador de método:

# Cambiar entre psicrométrico y energético
use_psic = True
dW_h = (dW_psic_h if use_psic else dW_ener_h) * scale

8) Conclusiones (Markdown)

  • Reportar ηd_acum al final del día y compararla con 20.4 % del Apéndice 7.
  • Reportar ηp_acum y compararla con 20.7 %.
  • Discutir discrepancias por supuestos horarios de I_h, T, HR y por el método de reparto de dW.

Checklist de trabajo en clase

  1. Abrir Google Colab y crear un nuevo notebook.
  2. Pegar secciones 1–8 en celdas separadas.
  3. Ejecutar y verificar que las tablas y gráficas se generen.
  4. Usar los prompts A–C para reemplazar las series simuladas por series generadas y re-ejecutar.
  5. Guardar en Drive y exportar a PDF para entrega.

(Opcional) Versión Codespaces + Streamlit

  • Copiar funciones y lógica a app.py.
  • Entradas con sliders para V, T, HR e irradiación.
  • Mostrar ηd_h, ηp_h y sus acumuladas en tiempo real.
  • Desplegar en Streamlit Community Cloud.