IAM Model Fitting#

Illustrates how to fit an IAM model to data using 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 martin_ruiz(), physical physical(), and ASHRAE ashrae(). Each model requires one or more parameters.

Here, we show how to use 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 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 some IAM data.
aoi = np.linspace(0, 85, 10)
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()
Fitting the physical model to data

The weight function#

pvlib.iam.fit() uses a weight function when computing residuals between the model and data. The default weight function is \(1 - \sin(aoi)\). We can instead pass a custom weight function to pvlib.iam.fit().

# Define a custom weight function.  The weight function must take ``aoi``
# as its argument and return a vector of the same length as ``aoi``.
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))
plot fit iam models
Parameters with default weights: {'n': 1.2031780765297881, 'K': 4, 'L': 0.015386312188580494}
Parameters with custom weights: {'n': 1.202753515577044, 'K': 4, 'L': 0.01545043069076259}

Total running time of the script: (0 minutes 0.463 seconds)

Gallery generated by Sphinx-Gallery