Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Linear shade loss model - continuation of pr 1725 #2004

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@ Shading
shading.projected_solar_zenith_angle
shading.shaded_fraction1d
shading.direct_martinez
shading.linear_shade_loss
59 changes: 59 additions & 0 deletions pvlib/shading.py
Original file line number Diff line number Diff line change
Expand Up @@ -692,3 +692,62 @@ def direct_martinez(
)
/ poa_global
)


def linear_shade_loss(shaded_fraction, diffuse_fraction):
r"""
Fraction of power lost to linear shade loss.

Linear shade loss is applicable to monolithic thin film modules like
First Solar CdTe, where the shadow is perpendicular to cell scribe lines.

.. versionadded:: 0.10.5

Parameters
----------
shaded_fraction : numeric
The fraction of the collector width shaded by an adjacent row. A
value of 1 corresponds to completely shaded and zero is no shading.
diffuse_fraction : numeric
The ratio of diffuse plane of array (POA) irradiance to global POA.
A value of 1 corresponds to all incident irradiance being diffuse,
and a value of zero corresponds to all irradiance being direct.

Returns
-------
linear_shade_loss : numeric
The fraction of power lost due to linear shading. A value of 1 is all
power lost and zero is no loss.

Notes
-----
The reasoning behind this loss model is described in sections 4.2 and 4.3
of [1]_.

The loss is calculated as:

.. math::

\text{loss} = \text{shaded_fraction}\cdot(1-\text{diffuse_fraction})

See also
--------
pvlib.shading.shaded_fraction1d : 1-dimensional shaded fraction calculation

Example
-------
>>> from pvlib import shading
>>> sf = shading.shaded_fraction1d(80, 180, 90, 25,
collector_width=0.5, row_pitch=1, surface_to_axis_offset=0,
cross_axis_slope=5.711, shading_tracker_tilt=50)
>>> loss = shading.linear_shade_loss(sf, diffuse_fraction=0.2)
>>> P_no_shade = 100 # [kWdc] DC output from modules
>>> P_linear_shade = P_no_shade * (1-loss) # [kWdc] output after loss
75.51797783654133

References
----------
.. [1] First Solar, “First Solar Series 4 Module.” [Online]. Available at: https://web.archive.org/web/20230512210902/https://www.firstsolar.com/-/media/First-Solar/Technical-Documents/User-Guides/Series-4-Module-User-Guide-North-America.ashx?la=en [accessed 2024-04-12]
.. [2] First Solar, “Diffuse Irradiance and Tracker Simulations,” May 01-02, 2013. http://web.archive.org/web/20170127080529/https://energy.sandia.gov/wp-content/gallery/uploads/26-Littmann-Tracking-and-Diffuse-Shading.pdf0_.pdf [accessed 2024-04-12]
""" # noqa: E501
return shaded_fraction * (1 - diffuse_fraction)
16 changes: 16 additions & 0 deletions pvlib/tests/test_shading.py
Original file line number Diff line number Diff line change
Expand Up @@ -389,3 +389,19 @@ def test_direct_martinez(direct_martinez_Table2):
test_data, power_losses_expected = direct_martinez_Table2
power_losses = shading.direct_martinez(**test_data)
assert_allclose(power_losses, power_losses_expected, atol=5e-3)


def test_linear_shade_loss():
test_data = pd.DataFrame(
columns=["shaded_fraction", "diffuse_ratio", "expected_loss"],
data=[
[0.11611, 0.2, 0.09289],
[0.11611, 0.0, 0.11611], # no diffuse, shade fraction is the loss
[0.11611, 1.0, 0.00000], # all diffuse, no shade loss
[0.16667, 0.2, 0.13333],
[0.03775, 0.2, 0.03019],
]
)
loss = shading.linear_shade_loss(test_data["shaded_fraction"],
test_data["diffuse_ratio"])
assert_allclose(loss, test_data["expected_loss"], atol=1e-5)
Loading