.. title: Single-axis tracking and backtracking, part 2
.. slug: single-axis-tracking-and-backtracking-part-2
.. date: 2020-03-15 20:55:45-06:00
.. tags: pv, python
.. category:
.. link:
.. description:
.. type: text
.. has_math: True
The last post showed a simple derivation of the tracking pattern that minimizes
the incidence angle of incoming direct irradiance from the sun. There's just
one problem -- when the sun is at low elevation, adjacent rows shade each
other.
.. TEASER_END
.. image:: /images/self-shading.png
:align: center
For crystalline silicon modules, this is a big problem! The electrical
power loss associated with partial shading is sometimes called "catastrophic"
because shading a small portion of a module results in the majority of the module's
power being lost. For a detailed explanation, check out Mark Mikofski's excellent post
on it `here `_.
Backtracking
------------
So it turns out that our original premise was only part of the story: we should
point the panels towards the sun as directly as possible *while avoiding self-shading*.
Think about the shape of a row's shadow when the sun is at low elevation. If the
row is oriented almost flat, the bottom edge will be fairly high and the top edge
fairly low. Here's an image of two rows rotated at the perfect angle so that the
shadow from one is exactly tangent to the next.
.. image:: /images/backtracking_sideview.png
:align: center
As the sun gets lower in the sky, the rows will have to rotate even closer to
horizontal to avoid self-shading. This behavior is called backtracking because
the rows track backwards in morning and afternoon. Let's derive the backtracking angle!
Here's a helper diagram to get us started. It compares truetracking (positions
:math:`C` and :math:`H`) with backtracking (positions :math:`D` and :math:`F`).
If we can calculate the angle :math:`\angle DAB = \theta_{C}` (the difference between
truetracking and backtracking), adding it to the truetracking position
:math:`\theta_{TT}` will give the backtracking position :math:`\theta_{BT}`.
.. image:: /images/backtracking_diagram.png
:align: center
This is a side-view diagram of two adjacent tracker rows. The rows are
separated by a distance :math:`p` for `pitch` and the height (or "collector
bandwidth" in PVSyst) of each row is :math:`l`.
This visualization is heavily inspired by one in Lorenzo et al.'s "Tracking and
back-tracking" [1]_. The approach to derive :math:`\theta_C` is built on the
fact that triangles :math:`EAB` and :math:`DAB` share side :math:`AB`.
First, let's recognize that :math:`\angle EAB` is the truetracking position :math:`\theta_{TT}`
and triangle :math:`EAB` is a right triangle. We also know by symmetry that
:math:`|EA| = p/2`, where :math:`p` is the pitch or on-center row spacing.
With our old friend soh-cah-toa, that means
.. math::
\cos \theta_{TT} = \frac{|AB|}{|EA|} = \frac{|AB|}{p/2}
Now let's consider triangle :math:`DAB`. By symmetry again, we know that
:math:`|AD| = l/2`, where :math:`l` is the height of the row. Therefore:
.. math::
\cos \theta_C = \frac{|AB|}{|AD|} = \frac{|AB|}{l/2}
Combining the two equations and eliminating :math:`|AB|` gives us:
.. math::
\cos \theta_C = \frac{\cos \theta_{TT}}{l/p} = \frac{\cos \theta_{TT}}{\mathrm{gcr}}
Where :math:`\mathrm{gcr} = l/p` is the ground coverage ratio, the fraction of the ground
that the array covers when it is rotated flat.
Inspection gives a little insight: because :math:`\cos` spans :math:`[-1, 1]`,
our backtracking correction angle :math:`\theta_C` is not defined in the middle
of the day -- :math:`\cos 0 = 1`, and since :math:`\mathrm{gcr} < 1`, that would mean
:math:`\cos \theta_C > 1`, which isn't possible. That makes sense, since in the middle
of the day, there's no self-shading to avoid! Further, the smaller :math:`\mathrm{gcr}`
is, the larger the fraction of the day when there's no need to avoid self-shading.
.. code-block:: python
:number-lines:
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
import pvlib
gcr = 0.5
times = pd.date_range('2019-03-01', '2019-03-02', freq='5min', tz='US/Eastern')
location = pvlib.location.Location(40, -80, tz='US/Eastern')
solpos = location.get_solarposition(times)
solpos = np.radians(solpos)
x = np.sin(solpos.zenith) * np.sin(solpos.azimuth)
z = np.cos(solpos.zenith)
theta_tt = np.arctan2(x, z)
theta_tt[z < 0] = 0
theta_c = np.arccos(np.cos(theta_tt) / gcr)
theta_c[np.isnan(theta_c)] = 0
theta_c[x > 0] *= -1
theta_bt = theta_tt + theta_c
np.degrees(theta_tt).plot(label=r'$\theta_{TT}$')
np.degrees(theta_bt).plot(label=r'$\theta_{BT}$')
plt.legend()
.. image:: /images/tracking_backtracking_plot.png
:align: center
This is the basis of the most common tracking algorithm used in tracker arrays.
It requires array lat and lon for the truetracking position and array gcr for
the backtracking correction angle. The same style of derivation can be used to
generalize the geometry to arrays on N-S slopes, E-W slopes, and shifted
azimuths.
Extra Credit
------------
If you go back and look at the labeled points diagram, you'll notice that there
are actually two distinct positions that prevent self-shading -- the one we already
talked about has the row rotate backwards away from the sun, but it could also
rotate forwards towards the sun until self-shading is eliminated. I've never seen
this strategy mentioned anywhere and in the absence of a pre-existing name for it,
I call it "overtracking". It has exactly the same self-shading characteristics
as backtracking and also has the same beam irradiance collection, but tends to
point the panels down at the ground instead of up at the sky. It also requires
huge tracker angles since the array needs to be able to flip upside down in
morning and evening. The only reason overtracking could ever be better than
normal backtracking would be when there is more diffuse irradiance coming up from
below than down from above -- for example, on the moon where there's no atmosphere.
Here's what it looks like:
.. image:: /images/tracking_backtracking_overtracking_plot.png
:align: center
References
----------
.. [1] Lorenzo, E et al., 2011, "Tracking and back-tracking", Prog. in
Photovoltaics: Research and Applications, v. 19, pp. 747-753.