Solar Tracking Art

Art based on variants of the single-axis tracking equations.

This example plays around with the cross-axis tilt parameter of the “slope-aware backtracking” method described in 1).

References

1

Kevin Anderson and Mark Mikofski, “Slope-Aware Backtracking for Single-Axis Trackers”, Technical Report NREL/TP-5K00-76626, July 2020. https://www.nrel.gov/docs/fy20osti/76626.pdf

import pvlib
import pandas as pd
from numpy import sin, cos, arctan2, arccos, radians, degrees, sign, array
import matplotlib.pyplot as plt
import imageio
import io

times = pd.date_range('2019-06-01', '2019-06-02', freq='5s', tz='Etc/GMT+5')
location = pvlib.location.Location(40, -80)
solpos = location.get_solarposition(times)
gcr = 0.5

beta_a = 0
beta_s = radians(solpos.elevation)
gamma_s = radians(solpos.azimuth)

s = array([
    cos(beta_s) * sin(gamma_s),
    cos(beta_s) * cos(gamma_s),
    sin(beta_s)
])

frames = []
for i, beta_c in enumerate(radians(range(-90, 90, 2))):
    fig = plt.figure()
    for gamma_a in radians([0, 180]):
        sp = array([
            s[0] * cos(gamma_a) - s[1] * sin(gamma_a),
            s[0] * sin(gamma_a) * cos(beta_a) + s[1] * cos(beta_a) * cos(gamma_a) - s[2]*sin(beta_a),
            s[0] * sin(gamma_a) * sin(beta_a) + s[1] * sin(beta_a) * cos(gamma_a) + s[2]*cos(beta_a)
        ])
        theta_t = arctan2(sp[0], sp[2])
        theta_t = pd.Series(theta_t, index=times)

        numerator = abs(cos(theta_t - beta_c))
        denominator = gcr * cos(beta_c)
        arg = numerator / denominator
        arg[abs(arg) > 1] = 1
        theta_c = -sign(theta_t) * arccos(arg)
        theta_c[theta_c.isnull() & (beta_s > 0)] = 0
        degrees(theta_t).plot()
        degrees(theta_t + theta_c).plot()

    plt.title(fr"$\beta_c$={degrees(beta_c):0.01f}$\degree$")
    plt.ylabel(r"Tracker Angle [$\degree$]")
    buffer = io.BytesIO()
    plt.savefig(buffer)
    if beta_c == 0:
        # repeat frames at beta_c=0 for visual effect
        for i in range(10):
            frames.append(buffer)
        thumbnail = fig
    else:
        frames.append(buffer)
        plt.close(fig)  # only close if not using for thumbnail

thumbnail.show()
$\beta_c$=0.0$\degree$
with imageio.get_writer('../../images/solar-tracking-art.gif', mode='I') as writer:
    for buffer in frames:
        buffer.seek(0)
        image = imageio.imread(buffer)
        writer.append_data(image)
../../_images/solar-tracking-art.gif

Total running time of the script: ( 1 minutes 26.422 seconds)

Gallery generated by Sphinx-Gallery