pvlib / pvlib-python

A set of documented functions for simulating the performance of photovoltaic energy systems.
https://pvlib-python.readthedocs.io
BSD 3-Clause "New" or "Revised" License
1.16k stars 985 forks source link

Ambiguous descriptions of axis_azimuth and axis_tilt in pvlib.tracking.singleaxis() docs #1976

Open williamhobbs opened 7 months ago

williamhobbs commented 7 months ago

Is your feature request related to a problem? Please describe. Some details around _axisazimuth and _axistilt in the docs (https://pvlib-python.readthedocs.io/en/stable/reference/generated/pvlib.tracking.singleaxis.html) seem ambiguous to me.

Examples:

  1. For a north-south aligned tracker axis, sloping 5 degrees down to the south, what are the inputs for _axisazimuth and _axistilt? I assume _axisazimuth = 180, _axistilt = 5.
  2. For the same north-south aligned tracker axis, but sloping 5 degrees down to the north, what are the inputs? I assume _axisazimuth = 0, _axistilt = 5, since _axistilt must be >= 0.

Additionally, the description in the docs includes:

For example, if tracker _axisazimuth is 180 (oriented south) and _axistilt is zero...

But the default for _axisazimuth is 0, which could lead to confusion around inputs and output sign convention.

Describe the solution you'd like More clear docs.

Additional context Changing definitions slightly and allowing for negative _axistilt would make more sense to me, but maybe that causes other problems. [edit: now I don't think this is a good idea - see the full discussion below] [2nd edit: looks like code allows for this even though docs do not. Also, my opinion is easily swayed...]

For example # 2 above (sloping down to the North), allowing for _axisazimuth = 180, _axistilt = -5 makes more since to me. You could unambigously define _axisazimuth as "the South-most direction of the axis of rotation" and _axistilt as "the tilt of the axis of rotation, with positive values indicating downward slope towards the South-most direction, and negative values indicating downward slope towards the North-most direction...".

I'm not sure how to handle the odd case of a tracker axis aligned perfectly East-West.

And for systems in the Southern Hemisphere, I don't think anything would need to change.

mikofski commented 7 months ago

Another argument for allowing negative axis tilt is to keep the common convention that rotation increases during the day, from negative in the morning when facing east to positive in the afternoon & trackers facing west. I think this only works if the axis points south?

williamhobbs commented 7 months ago

@mikofski, I agree. Good point.

Keeping a consistent rotation convention makes more sense to me than (the way I interpret) the existing docs for pvlib.tracking.singleaxis(): _trackertheta sign reverses depending on whether you pick 0 or 180 for _axisazimuth.

williamhobbs commented 7 months ago

I just ran some tests in NREL SAM using both the detailed PV model and the PVWatts model - in both cases, it does not allow tilt for 1-axis trackers to be less than zero.

The documentation there is also not clear, but it appears that azimuth = 0 and tilt = 5 models a system sloping down to the north, while azimuth = 180 and tilt = 5 models a system sloping down to the south.

So, I can now see a benefit to keeping the conventions in pvlib.tracking.singleaxis() as they are and simply updating the docs a bit. But @mikofski's point about rotation angle convention is still a good one...

janinefreeman commented 7 months ago

I left a comment on the SAM issue as well, but allowing negative input tilts would require some additional mathematical gymnastics inside the functions to make angle calculations and shading calculations work out (I'm assuming this is true for pvlib as well) - at the very least, transposition to the expected case before doing the math (i.e. if a user enters azimuth = 180, tilt = -5, the code would need to translate that to azimuth = 0, tilt = 5, then correctly re-translate the outputs). I have wondered about this issue of "how to explain which end of the tracker is the rotation around" before, since right now it follows mathematical rotational axis definitions, rather than cardinal direction conventions, that certainly aren't intuitive for most. Open to ideas here on the best way to communicate what tracker rotation angles mean...

Thanks @williamhobbs for linking the issues so we can brainstorm collectively! :)

williamhobbs commented 7 months ago

Keeping conventions the same between pvlib and SAM seems like it would be very beneficial to users.

The rotation "convention" of negative in the morning, positive in the afternoon, would stay reversed in the case of sloping down to the North, but 1) this can be clarified in docs, and 2) is likely a pretty rare case. I think anyone that is modeling an atypical system like this and needs to carefully interpret _trackertheta is already pretty far into the "weeds" and can probable make sense of it all with decent docs.

