@@ -305,3 +305,88 @@ def projected_solar_zenith_angle(solar_zenith, solar_azimuth,
305305 # Eq. (5); angle between sun's beam and surface
306306 theta_T = np .degrees (np .arctan2 (sx_prime , sz_prime ))
307307 return theta_T
308+
309+
310+ def tracker_shaded_fraction (tracker_theta , gcr , projected_solar_zenith ,
311+ cross_axis_slope = 0 ):
312+ """
313+ Shade fraction (FS) for trackers with a common angle on an east-west slope.
314+
315+ Parameters
316+ ----------
317+ tracker_theta : numeric
318+ The tracker rotation angle in degrees from horizontal.
319+ gcr : float
320+ The ground coverage ratio as a fraction equal to the collector width
321+ over the horizontal row-to-row pitch.
322+ projected_solar_zenith : numeric
323+ Zenith angle in degrees of the solar vector projected into the plane
324+ perpendicular to the tracker axes.
325+ cross_axis_slope : float, default 0
326+ Angle of the plane containing the tracker axes in degrees from
327+ horizontal.
328+
329+ Returns
330+ -------
331+ shade_fraction : numeric
332+ The fraction of the collector width shaded by an adjacent row. A
333+ value of 1 is completely shaded and zero is no shade.
334+
335+ References
336+ ----------
337+ Mark A. Mikofski, "First Solar Irradiance Shade Losses on Sloped Terrain,"
338+ PVPMC, 2023
339+ """
340+ theta_g_rad = np .radians (cross_axis_slope )
341+ # angle opposite shadow cast on the ground, z
342+ angle_z = (
343+ np .pi / 2 - np .radians (tracker_theta )
344+ + np .radians (projected_solar_zenith ))
345+ # angle opposite the collector width, L
346+ angle_gcr = (
347+ np .pi / 2 - np .radians (projected_solar_zenith )
348+ - theta_g_rad )
349+ # ratio of shadow, z, to pitch, P
350+ zp = gcr * np .sin (angle_z ) / np .sin (angle_gcr )
351+ # there's only row-to-row shade loss if the shadow on the ground, z, is
352+ # longer than row-to-row pitch projected on the ground, P*cos(theta_g)
353+ zp_cos_g = zp * np .cos (theta_g_rad )
354+ # shade fraction
355+ fs = np .where (zp_cos_g <= 1 , 0 , 1 - 1 / zp_cos_g )
356+ return fs
357+
358+
359+ def linear_shade_loss (shade_fraction , diffuse_fraction ):
360+ """
361+ Fraction of power lost to linear shade loss applicable to CdTe modules like
362+ First Solar.
363+
364+ Parameters
365+ ----------
366+ shade_fraction : numeric
367+ The fraction of the collector width shaded by an adjacent row. A
368+ value of 1 is completely shaded and zero is no shade.
369+ diffuse_fraction : numeric
370+ The ratio of diffuse plane of array (poa) irradiance to global poa.
371+ A value of 1 is completely diffuse and zero is no diffuse.
372+
373+ Returns
374+ -------
375+ linear_shade_loss : numeric
376+ The fraction of power lost due to linear shading. A value of 1 is all
377+ power lost and zero is no loss.
378+
379+ See also
380+ --------
381+ pvlib.tracking.tracker_shaded_fraction
382+
383+ Example
384+ -------
385+ >>> from pvlib import tracking
386+ >>> fs = tracking.tracker_shaded_fraction(45.0, 0.8, 45.0, 0)
387+ >>> loss = tracking.linear_shade_loss(fs, 0.2)
388+ >>> P_no_shade = 100 # [kWdc] DC output from modules
389+ >>> P_linear_shade = P_no_shade * (1-loss) # [kWdc] output after loss
390+ # 90.71067811865476 [kWdc]
391+ """
392+ return shade_fraction * (1 - diffuse_fraction )
0 commit comments