From b533c6dc9031166aa0f0a8f9088a601e817c6078 Mon Sep 17 00:00:00 2001 From: Mark Campanelli Date: Tue, 16 Jan 2024 08:22:51 -0700 Subject: [PATCH] Switch away from using dataclass --- pvfit/measurement/iv/types.py | 122 +++++++++++++++--- .../model/simple/goodness_of_fit.py | 66 ++++++++++ .../model/simple/inference_matrix.py | 7 +- .../model/simple/inference_spec_sheet.py | 6 +- 4 files changed, 181 insertions(+), 20 deletions(-) create mode 100644 pvfit/modeling/dc/single_diode/model/simple/goodness_of_fit.py diff --git a/pvfit/measurement/iv/types.py b/pvfit/measurement/iv/types.py index 789e122..55b6063 100644 --- a/pvfit/measurement/iv/types.py +++ b/pvfit/measurement/iv/types.py @@ -4,14 +4,13 @@ Copyright 2023 Intelligent Measurement Systems LLC """ -from dataclasses import dataclass from typing import TypedDict import numpy from scipy.constants import convert_temperature from pvfit.common import T_degC_abs_zero -from pvfit.modeling.dc.common import G_hemi_W_per_m2_stc, Material, T_degC_stc +from pvfit.modeling.dc.common import Material from pvfit.types import FloatArray, FloatBroadcastable, FloatVector @@ -182,9 +181,9 @@ def __init__( T_degC Cell temperatures [°C] G_W_per_m2_0 - Reference plane of array irradiance, defaults to STC [W/m^2] + Reference plane of array irradiance [W/m^2] T_degC_0 - Reference cell temperatures, defaults to STC [°C] + Reference cell temperatures [°C] """ if ( len(I_sc_A) @@ -311,24 +310,115 @@ def ivft_data(self) -> IVFTData: return IVFTData(I_A=I_A, V_V=V_V, F=F, T_degC=T_degC) -@dataclass class SpecSheetParameters: """ Performance parameters at specified reference conditions, typically found on the specification datasheet of a photovoltaic module. """ - material: Material - N_s: int - I_sc_A_0: float - I_mp_A_0: float - V_mp_V_0: float - V_oc_V_0: float - dI_sc_dT_A_per_degC_0: float - dP_mp_dT_W_per_degC_0: float - dV_oc_dT_V_per_degC_0: float - G_W_per_m2_0: float - T_degC_0: float + def __init__( + self, + *, + material: Material, + N_s: int, + I_sc_A_0: float, + I_mp_A_0: float, + V_mp_V_0: float, + V_oc_V_0: float, + dI_sc_dT_A_per_degC_0: float, + dP_mp_dT_W_per_degC_0: float, + dV_oc_dT_V_per_degC_0: float, + G_W_per_m2_0: float, + T_degC_0: float, + ) -> None: + """ + Parameters + ---------- + material + material of PV device + N_s + number of cells in series in each parallel string + I_sc_A_0 + Current at short-circuit at reference condition [A] + I_mp_A_0 + Current at maximum power at reference condition [A] + V_mp_V_0 + Voltage at maximum power at reference condition [V] + V_oc_V_0 + Voltage at open-circuit at reference condition [V] + dI_sc_dT_A_per_degC_0 + Derivative of current at short-circuit with respect to temperature at + reference condition [A/°C] + dP_mp_dT_W_per_degC_0 + Derivative of maximum power with respect to temperature at reference + condition [W/°C] + dV_oc_dT_V_per_degC_0 + Derivative of voltage at open-circuit with respect to temperature at + reference condition [V/°C] + G_W_per_m2_0 + Reference plane of array irradiance, defaults to STC [W/m^2] + T_degC_0 + Reference cell temperatures, defaults to STC [°C] + """ + self._material = material + self._N_s = N_s + self._I_sc_A_0 = I_sc_A_0 + self._I_mp_A_0 = I_mp_A_0 + self._V_mp_V_0 = V_mp_V_0 + self._V_oc_V_0 = V_oc_V_0 + self._dI_sc_dT_A_per_degC_0 = dI_sc_dT_A_per_degC_0 + self._dP_mp_dT_W_per_degC_0 = dP_mp_dT_W_per_degC_0 + self._dV_oc_dT_V_per_degC_0 = dV_oc_dT_V_per_degC_0 + self._G_W_per_m2_0 = G_W_per_m2_0 + self._T_degC_0 = T_degC_0 + + @property + def material(self) -> Material: + return self._material + + @property + def N_s(self) -> int: + return self._N_s + + @property + def I_sc_A_0(self) -> float: + return self._I_sc_A_0 + + @property + def I_mp_A_0(self) -> float: + return self._I_mp_A_0 + + @property + def V_mp_V_0(self) -> float: + return self._V_mp_V_0 + + @property + def V_oc_V_0(self) -> float: + return self._V_oc_V_0 + + @property + def dI_sc_dT_A_per_degC_0(self) -> float: + return self._dI_sc_dT_A_per_degC_0 + + @property + def dP_mp_dT_W_per_degC_0(self) -> float: + return self._dP_mp_dT_W_per_degC_0 + + @property + def dV_oc_dT_V_per_degC_0(self) -> float: + return self._dV_oc_dT_V_per_degC_0 + + @property + def G_W_per_m2_0(self) -> float: + return self._G_W_per_m2_0 + + @property + def T_degC_0(self) -> float: + return self._T_degC_0 + + @property + def T_K_0(self) -> float: + return convert_temperature(self._T_degC_0, "Celsius", "Kelvin") @property def P_mp_W_0(self) -> float: diff --git a/pvfit/modeling/dc/single_diode/model/simple/goodness_of_fit.py b/pvfit/modeling/dc/single_diode/model/simple/goodness_of_fit.py new file mode 100644 index 0000000..9edb438 --- /dev/null +++ b/pvfit/modeling/dc/single_diode/model/simple/goodness_of_fit.py @@ -0,0 +1,66 @@ +""" +PVfit: Goodness-of-fit metrics for simple single-diode model (SDM). + +Copyright 2023 Intelligent Measurement Systems LLC +""" + +from typing import Tuple + +import numpy + +from pvfit.measurement.iv.types import ( + FTData, + IVCurveParametersArray, + IVPerformanceMatrix, +) +import pvfit.modeling.dc.single_diode.equation.simulation as sde_sim +import pvfit.modeling.dc.single_diode.model.simple.auxiliary_equations as ae +import pvfit.modeling.dc.single_diode.model.simple.types as types + + +def compute_matrix_mape_mbpe( + iv_performance_matrix: IVPerformanceMatrix, model_parameters: types.ModelParameters +) -> Tuple[dict, IVCurveParametersArray]: + """Compute""" + + iv_curve_parameters = sde_sim.iv_curve_parameters( + model_parameters=ae.compute_sde_model_parameters( + ft_data=FTData( + F=iv_performance_matrix.F, T_degC=iv_performance_matrix.T_degC + ), + model_parameters=model_parameters, + ) + ) + + I_sc_pc_error = 100 * ( + iv_curve_parameters["I_sc_A"] / iv_performance_matrix.I_sc_A - 1 + ) + I_mp_pc_error = 100 * ( + iv_curve_parameters["I_mp_A"] / iv_performance_matrix.I_mp_A - 1 + ) + P_mp_pc_error = 100 * ( + iv_curve_parameters["P_mp_W"] / iv_performance_matrix.P_mp_W - 1 + ) + V_mp_pc_error = 100 * ( + iv_curve_parameters["V_mp_V"] / iv_performance_matrix.V_mp_V - 1 + ) + V_oc_pc_error = 100 * ( + iv_curve_parameters["V_oc_V"] / iv_performance_matrix.V_oc_V - 1 + ) + + return { + "mape": { + "I_sc_A": numpy.mean(numpy.abs(I_sc_pc_error)), + "I_mp_A": numpy.mean(numpy.abs(I_mp_pc_error)), + "P_mp_W": numpy.mean(numpy.abs(P_mp_pc_error)), + "V_mp_V": numpy.mean(numpy.abs(V_mp_pc_error)), + "V_oc_V": numpy.mean(numpy.abs(V_oc_pc_error)), + }, + "mbpe": { + "I_sc_A": numpy.mean(I_sc_pc_error), + "I_mp_A": numpy.mean(I_mp_pc_error), + "P_mp_W": numpy.mean(P_mp_pc_error), + "V_mp_V": numpy.mean(V_mp_pc_error), + "V_oc_V": numpy.mean(V_oc_pc_error), + }, + }, iv_curve_parameters diff --git a/pvfit/modeling/dc/single_diode/model/simple/inference_matrix.py b/pvfit/modeling/dc/single_diode/model/simple/inference_matrix.py index 6b9fdb4..d4c357f 100644 --- a/pvfit/modeling/dc/single_diode/model/simple/inference_matrix.py +++ b/pvfit/modeling/dc/single_diode/model/simple/inference_matrix.py @@ -1,8 +1,11 @@ """ -Calibrate single-diode model (SDM) from IEC 61853-1 matrix data (or similar) using -orthogonal distance regression (ODR). +PVfit: Calibrate simple single-diode model (SDM) from IEC 61853-1 matrix data (or +similar) using orthogonal distance regression (ODR). + +Copyright 2023 Intelligent Measurement Systems LLC """ + from typing import Optional, Tuple, TypedDict import warnings diff --git a/pvfit/modeling/dc/single_diode/model/simple/inference_spec_sheet.py b/pvfit/modeling/dc/single_diode/model/simple/inference_spec_sheet.py index f0c05e1..31d9aef 100644 --- a/pvfit/modeling/dc/single_diode/model/simple/inference_spec_sheet.py +++ b/pvfit/modeling/dc/single_diode/model/simple/inference_spec_sheet.py @@ -1,6 +1,8 @@ """ -Calibrate single-diode model (SDM) using nonlinear least squares (NLLS) and information -from photovoltaic device's specification datasheet (spec sheet). +Calibrate simple single-diode model (SDM) using nonlinear least squares (NLLS) and +information from photovoltaic device's specification datasheet (spec sheet). + +Copyright 2023 Intelligent Measurement Systems LLC """ from typing import Tuple