Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
96697f1
Add cross_axis_tilt to nomenclature.rst
echedey-ls Jan 8, 2025
8eebd5f
Rename, cross_axis_slope -> cross_axis_tilt
echedey-ls Jan 8, 2025
0aa8836
Add renamed_kwarg_warning
echedey-ls Jan 8, 2025
01d5c0b
Fix typo in renamed_kwarg_warning docstring
echedey-ls Jan 8, 2025
e72ca32
Deprecate in v0.13.1 / Removal in v0.15.0
echedey-ls Sep 7, 2025
08bcde4
move descriptions, link to nomenclature term
echedey-ls Sep 7, 2025
6f9da5e
Merge branch 'main' into cross-axis-whatever-name-consistent-name
echedey-ls Sep 7, 2025
3ca225e
merge fix
echedey-ls Sep 7, 2025
c74127c
whatsnew
echedey-ls Sep 7, 2025
3006aa1
Dax review
echedey-ls Sep 20, 2025
2cebae7
Change: deprecate *axis_tilt in favour of *axis_slope
echedey-ls Sep 24, 2025
27b24e7
Typo in v0.13.1 whatnew
echedey-ls Sep 24, 2025
0b6336e
Merge branch 'main' into cross-axis-whatever-name-consistent-name
echedey-ls Sep 24, 2025
3625a5a
flake8 may forgive me
echedey-ls Sep 24, 2025
de94021
whatsnew improvements
echedey-ls Sep 24, 2025
716c880
Merge branch 'main' into cross-axis-whatever-name-consistent-name
echedey-ls Oct 1, 2025
7e52234
move whatsnew entries
echedey-ls Oct 1, 2025
d8467bc
rm whatnew duplicated from merge entry
echedey-ls Oct 1, 2025
50b1740
Merge branch 'main' into cross-axis-whatever-name-consistent-name
echedey-ls Nov 26, 2025
b84adc6
axis_azimuth description revision feat. cwhanse
echedey-ls Dec 8, 2025
25410b3
Move definition from pvsystem's SingleAxisTrackerMount to nomenclature
echedey-ls Dec 8, 2025
4c8a029
add axis_slope definition, as per figure in cross_axis_slope
echedey-ls Dec 8, 2025
c964df4
bump deprecation version from 0.13.1 to 0.13.2
echedey-ls Dec 8, 2025
24415fd
Move Deprecations to its section, instead of Breaking Changes
echedey-ls Dec 8, 2025
0350466
Description update of axis_azimuth
echedey-ls Dec 8, 2025
6de2087
Merge branch 'main' into cross-axis-whatever-name-consistent-name
echedey-ls Dec 8, 2025
3ed6172
picky linter
echedey-ls Dec 8, 2025
30a4513
Merge branch 'cross-axis-whatever-name-consistent-name' of https://gi…
echedey-ls Dec 8, 2025
5d0719a
nomenclature cross_axis_slope redaction
echedey-ls Dec 8, 2025
9ecf9e4
Cliff's fixing my confusion
echedey-ls Dec 9, 2025
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
2 changes: 1 addition & 1 deletion benchmarks/benchmarks/infinite_sheds.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def setup(self, vectorize):
self.tracking = tracking.singleaxis(
self.solar_position['apparent_zenith'],
self.solar_position['azimuth'],
axis_tilt=0,
axis_slope=0,
axis_azimuth=0,
max_angle=60,
backtrack=True,
Expand Down
2 changes: 1 addition & 1 deletion benchmarks/benchmarks/tracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def time_singleaxis(self):
with np.errstate(invalid='ignore'):
tracking.singleaxis(self.solar_position.apparent_zenith,
self.solar_position.azimuth,
axis_tilt=0,
axis_slope=0,
axis_azimuth=0,
max_angle=60,
backtrack=True,
Expand Down
4 changes: 2 additions & 2 deletions docs/examples/bifacial/plot_bifi_model_mc.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
times = pd.date_range('2021-06-21', '2021-6-22', freq='1T', tz=tz)

# create site system characteristics
axis_tilt = 0
axis_slope = 0
axis_azimuth = 180
gcr = 0.35
max_angle = 60
Expand All @@ -65,7 +65,7 @@
cs = site_location.get_clearsky(times)

# load solar position and tracker orientation for use in pvsystem object
sat_mount = pvsystem.SingleAxisTrackerMount(axis_tilt=axis_tilt,
sat_mount = pvsystem.SingleAxisTrackerMount(axis_slope=axis_slope,
axis_azimuth=axis_azimuth,
max_angle=max_angle,
backtrack=True,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ def calculate_poa(tmy, solar_position, surface_tilt, surface_azimuth):
# single-axis tracking:
orientation = tracking.singleaxis(solar_position['apparent_zenith'],
solar_position['azimuth'],
axis_tilt=0, # flat array
axis_slope=0, # flat array
axis_azimuth=180, # south-facing azimuth
max_angle=60, # a common maximum rotation
backtrack=True, # backtrack for a c-Si array
Expand Down
14 changes: 7 additions & 7 deletions docs/examples/shading/plot_martinez_shade_loss.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@
gcr = width / pitch # ground coverage ratio
N_modules_per_row = 6
axis_azimuth = 180 # N-S axis
axis_tilt = 0 # flat because the axis is perpendicular to the slope
cross_axis_tilt = -7 # 7 degrees downward to the east
axis_slope = 0 # flat because the axis is perpendicular to the slope
cross_axis_slope = -7 # 7 degrees downward to the east

latitude, longitude = 40.2712, -3.7277
locus = pvlib.location.Location(
Expand Down Expand Up @@ -91,12 +91,12 @@
tracking_result = pvlib.tracking.singleaxis(
apparent_zenith=solar_apparent_zenith,
solar_azimuth=solar_azimuth,
axis_tilt=axis_tilt,
axis_slope=axis_slope,
axis_azimuth=axis_azimuth,
max_angle=(-90 + cross_axis_tilt, 90 + cross_axis_tilt), # (min, max)
max_angle=(-90 + cross_axis_slope, 90 + cross_axis_slope), # (min, max)
backtrack=False,
gcr=gcr,
cross_axis_tilt=cross_axis_tilt,
cross_axis_slope=cross_axis_slope,
)

tracker_theta, aoi, surface_tilt, surface_azimuth = (
Expand All @@ -111,12 +111,12 @@
solar_apparent_zenith,
solar_azimuth,
axis_azimuth,
axis_tilt=axis_tilt,
axis_slope=axis_slope,
shaded_row_rotation=tracker_theta,
shading_row_rotation=tracker_theta,
collector_width=width,
pitch=pitch,
cross_axis_slope=cross_axis_tilt,
cross_axis_slope=cross_axis_slope,
)

# %%
Expand Down
16 changes: 8 additions & 8 deletions docs/examples/shading/plot_shaded_fraction1d_ns_hsat_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
latitude, longitude = 28.51, -13.89
altitude = pvlib.location.lookup_altitude(latitude, longitude)

axis_tilt = 3 # degrees, positive is upwards in the axis_azimuth direction
axis_slope = 3 # degrees, positive is upwards in the axis_azimuth direction
axis_azimuth = 180 # degrees, N-S tracking axis
collector_width = 3.2 # m
pitch = 4.15 # m
Expand All @@ -71,12 +71,12 @@
rotation_angle = pvlib.tracking.singleaxis(
solar_zenith,
solar_azimuth,
axis_tilt,
axis_slope,
axis_azimuth,
max_angle=(-50, 50), # (min, max) degrees
backtrack=False,
gcr=gcr,
cross_axis_tilt=cross_axis_slope,
cross_axis_slope=cross_axis_slope,
)["tracker_theta"]

# %%
Expand All @@ -95,7 +95,7 @@
# failure or with a different system configuration.

psza = pvlib.shading.projected_solar_zenith_angle(
solar_zenith, solar_azimuth, axis_tilt, axis_azimuth
solar_zenith, solar_azimuth, axis_slope, axis_azimuth
)

# Calculate the shaded fraction for the eastmost row
Expand All @@ -108,7 +108,7 @@
solar_azimuth,
axis_azimuth,
shaded_row_rotation=rotation_angle,
axis_tilt=axis_tilt,
axis_slope=axis_slope,
collector_width=collector_width,
pitch=pitch,
surface_to_axis_offset=surface_to_axis_offset,
Expand All @@ -126,7 +126,7 @@
solar_azimuth,
axis_azimuth,
shaded_row_rotation=rotation_angle,
axis_tilt=axis_tilt,
axis_slope=axis_slope,
collector_width=collector_width,
pitch=pitch,
surface_to_axis_offset=surface_to_axis_offset,
Expand All @@ -139,7 +139,7 @@
solar_azimuth,
axis_azimuth,
shaded_row_rotation=rotation_angle,
axis_tilt=axis_tilt,
axis_slope=axis_slope,
collector_width=collector_width,
pitch=pitch,
surface_to_axis_offset=surface_to_axis_offset,
Expand All @@ -157,7 +157,7 @@
solar_azimuth,
axis_azimuth,
shaded_row_rotation=rotation_angle,
axis_tilt=axis_tilt,
axis_slope=axis_slope,
collector_width=collector_width,
pitch=pitch,
surface_to_axis_offset=surface_to_axis_offset,
Expand Down
6 changes: 3 additions & 3 deletions docs/examples/solar-tracking/plot_discontinuous_tracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

class DiscontinuousTrackerMount(pvsystem.SingleAxisTrackerMount):
# inherit from SingleAxisTrackerMount so that we get the
# constructor and tracking attributes (axis_tilt etc) automatically
# constructor and tracking attributes (axis_slope etc) automatically

def get_orientation(self, solar_zenith, solar_azimuth):
# Different trackers update at different rates; in this example we'll
Expand All @@ -37,9 +37,9 @@ def get_orientation(self, solar_zenith, solar_azimuth):

tracking_data_15min = tracking.singleaxis(
zenith_subset, azimuth_subset,
self.axis_tilt, self.axis_azimuth,
self.axis_slope, self.axis_azimuth,
self.max_angle, self.backtrack,
self.gcr, self.cross_axis_tilt
self.gcr, self.cross_axis_slope
)
# propagate the 15-minute positions to 1-minute stair-stepped values:
tracking_data_1min = tracking_data_15min.reindex(solar_zenith.index,
Expand Down
4 changes: 2 additions & 2 deletions docs/examples/solar-tracking/plot_single_axis_tracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
truetracking_angles = tracking.singleaxis(
apparent_zenith=solpos['apparent_zenith'],
solar_azimuth=solpos['azimuth'],
axis_tilt=0,
axis_slope=0,
axis_azimuth=180,
max_angle=90,
backtrack=False, # for true-tracking
Expand Down Expand Up @@ -62,7 +62,7 @@
backtracking_angles = tracking.singleaxis(
apparent_zenith=solpos['apparent_zenith'],
solar_azimuth=solpos['azimuth'],
axis_tilt=0,
axis_slope=0,
axis_azimuth=180,
max_angle=90,
backtrack=True,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
# calculating the backtracking angle requires knowledge of the relative spacing
# of adjacent tracker rows. This example shows how the backtracking angle
# changes based on a vertical offset between rows caused by sloped terrain.
# It uses :py:func:`pvlib.tracking.calc_axis_tilt` and
# :py:func:`pvlib.tracking.calc_cross_axis_tilt` to calculate the necessary
# It uses :py:func:`pvlib.tracking.calc_axis_slope` and
# :py:func:`pvlib.tracking.calc_cross_axis_slope` to calculate the necessary
# array geometry parameters and :py:func:`pvlib.tracking.singleaxis` to
# calculate the backtracking angles.
#
Expand Down Expand Up @@ -97,20 +97,20 @@

# compare the backtracking angle at various terrain slopes
fig, ax = plt.subplots()
for cross_axis_tilt in [0, 5, 10]:
for cross_axis_slope in [0, 5, 10]:
tracker_data = tracking.singleaxis(
apparent_zenith=solpos['apparent_zenith'],
solar_azimuth=solpos['azimuth'],
axis_tilt=0, # flat because the axis is perpendicular to the slope
axis_slope=0, # flat because the axis is perpendicular to the slope
axis_azimuth=180, # N-S axis, azimuth facing south
max_angle=90,
backtrack=True,
gcr=gcr,
cross_axis_tilt=cross_axis_tilt)
cross_axis_slope=cross_axis_slope)

# tracker rotation is undefined at night
backtracking_position = tracker_data['tracker_theta'].fillna(0)
label = 'cross-axis tilt: {}°'.format(cross_axis_tilt)
label = 'cross-axis tilt: {}°'.format(cross_axis_slope)
backtracking_position.plot(label=label, ax=ax)

plt.legend()
Expand Down Expand Up @@ -141,14 +141,14 @@
axis_azimuth = 180 # tracker axis is still N-S

# calculate the tracker axis tilt, assuming that the axis follows the terrain:
axis_tilt = tracking.calc_axis_tilt(slope_azimuth, slope_tilt, axis_azimuth)
axis_slope = tracking.calc_axis_slope(slope_azimuth, slope_tilt, axis_azimuth)

# calculate the cross-axis tilt:
cross_axis_tilt = tracking.calc_cross_axis_tilt(slope_azimuth, slope_tilt,
axis_azimuth, axis_tilt)
cross_axis_slope = tracking.calc_cross_axis_slope(slope_azimuth, slope_tilt,
axis_azimuth, axis_slope)

print('Axis tilt:', '{:0.01f}°'.format(axis_tilt))
print('Cross-axis tilt:', '{:0.01f}°'.format(cross_axis_tilt))
print('Axis tilt:', '{:0.01f}°'.format(axis_slope))
print('Cross-axis tilt:', '{:0.01f}°'.format(cross_axis_slope))

# %%
# And now we can pass use these values to generate the tracker curve as
Expand All @@ -157,18 +157,18 @@
tracker_data = tracking.singleaxis(
apparent_zenith=solpos['apparent_zenith'],
solar_azimuth=solpos['azimuth'],
axis_tilt=axis_tilt, # no longer flat because the terrain imparts a tilt
axis_slope=axis_slope, # no longer flat because the terrain imparts a tilt
axis_azimuth=axis_azimuth,
max_angle=90,
backtrack=True,
gcr=gcr,
cross_axis_tilt=cross_axis_tilt)
cross_axis_slope=cross_axis_slope)

backtracking_position = tracker_data['tracker_theta'].fillna(0)
backtracking_position.plot()

title_template = 'Axis tilt: {:0.01f}° Cross-axis tilt: {:0.01f}°'
plt.title(title_template.format(axis_tilt, cross_axis_tilt))
plt.title(title_template.format(axis_slope, cross_axis_slope))
plt.show()

# %%
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions docs/sphinx/source/reference/tracking.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ Tracking
:toctree: generated/

tracking.singleaxis
tracking.calc_axis_tilt
tracking.calc_cross_axis_tilt
tracking.calc_axis_slope
tracking.calc_cross_axis_slope
tracking.calc_surface_orientation
34 changes: 34 additions & 0 deletions docs/sphinx/source/user_guide/extras/nomenclature.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,37 @@ There is a convention on consistent variable names throughout the library:
Refraction-corrected solar elevation angle. This is the complement of
:term:`apparent_zenith` (90 - apparent_zenith). [°]

axis_slope
Angle of a tracker axis with respect to horizontal.
This is, left-hand rotation angle of :math:`t_y` around :math:`t_x` in Fig. [4] of [Anderson2020]_.
See figure in :term:`cross_axis_slope`.

bhi
Beam/direct horizontal irradiance

cross_axis_slope
Cross-axis slope angle. [°]
The angle, relative to horizontal, of the line between the axes of two
adjacent trackers, in the plane perpendicular to the tracker axes.
Cross-axis slope should be specified using a right-handed convention.

For example, trackers with axis azimuth of 180° (N-S rotation axis)
will have a negative cross-axis slope if the tracker axes plane slopes
down to the east and positive cross-axis slope if the tracker axes plane
slopes up to the east.

.. figure:: ../../_images/Anderson_Mikofski_2020_Fig4.png
:alt: Two rows of modules, tracker coordinate system and cross-axis slope of the second row w.r.t. the leftmost.
:align: center
:scale: 50 %

Fig. 4, [Anderson2020]_: Cross-axis slope angle :math:`\beta_C` relative to the tracker coordinate system.

Use :py::func:`pvlib.tracking.calc_cross_axis_slope` to calculate
``cross_axis_slope``.

See also :term:`axis_slope`.

dhi
Diffuse horizontal irradiance

Expand Down Expand Up @@ -215,3 +243,9 @@ units, refer to the following sources from `SoDa Service <http://www.soda-pro.co

.. note:: These further references might not use the same terminology as
*pvlib*. But the physical process referred to is the same.

References
----------
.. [Anderson2020] K. Anderson and M. Mikofski, 'Slope-Aware Backtracking for
Single-Axis Trackers', National Renewable Energy Lab. (NREL), Golden, CO (United States);
NREL/TP-5K00-76626, Jul. 2020. :doi:`10.2172/1660126`.
10 changes: 10 additions & 0 deletions docs/sphinx/source/whatsnew/v0.13.2.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,17 @@ Breaking Changes

Deprecations
~~~~~~~~~~~~
* Rename ``axis_tilt`` and ``cross_axis_tilt`` to ``axis_slope`` and ``cross_axis_slope`` all through the project, while keeping backwards-compatibility. Affects:

- :py:func:`pvlib.shading.shaded_fraction1d` parameters ``cross_axis_tilt`` and ``axis_tilt``
- :py:func:`pvlib.shading.projected_solar_zenith_angle` parameter ``axis_tilt``
- :py:func:`pvlib.tracking.singleaxis` parameters ``cross_axis_tilt`` and ``axis_tilt``
- :py:func:`pvlib.tracking.calc_surface_orientation` parameter ``axis_tilt``
- :py:func:`!pvlib.tracking.calc_axis_tilt` function is renamed to :py:func:`~pvlib.tracking.calc_axis_slope`
- :py:func:`!pvlib.tracking.calc_cross_axis_tilt` function is renamed to :py:func:`~pvlib.tracking.calc_cross_axis_slope`, and its parameter ``axis_tilt``
- :py:class:`pvlib.pvsystem.SingleAxisTrackerMount` dataclass fields ``axis_tilt`` and ``cross_axis_tilt``

(:issue:`2334`, :pull:`2543`)

Bug fixes
~~~~~~~~~
Expand Down
6 changes: 3 additions & 3 deletions docs/sphinx/source/whatsnew/v0.8.0.rst
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,14 @@ Enhancements
* Added ``racking_model``, ``module_type``, and ``temperature_model_parameters`` to
:py:class:`~pvlib.pvsystem.PVSystem` and :py:class:`~pvlib.tracking.SingleAxisTracker`
repr methods. (:issue:`1027`)
* Added :py:func:`~pvlib.tracking.calc_axis_tilt` to calculate the
tracker axes tilt and :py:func:`~pvlib.tracking.calc_cross_axis_tilt` to
* Added :py:func:`!pvlib.tracking.calc_axis_tilt` to calculate the
tracker axes tilt and :py:func:`!pvlib.tracking.calc_cross_axis_tilt` to
calculate the cross-axis tilt, which is the angle, relative to horizontal, of
the line formed by the intersection between the slope containing the tracker
axes and a plane perpendicular to the tracker axes. (:pull:`823`)
* Added ``cross_axis_tilt`` argument to :py:func:`~pvlib.tracking.singleaxis`
and :py:func:`~pvlib.tracking.SingleAxisTracker` which defaults to zero. Use
:py:func:`~pvlib.tracking.calc_cross_axis_tilt` to calculate the cross-axis
:py:func:`!pvlib.tracking.calc_cross_axis_tilt` to calculate the cross-axis
tilt angle if necessary. (:pull:`823`)
* Added ability for :py:func:`pvlib.soiling.hsu` to accept arbitrary time intervals. (:pull:`980`)
* Added :py:func:`pvlib.temperature.fuentes` for cell temperature modeling. (:pull:`1037`)
Expand Down
2 changes: 1 addition & 1 deletion pvlib/_deprecation.py
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ def renamed_kwarg_warning(since, old_param_name, new_param_name, removal=""):
Not compatible with positional-only arguments.

.. note::
Documentation for the function may updated to reflect the new parameter
Affected function docstring may be updated to reflect the new parameter
name; it is suggested to add a |.. versionchanged::| directive.

Parameters
Expand Down
2 changes: 1 addition & 1 deletion pvlib/modelchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -1257,7 +1257,7 @@ def _prep_inputs_tracking(self):
self.results.solar_position['azimuth'])
self.results.tracking['surface_tilt'] = (
self.results.tracking['surface_tilt']
.fillna(self.system.axis_tilt))
.fillna(self.system.axis_slope))
self.results.tracking['surface_azimuth'] = (
self.results.tracking['surface_azimuth']
.fillna(self.system.axis_azimuth))
Expand Down
Loading