Skip to content

Commit e03611c

Browse files
authored
Merge pull request #96 from cse-sim/single-axis-tracker
Fix single axis tracker algorithm
2 parents 7ab7a1b + 0f3a2a5 commit e03611c

File tree

17 files changed

+19340
-19320
lines changed

17 files changed

+19340
-19320
lines changed

doc/src/media/pv_fixed.png

71.9 KB
Loading
95 KB
Loading
85.6 KB
Loading
87.6 KB
Loading

doc/src/records/pvarray.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,16 @@ The tilt of the photovoltaic array from horizontal. Values outside the range 0
102102
else 0
103103
------------------------------------------------------------------
104104

105+
The following figures illustrate the use of both pvTilt and pvAzm for various configurations:
106+
107+
![Fixed, south facing, tilted at 40^o^](media/pv_fixed.png)
108+
109+
![One-axis tracker, south facing, tilted at 20^o^](media/pv_tilted_tracker_south.png)
110+
111+
![One-axis tracker, horizontal aligned North/South (more common)](media/pv_horiz_tracker_south.png)
112+
113+
![One-axis tracker, horizontal aligned East/West (less common)](media/pv_horiz_tracker_east.png)
114+
105115
**pvAzm=*float***
106116

107117
Photovoltaic array azimuth (0 = north, 90 = east, etc.). If a value outside the range 0^o^ $\leq$ *x* $<$ 360^o^ is given, it is normalized to that range. For one-axis tracking, defines the azimuth of the rotation axis. Not used for two-axis tracking arrays. Should be omitted if pvVertices is given.

src/CNRECS.DEF

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4454,6 +4454,7 @@ RECORD PVARRAY "PVArray" *RAT // input / runtime photovoltaics array
44544454
*h *e FLOAT pv_aoi // angle of incidence (radians)
44554455
*h *e ANGLE pv_panelTilt // tilt of pv panel (different from array tilt for tracking systems), radians
44564456
*h *e ANGLE pv_panelAzm // azimuth of pv panel (different from array tilt for tracking systems), radians
4457+
*h *e ANGLE pv_panelRot // rotation of pv panel for 1-axis tracking systems, radians clockwise from vertical
44574458
*h *e FLOAT pv_poa // plane of array incidence (before shading), Btu/h-ft2
44584459
*h *e FLOAT pv_poaBeam // plane of array beam incidence (before shading), Btu/h-ft2
44594460
*h *e FLOAT pv_radIBeam // beam radiation incident on array, Btu/h-ft2

src/PVCalc.cpp

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -303,35 +303,44 @@ RC PVARRAY::pv_CalcPOA()
303303
{
304304
case C_PVARRCH_1AXT:
305305
{
306-
float sinz = sin(acos(cosz));
307-
float x = (sinz*sin(azm - pv_azm)) / (sinz*cos(azm - pv_azm)*sin(pv_tilt) + cosz*cos(pv_tilt));
308-
float psi;
309-
if (x < 0.f && (azm - pv_azm) > 0.f) {
306+
// Based on Rotation Angle for the Optimum Tracking of One-Axis Trackers by William F.Marion and Aron P.Dobos
307+
const float sinz = sin(acos(cosz)); // sin of zenith angle
308+
float azm_delta = azm - pv_azm;
309+
310+
// normalize azm_delta between -Pi and Pi
311+
if (azm_delta >= kPi)
312+
azm_delta = azm_delta - k2Pi;
313+
314+
if (azm_delta <= -kPi)
315+
azm_delta = azm_delta + k2Pi;
316+
317+
const float x = (sinz*sin(azm_delta)) / (sinz*cos(azm_delta)*sin(pv_tilt) + cosz*cos(pv_tilt)); // from Equation #7
318+
float psi = 0.f;
319+
320+
if (x < 0.f && azm_delta > 0.f) {
310321
psi = kPi;
311322
}
312-
else if (x > 0.f && (azm - pv_azm) < 0.f){
323+
else if (x > 0.f && azm_delta < 0.f){
313324
psi = -kPi;
314325
}
315-
else {
316-
psi = 0.f;
317-
}
318-
float r = atan(x) + psi;
326+
327+
pv_panelRot = atan(x) + psi; // Equation #7
328+
319329
const float rlim = 0.25f*kPi;
320-
r = max(-rlim, min(rlim, r));
321-
pv_panelTilt = acos(cos(r)*cos(pv_tilt));
330+
pv_panelRot = max(-rlim, min(rlim, pv_panelRot));
331+
pv_panelTilt = acos(cos(pv_panelRot)*cos(pv_tilt)); // Equation #1
322332
if (pv_panelTilt == 0.f) {
323333
pv_panelAzm = pv_azm;
324334
}
325335
else
326336
{
327-
float rx = bracket(-1.f, sin(r) / sin(pv_panelTilt), 1.f);
328-
float asrx = asin(rx);
329-
if (r >= -kPiOver2 && r <= kPiOver2)
330-
pv_panelAzm = pv_azm + asrx;
331-
else if (r >= -kPi && r < -kPiOver2)
332-
pv_panelAzm = pv_azm - asrx - kPi;
333-
else // if (r > kPiOver2 && r <= kPi)
334-
pv_panelAzm = pv_azm - asrx + kPi;
337+
float const asrx = asin(bracket(-1.f, sin(pv_panelRot) / sin(pv_panelTilt), 1.f));
338+
if (pv_panelRot >= -kPiOver2 && pv_panelRot <= kPiOver2)
339+
pv_panelAzm = pv_azm + asrx; // Equation #2
340+
else if (pv_panelRot >= -kPi && pv_panelRot < -kPiOver2)
341+
pv_panelAzm = pv_azm - asrx - kPi; // Equation #3
342+
else // if (pv_panelRot > kPiOver2 && pv_panelRot <= kPi)
343+
pv_panelAzm = pv_azm - asrx + kPi; // Equation #4
335344
}
336345
}
337346
break;

0 commit comments

Comments
 (0)