Skip to content

Commit

Permalink
Find solar noon directly from maximum clearsky POA
Browse files Browse the repository at this point in the history
When identifying the tilt and azimuth in `system.orientation()` we
calculate solar noon on each day by fitting a quadratic to the power
or irradiance measurements and comparing this to solar noon for
clearsky POA irradiance at different orientations. Rather than fitting
a quadratic to the daily clearsky POA irradiance and using the vertex
of the quadratic as solar noon this commit uses the maximum POA value
for the day. The idea is that curve fitting is unnecessary---because
clearsky POA has no noise or interference we can identify solar noon
directly from the data. This matches the methodology in PVFleets QA
and should improve performance; however, using the maximum POA
directly can reduce the accuracy of the tilt & azimuth that are
returned if the frequency of clearsky data is low. In general the best
accuracy can be obtained by passing one-minute clearsky and solar
position data.

Because of the reduced accuracy with low-frequency clearsky data the
unit tests needed to be updated. Rather than extending the range of
'okay' tilt/azimuth values I elected to pass one minute clearsky. For
one-minute data we know that the accuracy should be +/- 10 degrees.
  • Loading branch information
wfvining committed Jul 27, 2020
1 parent ada4790 commit dfe8947
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 16 deletions.
2 changes: 1 addition & 1 deletion pvanalytics/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ def orientation(power_or_poa, daytime, tilts, azimuths,
dni=dni
).poa_global
poa_azimuths = azimuth_by_minute[
_peak_times(poa[solar_zenith < 70])
_group.by_day(poa).idxmax()
]
sum_of_squares = sum(
(poa_azimuths.values - modeled_azimuth.values)**2
Expand Down
48 changes: 33 additions & 15 deletions pvanalytics/tests/test_system.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
"""Tests for system paramter identification functions."""
import pytest
import pandas as pd
from pvlib import irradiance
from pvanalytics import system
Expand All @@ -9,7 +10,34 @@ def _assert_within(x, expected, margin):
assert x in range(expected - margin, expected + margin + 1)


def test_simple_poa_orientation(clearsky_year, solarposition_year):
@pytest.fixture(scope='module')
def fine_index(clearsky_year):
"""DatetimeIndex for the same period as `clearsky_year` but with 1
minute frequency."""
return pd.date_range(
start=clearsky_year.index.min(),
end=clearsky_year.index.max(),
freq='T'
)


@pytest.fixture(scope='module')
def fine_clearsky(albuquerque, fine_index):
"""Clearsky in Albuquerque with 1 minute timestamp spacing."""
return albuquerque.get_clearsky(
fine_index,
model='simplified_solis'
)


@pytest.fixture(scope='module')
def fine_solarposition(albuquerque, fine_index):
"""Solar position in Albuquerque with 1 minute timestamp spacing."""
return albuquerque.get_solarposition(fine_index)


def test_simple_poa_orientation(clearsky_year, solarposition_year,
fine_clearsky, fine_solarposition):
poa = irradiance.get_total_irradiance(
surface_tilt=15,
surface_azimuth=180,
Expand All @@ -21,10 +49,10 @@ def test_simple_poa_orientation(clearsky_year, solarposition_year):
poa['poa_global'],
tilts=range(5, 25, 5),
azimuths=range(150, 200, 5),
solar_zenith=solarposition_year['apparent_zenith'],
solar_azimuth=solarposition_year['azimuth'],
solar_zenith=fine_solarposition['apparent_zenith'],
solar_azimuth=fine_solarposition['azimuth'],
daytime=solarposition_year['apparent_zenith'] < 87,
**clearsky_year
**fine_clearsky
)
_assert_within(azimuth, 180, 10)
_assert_within(tilt, 15, 10)
Expand All @@ -45,7 +73,7 @@ def test_ghi_tilt_zero(clearsky_year, solarposition_year):


def test_azimuth_different_index(clearsky_year, solarposition_year,
albuquerque):
fine_clearsky, fine_solarposition):
"""Can use solar position and clearsky with finer time-resolution to
get an accurate estimate of tilt and azimuth."""
poa = irradiance.get_total_irradiance(
Expand All @@ -55,16 +83,6 @@ def test_azimuth_different_index(clearsky_year, solarposition_year,
solar_zenith=solarposition_year['apparent_zenith'],
solar_azimuth=solarposition_year['azimuth']
)
fine_index = pd.date_range(
start=clearsky_year.index.min(),
end=clearsky_year.index.max(),
freq='1T'
)
fine_solarposition = albuquerque.get_solarposition(fine_index)
fine_clearsky = albuquerque.get_clearsky(
fine_index,
model='simplified_solis'
)
azimuth, tilt = system.orientation(
poa['poa_global'],
daytime=solarposition_year['apparent_zenith'] < 87,
Expand Down

0 comments on commit dfe8947

Please sign in to comment.