|
| 1 | + |
| 2 | +""" |
| 3 | +IAM Model Conversion |
| 4 | +==================== |
| 5 | +
|
| 6 | +Illustrates how to convert from one IAM model to a different model using |
| 7 | +:py:func:`~pvlib.iam.convert`. |
| 8 | +
|
| 9 | +""" |
| 10 | + |
| 11 | +# %% |
| 12 | +# An incidence angle modifier (IAM) model quantifies the fraction of direct |
| 13 | +# irradiance that is reflected away from a module's surface. Three popular |
| 14 | +# IAM models are Martin-Ruiz :py:func:`~pvlib.iam.martin_ruiz`, physical |
| 15 | +# :py:func:`~pvlib.iam.physical`, and ASHRAE :py:func:`~pvlib.iam.ashrae`. |
| 16 | +# Each model requires one or more parameters. |
| 17 | +# |
| 18 | +# Here, we show how to use |
| 19 | +# :py:func:`~pvlib.iam.convert` to estimate parameters for a desired target |
| 20 | +# IAM model from a source IAM model. Model conversion uses a weight |
| 21 | +# function that can assign more influence to some AOI values than others. |
| 22 | +# We illustrate how to provide a custom weight function to |
| 23 | +# :py:func:`~pvlib.iam.convert`. |
| 24 | + |
| 25 | +import numpy as np |
| 26 | +import matplotlib.pyplot as plt |
| 27 | + |
| 28 | +from pvlib.tools import cosd |
| 29 | +from pvlib.iam import (ashrae, martin_ruiz, physical, convert) |
| 30 | + |
| 31 | +# %% |
| 32 | +# Converting from one IAM model to another model |
| 33 | +# ---------------------------------------------- |
| 34 | +# |
| 35 | +# Here we'll show how to convert from the Martin-Ruiz model to the |
| 36 | +# physical and the ASHRAE models. |
| 37 | + |
| 38 | +# Compute IAM values using the martin_ruiz model. |
| 39 | +aoi = np.linspace(0, 90, 100) |
| 40 | +martin_ruiz_params = {'a_r': 0.16} |
| 41 | +martin_ruiz_iam = martin_ruiz(aoi, **martin_ruiz_params) |
| 42 | + |
| 43 | +# Get parameters for the physical model and compute IAM using these parameters. |
| 44 | +physical_params = convert('martin_ruiz', martin_ruiz_params, 'physical') |
| 45 | +physical_iam = physical(aoi, **physical_params) |
| 46 | + |
| 47 | +# Get parameters for the ASHRAE model and compute IAM using these parameters. |
| 48 | +ashrae_params = convert('martin_ruiz', martin_ruiz_params, 'ashrae') |
| 49 | +ashrae_iam = ashrae(aoi, **ashrae_params) |
| 50 | + |
| 51 | +fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(11, 5), sharey=True) |
| 52 | + |
| 53 | +# Plot each model's IAM vs. angle-of-incidence (AOI). |
| 54 | +ax1.plot(aoi, martin_ruiz_iam, label='Martin-Ruiz') |
| 55 | +ax1.plot(aoi, physical_iam, label='physical') |
| 56 | +ax1.set_xlabel('AOI (degrees)') |
| 57 | +ax1.set_title('Convert from Martin-Ruiz to physical') |
| 58 | +ax1.legend() |
| 59 | + |
| 60 | +ax2.plot(aoi, martin_ruiz_iam, label='Martin-Ruiz') |
| 61 | +ax2.plot(aoi, ashrae_iam, label='ASHRAE') |
| 62 | +ax2.set_xlabel('AOI (degrees)') |
| 63 | +ax2.set_title('Convert from Martin-Ruiz to ASHRAE') |
| 64 | +ax2.legend() |
| 65 | + |
| 66 | +ax1.set_ylabel('IAM') |
| 67 | +plt.show() |
| 68 | + |
| 69 | + |
| 70 | +# %% |
| 71 | +# The weight function |
| 72 | +# ------------------- |
| 73 | +# :py:func:`pvlib.iam.convert` uses a weight function when computing residuals |
| 74 | +# between the two models. The default weight |
| 75 | +# function is :math:`1 - \sin(aoi)`. We can instead pass a custom weight |
| 76 | +# function to :py:func:`pvlib.iam.convert`. |
| 77 | +# |
| 78 | +# In some cases, the choice of weight function has a minimal effect on the |
| 79 | +# returned model parameters. This is especially true when converting between |
| 80 | +# the Martin-Ruiz and physical models, because the curves described by these |
| 81 | +# models can match quite closely. However, when conversion involves the ASHRAE |
| 82 | +# model, the choice of weight function can have a meaningful effect on the |
| 83 | +# returned parameters for the target model. |
| 84 | +# |
| 85 | +# Here we'll show examples of both of these cases, starting with an example |
| 86 | +# where the choice of weight function does not have much impact. In doing |
| 87 | +# so, we'll show how to pass in a custom weight function of our choice. |
| 88 | + |
| 89 | +# Compute IAM using the Martin-Ruiz model. |
| 90 | +aoi = np.linspace(0, 90, 100) |
| 91 | +martin_ruiz_params = {'a_r': 0.16} |
| 92 | +martin_ruiz_iam = martin_ruiz(aoi, **martin_ruiz_params) |
| 93 | + |
| 94 | +# Get parameters for the physical model ... |
| 95 | + |
| 96 | +# ... using the default weight function. |
| 97 | +physical_params_default = convert('martin_ruiz', martin_ruiz_params, |
| 98 | + 'physical') |
| 99 | +physical_iam_default = physical(aoi, **physical_params_default) |
| 100 | + |
| 101 | + |
| 102 | +# ... using a custom weight function. The weight function must take ``aoi`` |
| 103 | +# as its argument and return a vector of the same length as ``aoi``. |
| 104 | +def weight_function(aoi): |
| 105 | + return cosd(aoi) |
| 106 | + |
| 107 | + |
| 108 | +physical_params_custom = convert('martin_ruiz', martin_ruiz_params, 'physical', |
| 109 | + weight=weight_function) |
| 110 | +physical_iam_custom = physical(aoi, **physical_params_custom) |
| 111 | + |
| 112 | +# Plot IAM vs AOI. |
| 113 | +plt.plot(aoi, martin_ruiz_iam, label='Martin-Ruiz') |
| 114 | +plt.plot(aoi, physical_iam_default, label='Default weight function') |
| 115 | +plt.plot(aoi, physical_iam_custom, label='Custom weight function') |
| 116 | +plt.xlabel('AOI (degrees)') |
| 117 | +plt.ylabel('IAM') |
| 118 | +plt.title('Martin-Ruiz to physical') |
| 119 | +plt.legend() |
| 120 | +plt.show() |
| 121 | + |
| 122 | +# %% |
| 123 | +# For this choice of source and target models, the weight function has little |
| 124 | +# effect on the target model's parameters. |
| 125 | +# |
| 126 | +# Now we'll look at an example where the weight function does affect the |
| 127 | +# output. |
| 128 | + |
| 129 | +# Get parameters for the ASHRAE model ... |
| 130 | + |
| 131 | +# ... using the default weight function. |
| 132 | +ashrae_params_default = convert('martin_ruiz', martin_ruiz_params, 'ashrae') |
| 133 | +ashrae_iam_default = ashrae(aoi, **ashrae_params_default) |
| 134 | + |
| 135 | +# ... using the custom weight function |
| 136 | +ashrae_params_custom = convert('martin_ruiz', martin_ruiz_params, 'ashrae', |
| 137 | + weight=weight_function) |
| 138 | +ashrae_iam_custom = ashrae(aoi, **ashrae_params_custom) |
| 139 | + |
| 140 | +# Plot IAM vs AOI. |
| 141 | +plt.plot(aoi, martin_ruiz_iam, label='Martin-Ruiz') |
| 142 | +plt.plot(aoi, ashrae_iam_default, label='Default weight function') |
| 143 | +plt.plot(aoi, ashrae_iam_custom, label='Custom weight function') |
| 144 | +plt.xlabel('AOI (degrees)') |
| 145 | +plt.ylabel('IAM') |
| 146 | +plt.title('Martin-Ruiz to ASHRAE') |
| 147 | +plt.legend() |
| 148 | +plt.show() |
| 149 | + |
| 150 | +# %% |
| 151 | +# In this case, each of the two ASHRAE looks quite different. |
| 152 | +# Finding the right weight function and parameters in such cases will require |
| 153 | +# knowing where you want the target model to be more accurate. The default |
| 154 | +# weight function was chosen because it yielded IAM models that produce |
| 155 | +# similar annual insolation for a simulated PV system. |
| 156 | + |
| 157 | +# %% |
| 158 | +# Reference |
| 159 | +# --------- |
| 160 | +# .. [1] Jones, A. R., Hansen, C. W., Anderson, K. S. Parameter estimation |
| 161 | +# for incidence angle modifier models for photovoltaic modules. Sandia |
| 162 | +# report SAND2023-13944 (2023). |
0 commit comments