|
20 | 20 | # :py:func:`pvlib.shading.masking_angle_passias` and |
21 | 21 | # :py:func:`pvlib.shading.sky_diffuse_passias`. |
22 | 22 | # |
| 23 | +# However, the pvlib-python authors believe that this approach is incorrect. |
| 24 | +# A correction is suggested and compared with the diffuse shading as obtained |
| 25 | +# with the view factor model. |
| 26 | +# |
23 | 27 | # References |
24 | 28 | # ---------- |
25 | 29 | # .. [1] D. Passias and B. Källbäck, "Shading effects in rows of solar cell |
26 | 30 | # panels", Solar Cells, Volume 11, Pages 281-291. 1984. |
27 | 31 | # DOI: 10.1016/0379-6787(84)90017-6 |
28 | 32 |
|
29 | | -from pvlib import shading, irradiance |
30 | 33 | import matplotlib.pyplot as plt |
31 | 34 | import numpy as np |
| 35 | +from cycler import cycler |
| 36 | + |
| 37 | +from pvlib import bifacial, shading, irradiance |
32 | 38 |
|
33 | 39 | # %% |
34 | 40 | # First we'll recreate Figure 4, showing how the average masking angle varies |
|
43 | 49 |
|
44 | 50 | plt.figure() |
45 | 51 | for k in [1, 1.5, 2, 2.5, 3, 4, 5, 7, 10]: |
46 | | - gcr = 1/k |
| 52 | + gcr = 1 / k |
47 | 53 | psi = shading.masking_angle_passias(surface_tilt, gcr) |
48 | 54 | plt.plot(surface_tilt, psi, label=f'k={k}') |
49 | 55 |
|
|
60 | 66 | # diffuse plane of array irradiance (after accounting for shading) to diffuse |
61 | 67 | # horizontal irradiance. This means that the deviation from 100% is due to the |
62 | 68 | # combination of self-shading and the fact that being at a tilt blocks off |
63 | | -# the portion of the sky behind the row. The first effect is modeled with |
| 69 | +# the portion of the sky behind the row. Following the approach detailed in |
| 70 | +# [1]_, the first effect would be modeled with |
64 | 71 | # :py:func:`pvlib.shading.sky_diffuse_passias` and the second with |
65 | 72 | # :py:func:`pvlib.irradiance.isotropic`. |
66 | 73 |
|
67 | 74 | plt.figure() |
68 | 75 | for k in [1, 1.5, 2, 10]: |
69 | | - gcr = 1/k |
| 76 | + gcr = 1 / k |
70 | 77 | psi = shading.masking_angle_passias(surface_tilt, gcr) |
71 | 78 | shading_loss = shading.sky_diffuse_passias(psi) |
72 | 79 | transposition_ratio = irradiance.isotropic(surface_tilt, dhi=1.0) |
73 | | - relative_diffuse = transposition_ratio * (1-shading_loss) * 100 # % |
| 80 | + relative_diffuse = transposition_ratio * (1 - shading_loss) * 100 # % |
74 | 81 | plt.plot(surface_tilt, relative_diffuse, label=f'k={k}') |
75 | 82 |
|
76 | 83 | plt.xlabel('Inclination angle [degrees]') |
|
82 | 89 | # %% |
83 | 90 | # As ``k`` decreases, GCR increases, so self-shading loss increases and |
84 | 91 | # collected diffuse irradiance decreases. |
| 92 | +# |
| 93 | +# However, the pvlib-python authors believe that this approach is incorrect. |
| 94 | +# |
| 95 | +# Instead, the combination of inter-row shading from the previous row and the |
| 96 | +# surface tilt blocking the portion of the sky behind the row is obtained by |
| 97 | +# applying :py:func:`pvlib.shading.sky_diffuse_passias` on the sum of the |
| 98 | +# masking and surface tilt angles (see dashed curves in below figure). The |
| 99 | +# difference with the above approach is marginal for a ground coverage ratio |
| 100 | +# of 10%, but becomes very significant for high ground coverage ratios. |
| 101 | +# |
| 102 | +# Alternatively, one can also use :py:func:`bifacial.utils.vf_row_sky_2d_integ` |
| 103 | +# (see dotted curve in below figure), with very similar results except for the |
| 104 | +# highest ground coverage ratio. It is believed that the deviation is a result |
| 105 | +# of an approximation in :py:func:`pvlib.shading.masking_angle_passias` and |
| 106 | +# that :py:func:`bifacial.utils.vf_row_sky_2d_integ` provides the most accurate |
| 107 | +# result. |
| 108 | + |
| 109 | +color_cycler = cycler('color', ['blue', 'orange', 'green', 'red']) |
| 110 | +linestyle_cycler = cycler('linestyle', ['--', ':']) |
| 111 | +plt.rc('axes', prop_cycle=color_cycler * linestyle_cycler) |
| 112 | +plt.figure() |
| 113 | +for k in [1, 1.5, 2, 10]: |
| 114 | + gcr = 1 / k |
| 115 | + psi = shading.masking_angle_passias(surface_tilt, gcr) |
| 116 | + vf1 = (1 - shading.sky_diffuse_passias(surface_tilt + psi)) * 100 # % |
| 117 | + vf2 = bifacial.utils.vf_row_sky_2d_integ(surface_tilt, gcr) * 100 # % |
| 118 | + plt.plot(surface_tilt, vf1, label=f'k={k} passias corrected') |
| 119 | + plt.plot(surface_tilt, vf2, label=f'k={k} vf_row_sky_2d_integ') |
| 120 | + |
| 121 | +plt.xlabel('Inclination angle [degrees]') |
| 122 | +plt.ylabel('Relative diffuse irradiance [%]') |
| 123 | +plt.ylim(0, 105) |
| 124 | +plt.legend() |
| 125 | +plt.show() |
0 commit comments