|
| 1 | +import numpy as np |
| 2 | +import pandas as pd |
| 3 | + |
| 4 | + |
| 5 | +def power_mismatch_deline( |
| 6 | + rmad, |
| 7 | + coefficients=(0, 0.142, 0.032 * 100), |
| 8 | + fill_factor: float = None, |
| 9 | + fill_factor_reference: float = 0.79, |
| 10 | +): |
| 11 | + r""" |
| 12 | + Estimate DC power loss due to irradiance non-uniformity. |
| 13 | +
|
| 14 | + This model is described for bifacial modules in [1]_, where the backside |
| 15 | + irradiance is less uniform due to mounting and site conditions. |
| 16 | +
|
| 17 | + The power loss is estimated by a polynomial model of the Relative Mean |
| 18 | + Absolute Difference (RMAD) of the cell-by-cell total irradiance. |
| 19 | +
|
| 20 | + Use ``fill_factor`` to account for different fill factors between the |
| 21 | + data used to fit the model and the module of interest. Specify the model's fill factor with |
| 22 | + ``fill_factor_reference``. |
| 23 | +
|
| 24 | + .. versionadded:: 0.11.1 |
| 25 | +
|
| 26 | + Parameters |
| 27 | + ---------- |
| 28 | + rmad : numeric |
| 29 | + The Relative Mean Absolute Difference of the cell-by-cell total |
| 30 | + irradiance. [Unitless] |
| 31 | +
|
| 32 | + See the *Notes* section for the equation to calculate ``rmad`` from the |
| 33 | + bifaciality and the front and back irradiances. |
| 34 | +
|
| 35 | + coefficients : float collection or numpy.polynomial.polynomial.Polynomial, default ``(0, 0.142, 0.032 * 100)`` |
| 36 | + The polynomial coefficients to use. |
| 37 | +
|
| 38 | + If a :external:class:`numpy.polynomial.polynomial.Polynomial`, |
| 39 | + it is evaluated as is. If not a ``Polynomial``, it must be the |
| 40 | + coefficients of a polynomial in ``rmad``, where the first element is |
| 41 | + the constant term and the last element is the highest order term. A |
| 42 | + :external:class:`~numpy.polynomial.polynomial.Polynomial` |
| 43 | + will be created internally. |
| 44 | +
|
| 45 | + fill_factor : float, optional |
| 46 | + Fill factor at standard test condition (STC) of the module. |
| 47 | + Accounts for different fill factors between the trained model and the |
| 48 | + module under non-uniform irradiance. |
| 49 | + If not provided, the default ``fill_factor_reference`` of 0.79 is used. |
| 50 | +
|
| 51 | + fill_factor_reference : float, default 0.79 |
| 52 | + Fill factor at STC of the module used to train the model. |
| 53 | +
|
| 54 | + Returns |
| 55 | + ------- |
| 56 | + loss : numeric |
| 57 | + The fractional power loss. [Unitless] |
| 58 | +
|
| 59 | + Output will be a ``pandas.Series`` if ``rmad`` is a ``pandas.Series``. |
| 60 | +
|
| 61 | + Notes |
| 62 | + ----- |
| 63 | + The default model implemented is equation (11) [1]_: |
| 64 | +
|
| 65 | + .. math:: |
| 66 | +
|
| 67 | + M[\%] &= 0.142 \Delta[\%] + 0.032 \Delta^2[\%] \qquad \text{(11)} |
| 68 | +
|
| 69 | + M[-] &= 0.142 \Delta[-] + 0.032 \times 100 \Delta^2[-] |
| 70 | +
|
| 71 | + where the upper equation is in percentage (same as paper) and the lower |
| 72 | + one is unitless. The implementation uses the unitless version, where |
| 73 | + :math:`M[-]` is the mismatch power loss [unitless] and |
| 74 | + :math:`\Delta[-]` is the Relative Mean Absolute Difference [unitless] |
| 75 | + of the global irradiance, Eq. (4) of [1]_ and [2]_. |
| 76 | + Note that the n-th power coefficient is multiplied by :math:`100^{n-1}` |
| 77 | + to convert the percentage to unitless. |
| 78 | +
|
| 79 | + The losses definition is Eq. (1) of [1]_, and it's defined as a loss of the |
| 80 | + output power: |
| 81 | +
|
| 82 | + .. math:: |
| 83 | +
|
| 84 | + M = 1 - \frac{P_{Array}}{\sum P_{Cells}} \qquad \text{(1)} |
| 85 | +
|
| 86 | + To account for a module with a fill factor distinct from the one used to |
| 87 | + train the model (``0.79`` by default), the output of the model can be |
| 88 | + modified with Eq. (7): |
| 89 | +
|
| 90 | + .. math:: |
| 91 | +
|
| 92 | + M_{FF_1} = M_{FF_0} \frac{FF_1}{FF_0} \qquad \text{(7)} |
| 93 | +
|
| 94 | + where parameter ``fill_factor`` is :math:`FF_1` and |
| 95 | + ``fill_factor_reference`` is :math:`FF_0`. |
| 96 | +
|
| 97 | + In the section *See Also*, you will find two packages that can be used to |
| 98 | + calculate the irradiance at different points of the module. |
| 99 | +
|
| 100 | + .. note:: |
| 101 | + The global irradiance RMAD is different from the backside irradiance |
| 102 | + RMAD. |
| 103 | +
|
| 104 | + In case the RMAD of the backside irradiance is known, the global RMAD can |
| 105 | + be calculated as follows, assuming the front irradiance RMAD is |
| 106 | + negligible [2]_: |
| 107 | +
|
| 108 | + .. math:: |
| 109 | +
|
| 110 | + RMAD(k \cdot X + c) = RMAD(X) \cdot k \frac{k \bar{X}}{k \bar{X} + c} |
| 111 | + = RMAD(X) \cdot \frac{k}{1 + \frac{c}{k \bar{X}}} |
| 112 | +
|
| 113 | + by similarity with equation (2) of [1]_: |
| 114 | +
|
| 115 | + .. math:: |
| 116 | +
|
| 117 | + G_{total\,i} = G_{front\,i} + \phi_{Bifi} G_{rear\,i} \qquad \text{(2)} |
| 118 | +
|
| 119 | + which yields: |
| 120 | +
|
| 121 | + .. math:: |
| 122 | +
|
| 123 | + RMAD_{total} = RMAD_{rear} \frac{\phi_{Bifi}} |
| 124 | + {1 + \frac{G_{front}}{\phi_{Bifi} \bar{G}_{rear}}} |
| 125 | +
|
| 126 | + See Also |
| 127 | + -------- |
| 128 | + `solarfactors <https://github.com/pvlib/solarfactors/>`_ |
| 129 | + Calculate the irradiance at different points of the module. |
| 130 | + `bifacial_radiance <https://github.com/NREL/bifacial_radiance>`_ |
| 131 | + Calculate the irradiance at different points of the module. |
| 132 | +
|
| 133 | + References |
| 134 | + ---------- |
| 135 | + .. [1] C. Deline, S. Ayala Pelaez, S. MacAlpine, and C. Olalla, 'Estimating |
| 136 | + and parameterizing mismatch power loss in bifacial photovoltaic |
| 137 | + systems', Progress in Photovoltaics: Research and Applications, vol. 28, |
| 138 | + no. 7, pp. 691-703, 2020, :doi:`10.1002/pip.3259`. |
| 139 | + .. [2] “Mean absolute difference,” Wikipedia, Sep. 05, 2023. |
| 140 | + https://en.wikipedia.org/wiki/Mean_absolute_difference#Relative_mean_absolute_difference |
| 141 | + (accessed 2024-04-14). |
| 142 | + """ # noqa: E501 |
| 143 | + if isinstance(coefficients, np.polynomial.Polynomial): |
| 144 | + model_polynom = coefficients |
| 145 | + else: # expect an iterable |
| 146 | + model_polynom = np.polynomial.Polynomial(coef=coefficients) |
| 147 | + |
| 148 | + if fill_factor: # Eq. (7), [1] |
| 149 | + # Scale output of trained model to account for different fill factors |
| 150 | + model_polynom = model_polynom * fill_factor / fill_factor_reference |
| 151 | + |
| 152 | + mismatch = model_polynom(rmad) |
| 153 | + if isinstance(rmad, pd.Series): |
| 154 | + mismatch = pd.Series(mismatch, index=rmad.index) |
| 155 | + return mismatch |
0 commit comments