This page was generated from /home/docs/checkouts/readthedocs.org/user_builds/pvcaptest/checkouts/v0.13.2/docs/examples/concise_capacity_test.ipynb.
Interactive online version:
Concise Example Capacity Test using pvcaptest
This example performs the same test as the Complete Capacity Testing example, but uses the run_test function to apply the filters and then displays the filtering steps visually using the scatter_filters method.
Imports
[1]:
import warnings
warnings.filterwarnings('ignore')
import pandas as pd
# import captest as pvc
import captest as ct
from captest import capdata as pvc
from bokeh.io import output_notebook, show
# uncomment below two lines to use cptest.scatter_hv in notebook
import holoviews as hv
hv.extension('bokeh')
#if working offline with the CapData.plot() method may fail
#run 'export BOKEH_RESOURCES=inline' at the command line before
#running the jupyter notebook
output_notebook()
Load and Plot Measured Data
Load the measured data with the load_data method, which returns a CapData object. This example uses a column grouping defined in an excel file.
[2]:
das = ct.load_data('./data/example_meas_data.csv', group_columns='./data/column_groups.xlsx')
[3]:
das.column_groups
[3]:
irr_ghi:
Example Project_Weather Station 1 (Standard w/ POA GHI)_Weather Station 1 (Standard w/ POA GHI), Sun2_W/m^2
Example Project_Weather Station 2 (Standard with POA GHI)_Weather Station 2 (Standard with POA GHI), Sun2_W/m^2
irr_poa:
Example Project_Weather Station 1 (Standard w/ POA GHI)_Weather Station 1 (Standard w/ POA GHI), Sun_W/m^2
Example Project_Weather Station 2 (Standard with POA GHI)_Weather Station 2 (Standard with POA GHI), Sun_W/m^2
real_pwr_inv:
Example Project_Inverter 1_Inverter 1, KW_kW
Example Project_Inverter 2_Inverter 2, KW_kW
Example Project_Inverter 3_Inverter 3, KW_kW
Example Project_Inverter 4_Inverter 4, KW_kW
Example Project_Inverter 5_Inverter 5, KW_kW
Example Project_Inverter 6_Inverter 6, KW_kW
Example Project_Inverter 7_Inverter 7, KW_kW
Example Project_Inverter 8_Inverter 8, KW_kW
real_pwr_mtr:
Example Project_Elkor Production Meter_Elkor Production Meter, KW_kW
temp_amb:
Example Project_Weather Station 1 (Standard w/ POA GHI)_Weather Station 1 (Standard w/ POA GHI), Temp1_çF
Example Project_Weather Station 2 (Standard with POA GHI)_Weather Station 2 (Standard with POA GHI), Temp1_çF
temp_bom:
Example Project_Weather Station 1 (Standard w/ POA GHI)_Weather Station 1 (Standard w/ POA GHI), TempF_çF
Example Project_Weather Station 2 (Standard with POA GHI)_Weather Station 2 (Standard with POA GHI), TempF_çF
wind:
Example Project_Weather Station 1 (Standard w/ POA GHI)_Weather Station 1 (Standard w/ POA GHI), WindSpeed_mph
Example Project_Weather Station 2 (Standard with POA GHI)_Weather Station 2 (Standard with POA GHI), WindSpeed_mph
[4]:
das.set_regression_cols(power='real_pwr_mtr', poa='irr_poa', t_amb='temp_amb', w_vel='wind')
[5]:
das.agg_sensors(agg_map={'real_pwr_inv':'sum', 'irr_poa':'mean', 'temp_amb':'mean', 'wind':'mean'})
Regression variable 'poa' has been remapped: 'irr_poa' to 'irr_poa_mean_agg'
Regression variable 't_amb' has been remapped: 'temp_amb' to 'temp_amb_mean_agg'
Regression variable 'w_vel' has been remapped: 'wind' to 'wind_mean_agg'
Note, the full functionality of the dashboard requires a live notebook. Try installing to run or using the launch binder button at the top of the page.
[6]:
combine = {'inv_sum_mtr_pwr': ['mtr', 'inv.*agg'], 'irr_all':['irr_poa', 'irr_ghi'], 'temp_all':['temp_amb', 'temp_mod']}
default_groups = ['inv_sum_mtr_pwr', 'irr_all', 'temp_all']
das.plot(combine=combine, default_groups=default_groups)
[6]:
Filtering Measured Data
The CapData class provides a number of convience methods to apply filtering steps as defined in ASTM E2848. The following section demonstrates the use of the more commonly used filtering steps to remove measured data points.
[7]:
# Uncomment and run to copy over the filtered dataset with the unfiltered data.
das.reset_filter()
[8]:
measured_filters = [
(pvc.CapData.filter_sensors, (), {}),
(pvc.CapData.filter_custom, (pd.DataFrame.dropna, ), {}),
(pvc.CapData.filter_irr, (200, 2000), {}),
(pvc.CapData.filter_outliers, (), {}),
(pvc.CapData.fit_regression, (), {'filter':True, 'summary':False}),
(pvc.CapData.rep_cond, (), {}),
(pvc.CapData.filter_irr, (0.5, 1.5), {'ref_val':'self_val'}),
(pvc.CapData.fit_regression, (), {}),
]
[9]:
pvc.run_test(das, measured_filters)
NOTE: Regression used to filter outlying points.
Reporting conditions saved to rc attribute.
poa t_amb w_vel
0 762.726562 47.967849 1.988983
OLS Regression Results
=======================================================================================
Dep. Variable: power R-squared (uncentered): 1.000
Model: OLS Adj. R-squared (uncentered): 1.000
Method: Least Squares F-statistic: 4.299e+05
Date: Fri, 18 Jul 2025 Prob (F-statistic): 0.00
Time: 03:00:19 Log-Likelihood: -3646.9
No. Observations: 293 AIC: 7302.
Df Residuals: 289 BIC: 7317.
Df Model: 4
Covariance Type: nonrobust
==================================================================================
coef std err t P>|t| [0.025 0.975]
----------------------------------------------------------------------------------
poa 7691.8940 50.543 152.187 0.000 7592.416 7791.372
I(poa * poa) 1.5976 0.106 15.072 0.000 1.389 1.806
I(poa * t_amb) -51.9936 2.294 -22.666 0.000 -56.509 -47.479
I(poa * w_vel) 14.2147 4.469 3.181 0.002 5.419 23.010
==============================================================================
Omnibus: 71.503 Durbin-Watson: 0.672
Prob(Omnibus): 0.000 Jarque-Bera (JB): 152.277
Skew: -1.218 Prob(JB): 8.58e-34
Kurtosis: 5.558 Cond. No. 9.17e+03
==============================================================================
Notes:
[1] R² is computed without centering (uncentered) since the model does not contain a constant.
[2] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[3] The condition number is large, 9.17e+03. This might indicate that there are
strong multicollinearity or other numerical problems.
[10]:
das.get_summary()
[10]:
| pts_after_filter | pts_removed | filter_arguments | ||
|---|---|---|---|---|
| meas | filter_sensors | 1245 | 195 | Default arguments |
| filter_custom | 1240 | 5 | DataFrame.dropna, , | |
| filter_irr | 424 | 816 | 200, 2000, | |
| filter_outliers | 407 | 17 | Default arguments | |
| fit_regression | 385 | 22 | filter: True, summary: False | |
| rep_cond | 385 | 0 | Default arguments | |
| filter_irr-1 | 293 | 92 | 0.5, 1.5, ref_val: self_val | |
| fit_regression-1 | 293 | 0 | Default arguments |
[11]:
das_scatter = das.scatter_filters()
das_scatter
[11]:
[12]:
das.timeseries_filters().opts(width=1200)
[12]:
Load and Filter PVsyst Data
To load and filter the modeled data, often from PVsyst, we simply create a new CapData object, load the PVsyst data, and apply the filtering methods as appropriate.
To load pvsyst data we use the load_data method with the load_pvsyst option set to True. By default the load_data method will search for a csv file that includes pvsyst in the filename in a data directory in the same directory as this file. If you have saved the pvsyst file in a different location, you can use the path and fname arguments to load it.
[13]:
sim = ct.load_pvsyst('./data/pvsyst_example_HourlyRes_2.CSV')
[14]:
sim.column_groups
[14]:
index__:
index
real_pwr__:
E_Grid
shade__:
FShdBm
wind__:
WindVel
irr_poa_:
GlobInc
pvsyt_losses__:
IL Pmax
IL Pmin
IL Vmax
IL Vmin
irr_ghi_:
GlobHor
temp_mod_:
TArray
temp_amb_:
T_Amb
_inv_:
EOutInv
[15]:
sim.set_regression_cols(power='real_pwr__', poa='irr_poa_', t_amb='temp_amb_', w_vel='wind__')
[16]:
# Write over cptest.flt_sim dataframe with a copy of the original unfiltered dataframe
sim.reset_filter()
[17]:
simulated_filters = [
(pvc.CapData.filter_time, (), {'test_date':'10/11/1990', 'days':60}),
(pvc.CapData.filter_irr, (200, 930), {}),
(pvc.CapData.filter_pvsyst, (), {}),
(pvc.CapData.filter_irr, (0.5, 1.5), {'ref_val':das.rc['poa'][0]}),
(pvc.CapData.fit_regression, (), {}),
]
[18]:
pvc.run_test(sim, simulated_filters)
OLS Regression Results
=======================================================================================
Dep. Variable: power R-squared (uncentered): 1.000
Model: OLS Adj. R-squared (uncentered): 1.000
Method: Least Squares F-statistic: 2.587e+06
Date: Fri, 18 Jul 2025 Prob (F-statistic): 0.00
Time: 03:00:20 Log-Likelihood: -3245.9
No. Observations: 284 AIC: 6500.
Df Residuals: 280 BIC: 6514.
Df Model: 4
Covariance Type: nonrobust
==================================================================================
coef std err t P>|t| [0.025 0.975]
----------------------------------------------------------------------------------
poa 7662.7945 15.456 495.779 0.000 7632.370 7693.219
I(poa * poa) -0.8335 0.013 -64.665 0.000 -0.859 -0.808
I(poa * t_amb) -31.2845 0.484 -64.585 0.000 -32.238 -30.331
I(poa * w_vel) -1.2087 1.137 -1.063 0.289 -3.447 1.030
==============================================================================
Omnibus: 25.890 Durbin-Watson: 2.014
Prob(Omnibus): 0.000 Jarque-Bera (JB): 9.635
Skew: -0.169 Prob(JB): 0.00809
Kurtosis: 2.163 Cond. No. 6.11e+03
==============================================================================
Notes:
[1] R² is computed without centering (uncentered) since the model does not contain a constant.
[2] Standard Errors assume that the covariance matrix of the errors is correctly specified.
[3] The condition number is large, 6.11e+03. This might indicate that there are
strong multicollinearity or other numerical problems.
[19]:
sim.get_summary()
[19]:
| pts_after_filter | pts_removed | filter_arguments | ||
|---|---|---|---|---|
| pvsyst | filter_time | 1441 | 7319 | test_date: 10/11/1990, days: 60 |
| filter_irr | 397 | 1044 | 200, 930, | |
| filter_pvsyst | 397 | 0 | Default arguments | |
| filter_irr-1 | 284 | 113 | 0.5, 1.5, ref_val: 762.727 | |
| fit_regression | 284 | 0 | Default arguments |
[20]:
sim_scatter = sim.scatter_filters()
sim_scatter
[20]:
Results
The get_summary and captest_results_check_pvalues functions display the results of filtering on simulated and measured data and the final capacity test results comparing measured capacity to expected capacity, respectively.
[21]:
pvc.get_summary(das, sim)
[21]:
| pts_after_filter | pts_removed | filter_arguments | ||
|---|---|---|---|---|
| meas | filter_sensors | 1245 | 195 | Default arguments |
| filter_custom | 1240 | 5 | DataFrame.dropna, , | |
| filter_irr | 424 | 816 | 200, 2000, | |
| filter_outliers | 407 | 17 | Default arguments | |
| fit_regression | 385 | 22 | filter: True, summary: False | |
| rep_cond | 385 | 0 | Default arguments | |
| filter_irr-1 | 293 | 92 | 0.5, 1.5, ref_val: self_val | |
| fit_regression-1 | 293 | 0 | Default arguments | |
| pvsyst | filter_time | 1441 | 7319 | test_date: 10/11/1990, days: 60 |
| filter_irr | 397 | 1044 | 200, 930, | |
| filter_pvsyst | 397 | 0 | Default arguments | |
| filter_irr-1 | 284 | 113 | 0.5, 1.5, ref_val: 762.727 | |
| fit_regression | 284 | 0 | Default arguments |
[22]:
das.rc
[22]:
| poa | t_amb | w_vel | |
|---|---|---|---|
| 0 | 762.726562 | 47.967849 | 1.988983 |
[23]:
# the default hrs_req value is shown
das.print_points_summary(hrs_req=12.5)
length of test period to date: 5 days
sufficient points have been collected. 150.0 points required; 293 points collected
[24]:
pvc.captest_results_check_pvalues(sim, das, 6000, '+/- 7', print_res=True)
Using reporting conditions from das.
Capacity Test Result: FAIL
Modeled test output: 4213300.189
Actual test output: 4915552.297
Tested output ratio: 1.167
Tested Capacity: 7000.050
Bounds: 5580.0, 6420.0
Using reporting conditions from das.
Capacity Test Result: FAIL
Modeled test output: 4215133.791
Actual test output: 4915552.297
Tested output ratio: 1.166
Tested Capacity: 6997.005
Bounds: 5580.0, 6420.0
116.670% - Cap Ratio
116.620% - Cap Ratio after pval check
[24]:
| das_pvals | sim_pvals | das_params | sim_params | |
|---|---|---|---|---|
| poa | 0.00000 | 0.00000 | 7,691.89402 | 7,662.79447 |
| I(poa * poa) | 0.00000 | 0.00000 | 1.59764 | -0.83351 |
| I(poa * t_amb) | 0.00000 | 0.00000 | -51.99357 | -31.28454 |
| I(poa * w_vel) | 0.00163 | 0.28878 | 14.21468 | -1.20866 |
The overlay_scatters function can be used to overlay the final scatter plots from scatter plots of all filtering steps produced above.
[25]:
pvc.overlay_scatters(das_scatter, sim_scatter)
[25]: