Skip to content

Commit b212fff

Browse files
kperrynrelPerrykandersolarcwhanse
authored
System module sphinx documentation (#146)
* Added dummy files for the system module documentation. * Added new examples for system tracking. * updated the system tracking docs. * adding docs * updates to the routines for system module * updated the routines for tracking module * cleaned up doc strings + added example SERF East data. * updated the whatsnew docs * Updated the pvwatts routine to use PSM3 data * added psm3 csv * reduced size of the serf east fiel to 10k rows * removed duplicate csv file * added the system ID to OEDI documentation * update the system ID for OEDI * Update docs/examples/infer-orientation-daily-peak.py Co-authored-by: Kevin Anderson <[email protected]> * Update docs/examples/infer-orientation-fit-pvwatts.py Co-authored-by: Kevin Anderson <[email protected]> * changes to documentation based on @kandersonrel's review * Update docs/examples/infer-orientation-fit-pvwatts.py Co-authored-by: Kevin Anderson <[email protected]> * updated the docstring to avoid pep8 errors> * update the csv name * removed the daily peak documentation. * reformatting for release 0.1.3 * updated pvwatts model docstring * added oedi reference to tracking system documentation * removed redundant file directory definition * Added readme for the system examples * update the naming for pvwatts model * Add visualizations for the documentation (plot first few days of time series) * updated docstrings in final review * fix flake8 issues * added back missing text in whats new 0.1.2 * Update docs/examples/system/infer-orientation-fit-pvwatts.py Co-authored-by: Cliff Hansen <[email protected]> Co-authored-by: Perry <[email protected]> Co-authored-by: Kevin Anderson <[email protected]> Co-authored-by: Cliff Hansen <[email protected]>
1 parent 83500ac commit b212fff

File tree

7 files changed

+19590
-1
lines changed

7 files changed

+19590
-1
lines changed

docs/examples/system/README.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
System
2+
------
3+
4+
This includes examples for system parameter estimation, including azimuth and tilt estimation, and determination if the system is fixed tilt or tracking.
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
"""
2+
Infer Array Tilt/Azimuth - PVWatts Method
3+
=========================================
4+
5+
Infer the azimuth and tilt of a system using PVWatts-based methods
6+
"""
7+
8+
# %%
9+
# Identifing and/or validating the azimuth and tilt information for a
10+
# system is important, as these values must be correct for degradation
11+
# and system yield analysis. This example shows how to use
12+
# :py:func:`pvanalytics.system.infer_orientation_fit_pvwatts` to estimate
13+
# a fixed-tilt system's azimuth and tilt, using the system's known
14+
# latitude-longitude coordinates and an associated AC power time series.
15+
16+
import pvanalytics
17+
import matplotlib.pyplot as plt
18+
from pvanalytics import system
19+
import pandas as pd
20+
import pathlib
21+
import pvlib
22+
23+
# %%
24+
# First, we import an AC power data stream from the SERF East site located at
25+
# NREL. This data set is publicly available via the PVDAQ database in the
26+
# DOE Open Energy Data Initiative (OEDI)
27+
# (https://data.openei.org/submissions/4568), under system ID 50.
28+
# This data is timezone-localized.
29+
30+
pvanalytics_dir = pathlib.Path(pvanalytics.__file__).parent
31+
ac_power_file = pvanalytics_dir / 'data' / 'serf_east_15min_ac_power.csv'
32+
data = pd.read_csv(ac_power_file, index_col=0, parse_dates=True)
33+
data = data.sort_index()
34+
time_series = data['ac_power']
35+
time_series = time_series.asfreq('15T')
36+
37+
# Plot the first few days of the time series to visualize it
38+
time_series[:pd.to_datetime("2016-07-06 00:00:00-07:00")].plot()
39+
plt.show()
40+
41+
# Outline the ground truth metadata associated with the system
42+
latitude = 39.742
43+
longitude = -105.1727
44+
actual_azimuth = 158
45+
actual_tilt = 45
46+
47+
# %%
48+
# Next, we import the PSM3 data generated via the
49+
# :py:func:`pvlib.iotools.get_psm3` function, using
50+
# site latitude-longitude coordinates. To generate the
51+
# PSM3 data, you must first register for NREL's NSDRB API at the
52+
# following link: https://developer.nrel.gov/signup/.
53+
# PSM3 data can then be retrieved using :py:func:`pvlib.iotools.get_psm3`.
54+
# The PSM3 data has been resampled to 15 minute intervals, to match the AC
55+
# power data.
56+
57+
psm3_file = pvanalytics_dir / 'data' / 'serf_east_psm3_data.csv'
58+
psm3 = pd.read_csv(psm3_file, index_col=0, parse_dates=True)
59+
60+
# %%
61+
# Filter the PSM3 data to only include clearsky periods
62+
is_clear = (psm3.ghi_clear == psm3.ghi)
63+
is_daytime = (psm3.ghi > 0)
64+
time_series_clearsky = time_series[is_clear & is_daytime]
65+
time_series_clearsky = time_series_clearsky.dropna()
66+
psm3_clearsky = psm3.loc[time_series_clearsky.index]
67+
68+
# Get solar azimuth and zenith from pvlib, based on
69+
# lat-long coords
70+
solpos_clearsky = pvlib.solarposition.get_solarposition(
71+
time_series_clearsky.index, latitude, longitude)
72+
73+
# %%
74+
# Run the pvlib data and the sensor-based time series data through
75+
# the :py:func:`pvanalytics.system.infer_orientation_fit_pvwatts` function.
76+
best_tilt, best_azimuth, r2 = system.infer_orientation_fit_pvwatts(
77+
time_series_clearsky,
78+
psm3_clearsky.ghi_clear,
79+
psm3_clearsky.dhi_clear,
80+
psm3_clearsky.dni_clear,
81+
solpos_clearsky.zenith,
82+
solpos_clearsky.azimuth,
83+
temperature=psm3_clearsky.temp_air,
84+
)
85+
86+
# Compare actual system azimuth and tilt to predicted azimuth and tilt
87+
print("Actual Azimuth: " + str(actual_azimuth))
88+
print("Predicted Azimuth: " + str(best_azimuth))
89+
print("Actual Tilt: " + str(actual_tilt))
90+
print("Predicted Tilt: " + str(best_tilt))
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
"""
2+
Detect if a System is Tracking
3+
==============================
4+
5+
Identifying if a system is tracking or fixed tilt
6+
"""
7+
8+
# %%
9+
# It is valuable to identify if a system is fixed tilt or tracking for
10+
# future analysis. This example shows how to use
11+
# :py:func:`pvanalytics.system.is_tracking_envelope` to determine if a
12+
# system is tracking or not by fitting data to a maximum power or
13+
# irradiance envelope, and fitting this envelope to quadratic and
14+
# quartic curves. The r^2 output from these fits is used to determine
15+
# if the system fits a tracking or fixed-tilt profile.
16+
17+
import pvanalytics
18+
from pvanalytics.system import is_tracking_envelope
19+
from pvanalytics.features.clipping import geometric
20+
from pvanalytics.features.daytime import power_or_irradiance
21+
import pandas as pd
22+
import pathlib
23+
import matplotlib.pyplot as plt
24+
25+
# %%
26+
# First, we import an AC power data stream from the SERF East site located at
27+
# NREL. This data set is publicly available via the PVDAQ database in the
28+
# DOE Open Energy Data Initiative (OEDI)
29+
# (https://data.openei.org/submissions/4568), under system ID 50.
30+
# This data is timezone-localized. This particular data stream is associated
31+
# with a fixed-tilt system.
32+
33+
pvanalytics_dir = pathlib.Path(pvanalytics.__file__).parent
34+
ac_power_file = pvanalytics_dir / 'data' / \
35+
'serf_east_15min_ac_power.csv'
36+
data = pd.read_csv(ac_power_file, index_col=0, parse_dates=True)
37+
data = data.sort_index()
38+
time_series = data['ac_power']
39+
time_series = time_series.asfreq('15T')
40+
41+
# Plot the first few days of the time series to visualize it
42+
time_series[:pd.to_datetime("2016-07-06 00:00:00-07:00")].plot()
43+
plt.show()
44+
45+
# %%
46+
# Run the clipping and the daytime filters on the time series.
47+
# Both of these masks will be used as inputs to the
48+
# :py:func:`pvanalytics.system.is_tracking_envelope` function.
49+
50+
# Generate the daylight mask for the AC power time series
51+
daytime_mask = power_or_irradiance(time_series)
52+
53+
# Generate the clipping mask for the time series
54+
clipping_mask = geometric(time_series)
55+
56+
# %%
57+
# Now, we use :py:func:`pvanalytics.system.is_tracking_envelope` to
58+
# identify if the data stream is associated with a tracking or fixed-tilt
59+
# system.
60+
61+
predicted_mounting_config = is_tracking_envelope(time_series,
62+
daytime_mask,
63+
clipping_mask)
64+
65+
print("Estimated mounting configuration: " + predicted_mounting_config.name)

docs/whatsnew/0.1.2.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ Other
6363
* Removed empty modules ``pvanalytics.filtering`` and ``pvanalytics.fitting``
6464
until the relevant functionality is added to the package. (:pull:`145`)
6565

66-
6766
Contributors
6867
~~~~~~~~~~~~
6968

docs/whatsnew/0.1.3.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,11 @@ Added new gallery example pages:
3232
* :py:func:`~pvanalytics.quality.weather.relative_humidity_limits`
3333
* :py:func:`~pvanalytics.quality.weather.wind_limits`
3434
* :py:func:`~pvanalytics.quality.weather.module_temperature_check`
35+
36+
* ``pvanalytics.system`` (:issue:`133`, :pull:`146`):
37+
38+
* :py:func:`~pvanalytics.system.infer_orientation_fit_pvwatts`
39+
* :py:func:`~pvanalytics.system.is_tracking_envelope`
3540

3641
* ``pvanalytics.quality.irradiance.calculate_component_sum_series``(:issue:`157`, :pull:`163`)
3742

0 commit comments

Comments
 (0)