Open williamhobbs opened 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?
@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.
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...
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! :)
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.
@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.
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.
@mikofski you are correct, it works with negative _axistilt.
(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()
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.
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.
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?
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:
Additionally, the description in the docs includes:
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.