Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 2 additions & 5 deletions docs/examples/shading/plot_partial_module_shading_simple.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@
from pvlib import pvsystem, singlediode
import pandas as pd
import numpy as np
from scipy.interpolate import interp1d
import matplotlib.pyplot as plt

from scipy.constants import e as qe, k as kB
Expand Down Expand Up @@ -178,10 +177,8 @@ def plot_curves(dfs, labels, title):


def interpolate(df, i):
"""convenience wrapper around scipy.interpolate.interp1d"""
f_interp = interp1d(np.flipud(df['i']), np.flipud(df['v']), kind='linear',
fill_value='extrapolate')
return f_interp(i)
"""convenience wrapper around numpy.interp"""
return np.interp(i, np.flipud(df['i']), np.flipud(df['v']))


def combine_series(dfs):
Expand Down
23 changes: 16 additions & 7 deletions pvlib/iam.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import functools
from scipy.optimize import minimize
from pvlib.tools import cosd, sind, acosd
from scipy.interpolate import make_interp_spline

# a dict of required parameter names for each IAM model
# keys are the function names for the IAM models
Expand Down Expand Up @@ -440,7 +441,7 @@ def interp(aoi, theta_ref, iam_ref, method='linear', normalize=True):
method : str, default 'linear'
Specifies the interpolation method.
Useful options are: 'linear', 'quadratic', 'cubic'.
See scipy.interpolate.interp1d for more options.
See scipy.interpolate for more options.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line may need to be edited, depending on https://github.com/pvlib/pvlib-python/pull/2741/changes#r3137773820


normalize : boolean, default True
When true, the interpolated values are divided by the interpolated
Expand Down Expand Up @@ -469,9 +470,6 @@ def interp(aoi, theta_ref, iam_ref, method='linear', normalize=True):
pvlib.iam.sapm
'''
# Contributed by Anton Driesse (@adriesse), PV Performance Labs. July, 2019

from scipy.interpolate import interp1d

# Scipy doesn't give the clearest feedback, so check number of points here.
MIN_REF_VALS = {'linear': 2, 'quadratic': 3, 'cubic': 4, 1: 2, 2: 3, 3: 4}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You could add a dictionary with names and k values, or something like that, to use below.


Expand All @@ -483,10 +481,21 @@ def interp(aoi, theta_ref, iam_ref, method='linear', normalize=True):
raise ValueError("Negative value(s) found in 'iam_ref'. "
"This is not physically possible.")

interpolator = interp1d(theta_ref, iam_ref, kind=method,
fill_value='extrapolate')
aoi_input = aoi
if method == "linear":
interpolator = make_interp_spline(theta_ref, iam_ref, k=1)

elif method == "quadratic":
interpolator = make_interp_spline(theta_ref, iam_ref, k=2)

elif method == "cubic":
interpolator = make_interp_spline(theta_ref, iam_ref, k=3)

else:
raise ValueError(
f"Interpolation method '{method}' is not supported"
" in pvlib-python.")

aoi_input = aoi
aoi = np.asanyarray(aoi)
aoi = np.abs(aoi)
iam = interpolator(aoi)
Expand Down
16 changes: 7 additions & 9 deletions pvlib/spectrum/response.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import numpy as np
import pandas as pd
import scipy.constants
from scipy.interpolate import interp1d
from scipy.interpolate import make_interp_spline


_PLANCK_BY_LIGHT_SPEED_OVER_ELEMENTAL_CHARGE_BY_BILLION = (
Expand Down Expand Up @@ -66,16 +66,14 @@ def get_example_spectral_response(wavelength=None):
if wavelength is None:
resolution = 5.0
wavelength = np.arange(280, 1200 + resolution, resolution)
x = SR_DATA[0]
y = SR_DATA[1]
spline = make_interp_spline(x, y, k=3)

interpolator = interp1d(SR_DATA[0], SR_DATA[1],
kind='cubic',
bounds_error=False,
fill_value=0.0,
copy=False,
assume_sorted=True)

sr = pd.Series(data=interpolator(wavelength), index=wavelength)
values = spline(wavelength)
values[(wavelength < x[0]) | (wavelength > x[-1])] = 0.0

sr = pd.Series(data=values, index=wavelength)
sr.index.name = 'wavelength'
sr.name = 'spectral_response'

Expand Down
46 changes: 40 additions & 6 deletions tests/test_iam.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,8 @@ def test_martin_ruiz_diffuse():

def test_iam_interp():

aoi_meas = [0.0, 45.0, 65.0, 75.0]
iam_meas = [1.0, 0.9, 0.8, 0.6]
aoi_meas = np.array([0.0, 45.0, 65.0, 75.0])
iam_meas = np.array([1.0, 0.9, 0.8, 0.6])

# simple default linear method
aoi = 55.0
Expand Down Expand Up @@ -200,18 +200,52 @@ def test_iam_interp():
assert_series_equal(iam, expected)

# check beyond reference values
aoi = [-45, 0, 45, 85, 90, 95, 100, 105, 110]
expected = [0.9, 1.0, 0.9, 0.4, 0.3, 0.2, 0.1, 0.0, 0.0]
aoi = np.array([-45, 0, 45, 85, 90, 95, 100, 105, 110])
expected = np.array([0.9, 1.0, 0.9, 0.4, 0.3, 0.2, 0.1, 0.0, 0.0])
iam = _iam.interp(aoi, aoi_meas, iam_meas)
assert_allclose(iam, expected)

# check exception clause
with pytest.raises(ValueError):
_iam.interp(0.0, [0], [1])
_iam.interp(0.0, np.array([0]), np.array([1]))

# check exception clause
with pytest.raises(ValueError):
_iam.interp(0.0, [0, 90], [1, -1])
_iam.interp(0.0, np.array([0, 90]), np.array([1, -1]))

# check linear after updating interp1d
theta_ref = np.array([0, 60, 90])
iam_ref = np.array([1.0, 0.8, 0.0])

aoi = np.array([0, 30, 60])
iam = _iam.interp(
aoi, theta_ref, iam_ref,
method="linear", normalize=False)
expected = np.array([1.0, 0.9, 0.8])
np.testing.assert_allclose(iam, expected)

# check quadratic
theta_ref = np.array([0, 30, 60, 90])
iam_ref = 1.0 - 1e-4 * theta_ref**2
aoi = np.array([15, 45, 75])
iam = _iam.interp(
aoi,
theta_ref,
iam_ref,
method="quadratic",
normalize=False
)

expected = 1.0 - 1e-4 * aoi**2
np.testing.assert_allclose(iam, expected, rtol=1e-12)

# check exception clause - list input for theta_ref
with pytest.raises(TypeError):
_iam.interp(0.0, [0, 60, 90], np.array([1.0, 0.8, 0.0]))

# check exception clause - list input for iam_ref
with pytest.raises(TypeError):
_iam.interp(0.0, np.array([0, 60, 90]), [1.0, 0.8, 0.0])


@pytest.mark.parametrize('aoi,expected', [
Expand Down
Loading