forked from pvlib/pvlib-python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
plot_fit_iam_models.py
98 lines (77 loc) · 3 KB
/
plot_fit_iam_models.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
"""
IAM Model Fitting
================================
Illustrates how to fit an IAM model to data using :py:func:`~pvlib.iam.fit`.
"""
# %%
# An incidence angle modifier (IAM) model quantifies the fraction of direct
# irradiance is that is reflected away from a module's surface. Three popular
# IAM models are Martin-Ruiz :py:func:`~pvlib.iam.martin_ruiz`, physical
# :py:func:`~pvlib.iam.physical`, and ASHRAE :py:func:`~pvlib.iam.ashrae`.
# Each model requires one or more parameters.
#
# Here, we show how to use
# :py:func:`~pvlib.iam.fit` to estimate a model's parameters from data.
#
# Model fitting require a weight function that can assign
# more influence to some AOI values than others. We illustrate how to provide
# a custom weight function to :py:func:`~pvlib.iam.fit`.
import numpy as np
from random import uniform
import matplotlib.pyplot as plt
from pvlib.tools import cosd
from pvlib.iam import (martin_ruiz, physical, fit)
# %%
# Fitting an IAM model to data
# ----------------------------
#
# Here, we'll show how to fit an IAM model to data.
# We'll generate some data by perturbing output from the Martin-Ruiz model to
# mimic measured data and then we'll fit the physical model to the perturbed
# data.
# Create and perturb IAM data.
aoi = np.linspace(0, 90, 100)
params = {'a_r': 0.16}
iam = martin_ruiz(aoi, **params)
data = iam * np.array([uniform(0.98, 1.02) for _ in range(len(iam))])
# Get parameters for the physical model by fitting to the perturbed data.
physical_params = fit(aoi, data, 'physical')
# Compute IAM with the fitted physical model parameters.
physical_iam = physical(aoi, **physical_params)
# Plot IAM vs. AOI
plt.scatter(aoi, data, c='darkorange', label='Data')
plt.plot(aoi, physical_iam, label='physical')
plt.xlabel('AOI (degrees)')
plt.ylabel('IAM')
plt.title('Fitting the physical model to data')
plt.legend()
plt.show()
# %%
# The weight function
# -------------------
# :py:func:`pvlib.iam.fit` uses a weight function when computing residuals
# between the model and data. The default weight
# function is :math:`1 - \sin(aoi)`. We can instead pass a custom weight
# function to :py:func:`pvlib.iam.fit`.
#
# Define a custom weight function.
def weight_function(aoi):
return cosd(aoi)
physical_params_custom = fit(aoi, data, 'physical', weight=weight_function)
physical_iam_custom = physical(aoi, **physical_params_custom)
# Plot IAM vs AOI.
fig, ax = plt.subplots(2, 1, figsize=(5, 8))
ax[0].plot(aoi, data, '.', label='Data (from Martin-Ruiz model)')
ax[0].plot(aoi, physical_iam, label='With default weight function')
ax[0].plot(aoi, physical_iam_custom, label='With custom weight function')
ax[0].set_xlabel('AOI (degrees)')
ax[0].set_ylabel('IAM')
ax[0].legend()
ax[1].plot(aoi, physical_iam_custom - physical_iam, label='Custom - default')
ax[1].set_xlabel('AOI (degrees)')
ax[1].set_ylabel('Diff. in IAM')
ax[1].legend()
plt.tight_layout()
plt.show()
print("Parameters with default weights: " + str(physical_params))
print("Parameters with custom weights: " + str(physical_params_custom))