mikofski commented 7 months ago

@williamhobbs please just try it with negative axis_tilt and see if it works already as expected. I looked through the code here: https://github.com/pvlib/pvlib-python/blob/main/pvlib/tracking.py and I don’t see anything other than the docstring that limits it between zero and 90°. @janinefreeman I believe pvlib should just work even if axis tilt is negative without any changes at all because singleaxis() used arctan2 instead of cosine so should work in any quadrant.

AdamRJensen commented 7 months ago

I would vote in favor of allowing negative tilts, and thus allowing the standard convention of negative morning and positive evening tilts.

I could easily imagine simulations of larger systems (where the field is broken down into several sub-systems of uniform tilt) where one part of the field is sloping north and another is sloping south. In such a case it would be inconvenient having different axis azimuth conventions for different parts of the field.

williamhobbs commented 7 months ago

@mikofski you are correct, it works with negative _axistilt.

image

(edit: code below)

import pvlib
import matplotlib.pyplot as plt
import pandas as pd

lat, lon = 33.52, -86.81
tz = 'US/Central'

times = pd.date_range('2023-12-21 5:00',
                      '2023-12-21 18:00',
                      freq='5min',
                      tz=tz)

solpos = pvlib.solarposition.get_solarposition(times, lat, lon)

angles_1 = pvlib.tracking.singleaxis(
    apparent_zenith=solpos['apparent_zenith'],
    apparent_azimuth=solpos['azimuth'],
    axis_tilt=0,
    axis_azimuth=180,
    max_angle=50,
    backtrack=True,
    gcr=0.45
)['tracker_theta'].fillna(0)

angles_2 = pvlib.tracking.singleaxis(
    apparent_zenith=solpos['apparent_zenith'],
    apparent_azimuth=solpos['azimuth'],
    axis_tilt=10,
    axis_azimuth=180,
    max_angle=50,
    backtrack=True,
    gcr=0.45
)['tracker_theta'].fillna(0)

angles_3 = pvlib.tracking.singleaxis(
    apparent_zenith=solpos['apparent_zenith'],
    apparent_azimuth=solpos['azimuth'],
    axis_tilt=-10,
    axis_azimuth=0,
    max_angle=50,
    backtrack=True,
    gcr=0.45
)['tracker_theta'].fillna(0)

angles_1.plot()
angles_2.plot()
angles_3.plot()
plt.legend(['tilt=0, az=180', 'tilt=10, az=180', 'tilt=-10, az=0'])
plt.ylabel('Tracker rotation angle, degrees')
plt.xlabel('Local time')
plt.show()
williamhobbs commented 7 months ago

Since negative values of _axistilt are allowed in the code, it seems like users can use either convention and the docs simply need to be updated accordingly. And part of that is noting that if users select _axisazimuth between 270 and 90 (North-facing), the rotation angle convention is reversed.

cwhanse commented 7 months ago

I'm OK with negative axis tilt, as long as the definition of axis_tilt and axis_azimuth are not dependent on hemisphere, and together unambiguously define the coordinate system that defines rotation. I'd be opposed to start with a desired rotation convention (e.g. negative is east) because I'm fairly sure that will make the coordinate system depend on hemisphere.

matsuobasho commented 6 months ago

Taking the above discussion into account, if we specify an axis_azimuth of 0 and an axis_tilt of -5, what does that mean in terms of the positioning of the trackers?

From the way the docstring is currently worded The tilt of the axis of rotation (i.e, the y-axis defined by axis_azimuth) with respect to horizontal. seems like it would be a confusing situation where we specify that the azimuth is 0 (point towards north), but also specify that there is a -5 degree tilt, meaning that the slope is actually towards the south?