|
| 1 | +""" |
| 2 | +Calculating a module's IV curves |
| 3 | +===================== |
| 4 | +
|
| 5 | +Examples of modeling IV curves using a single-diode circuit equivalent model. |
| 6 | +""" |
| 7 | + |
| 8 | +# %% |
| 9 | +# Calculating a module IV curve for certain operating conditions is a two-step |
| 10 | +# process. Multiple methods exist for both parts of the process. Here we use |
| 11 | +# the De Soto model [1]_ to calculate the electrical parameters for an IV |
| 12 | +# curve at a certain irradiance and temperature using the module's |
| 13 | +# base characteristics at reference conditions. Those parameters are then used |
| 14 | +# to calculate the module's IV curve by solving the single-diode equation using |
| 15 | +# the Lambert W method. |
| 16 | +# |
| 17 | +# The single-diode equation is a circuit-equivalent model of a PV |
| 18 | +# cell and has five electrical parameters that depend on the operating |
| 19 | +# conditions. For more details on the single-diode equation and the five |
| 20 | +# parameters, see the `PVPMC single diode page |
| 21 | +# <https://pvpmc.sandia.gov/modeling-steps/2-dc-module-iv/diode-equivalent-circuit-models/>`_. |
| 22 | +# |
| 23 | +# References |
| 24 | +# ---------- |
| 25 | +# .. [1] W. De Soto et al., "Improvement and validation of a model for |
| 26 | +# photovoltaic array performance", Solar Energy, vol 80, pp. 78-88, 2006. |
| 27 | +# |
| 28 | +# Calculating IV Curves |
| 29 | +# ----------------------- |
| 30 | +# This example uses :py:meth:`pvlib.pvsystem.calcparams_desoto` to calculate |
| 31 | +# the 5 electrical parameters needed to solve the single-diode equation. |
| 32 | +# :py:meth:`pvlib.pvsystem.singlediode` is then used to generate the IV curves. |
| 33 | + |
| 34 | +from pvlib import pvsystem |
| 35 | +import pandas as pd |
| 36 | +import matplotlib.pyplot as plt |
| 37 | + |
| 38 | +# Example module parameters for the Canadian Solar CS5P-220M: |
| 39 | +parameters = { |
| 40 | + 'Name': 'Canadian Solar CS5P-220M', |
| 41 | + 'BIPV': 'N', |
| 42 | + 'Date': '10/5/2009', |
| 43 | + 'T_NOCT': 42.4, |
| 44 | + 'A_c': 1.7, |
| 45 | + 'N_s': 96, |
| 46 | + 'I_sc_ref': 5.1, |
| 47 | + 'V_oc_ref': 59.4, |
| 48 | + 'I_mp_ref': 4.69, |
| 49 | + 'V_mp_ref': 46.9, |
| 50 | + 'alpha_sc': 0.004539, |
| 51 | + 'beta_oc': -0.22216, |
| 52 | + 'a_ref': 2.6373, |
| 53 | + 'I_L_ref': 5.114, |
| 54 | + 'I_o_ref': 8.196e-10, |
| 55 | + 'R_s': 1.065, |
| 56 | + 'R_sh_ref': 381.68, |
| 57 | + 'Adjust': 8.7, |
| 58 | + 'gamma_r': -0.476, |
| 59 | + 'Version': 'MM106', |
| 60 | + 'PTC': 200.1, |
| 61 | + 'Technology': 'Mono-c-Si', |
| 62 | +} |
| 63 | + |
| 64 | +cases = [ |
| 65 | + (1000, 55), |
| 66 | + (800, 55), |
| 67 | + (600, 55), |
| 68 | + (400, 25), |
| 69 | + (400, 40), |
| 70 | + (400, 55) |
| 71 | +] |
| 72 | + |
| 73 | +conditions = pd.DataFrame(cases, columns=['Geff', 'Tcell']) |
| 74 | + |
| 75 | +# adjust the reference parameters according to the operating |
| 76 | +# conditions using the De Soto model: |
| 77 | +IL, I0, Rs, Rsh, nNsVth = pvsystem.calcparams_desoto( |
| 78 | + conditions['Geff'], |
| 79 | + conditions['Tcell'], |
| 80 | + alpha_sc=parameters['alpha_sc'], |
| 81 | + a_ref=parameters['a_ref'], |
| 82 | + I_L_ref=parameters['I_L_ref'], |
| 83 | + I_o_ref=parameters['I_o_ref'], |
| 84 | + R_sh_ref=parameters['R_sh_ref'], |
| 85 | + R_s=parameters['R_s'], |
| 86 | + EgRef=1.121, |
| 87 | + dEgdT=-0.0002677 |
| 88 | +) |
| 89 | + |
| 90 | +# plug the parameters into the SDE and solve for IV curves: |
| 91 | +curve_info = pvsystem.singlediode( |
| 92 | + photocurrent=IL, |
| 93 | + saturation_current=I0, |
| 94 | + resistance_series=Rs, |
| 95 | + resistance_shunt=Rsh, |
| 96 | + nNsVth=nNsVth, |
| 97 | + ivcurve_pnts=100, |
| 98 | + method='lambertw' |
| 99 | +) |
| 100 | + |
| 101 | +# plot the calculated curves: |
| 102 | +plt.figure() |
| 103 | +for i, case in conditions.iterrows(): |
| 104 | + label = ( |
| 105 | + "$G_{eff}$ " + f"{case['Geff']} $W/m^2$\n" |
| 106 | + "$T_{cell}$ " + f"{case['Tcell']} $C$" |
| 107 | + ) |
| 108 | + plt.plot(curve_info['v'][i], curve_info['i'][i], label=label) |
| 109 | + v_mp = curve_info['v_mp'][i] |
| 110 | + i_mp = curve_info['i_mp'][i] |
| 111 | + # mark the MPP |
| 112 | + plt.plot([v_mp], [i_mp], ls='', marker='o', c='k') |
| 113 | + |
| 114 | +plt.legend(loc=(1.0, 0)) |
| 115 | +plt.xlabel('Module voltage [V]') |
| 116 | +plt.ylabel('Module current [A]') |
| 117 | +plt.title(parameters['Name']) |
| 118 | +plt.show() |
| 119 | +plt.gcf().set_tight_layout(True) |
| 120 | + |
| 121 | + |
| 122 | +# draw trend arrows |
| 123 | +def draw_arrow(ax, label, x0, y0, rotation, size, direction): |
| 124 | + style = direction + 'arrow' |
| 125 | + bbox_props = dict(boxstyle=style, fc=(0.8, 0.9, 0.9), ec="b", lw=1) |
| 126 | + t = ax.text(x0, y0, label, ha="left", va="bottom", rotation=rotation, |
| 127 | + size=size, bbox=bbox_props, zorder=-1) |
| 128 | + |
| 129 | + bb = t.get_bbox_patch() |
| 130 | + bb.set_boxstyle(style, pad=0.6) |
| 131 | + |
| 132 | + |
| 133 | +ax = plt.gca() |
| 134 | +draw_arrow(ax, 'Irradiance', 20, 2.5, 90, 15, 'r') |
| 135 | +draw_arrow(ax, 'Temperature', 35, 1, 0, 15, 'l') |
| 136 | + |
| 137 | +print(pd.DataFrame({ |
| 138 | + 'i_sc': curve_info['i_sc'], |
| 139 | + 'v_oc': curve_info['v_oc'], |
| 140 | + 'i_mp': curve_info['i_mp'], |
| 141 | + 'v_mp': curve_info['v_mp'], |
| 142 | + 'p_mp': curve_info['p_mp'], |
| 143 | +})) |
0 commit comments