Skip to content

Commit 4a08ad9

Browse files
committed
Refactor to separate out VR computation within pvlib.scaling.wvm to a new function pvlib.scaling._compute_vr.
1 parent d90a377 commit 4a08ad9

File tree

2 files changed

+75
-18
lines changed

2 files changed

+75
-18
lines changed

pvlib/scaling.py

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -62,26 +62,9 @@ def wvm(clearsky_index, positions, cloud_speed, dt=None):
6262

6363
# Added by Joe Ranalli (@jranalli), Penn State Hazleton, 2019
6464

65-
pos = np.array(positions)
66-
dist = pdist(pos, 'euclidean')
6765
wavelet, tmscales = _compute_wavelet(clearsky_index, dt)
6866

69-
# Find effective length of position vector, 'dist' is full pairwise
70-
n_pairs = len(dist)
71-
72-
def fn(x):
73-
return np.abs((x ** 2 - x) / 2 - n_pairs)
74-
n_dist = np.round(scipy.optimize.fmin(fn, np.sqrt(n_pairs), disp=False))
75-
76-
# Compute VR
77-
A = cloud_speed / 2 # Resultant fit for A from [2]
78-
vr = np.zeros(tmscales.shape)
79-
for i, tmscale in enumerate(tmscales):
80-
rho = np.exp(-1 / A * dist / tmscale) # Eq 5 from [1]
81-
82-
# 2*rho is because rho_ij = rho_ji. +n_dist accounts for sum(rho_ii=1)
83-
denominator = 2 * np.sum(rho) + n_dist
84-
vr[i] = n_dist ** 2 / denominator # Eq 6 of [1]
67+
vr = _compute_vr(positions, cloud_speed, tmscales)
8568

8669
# Scale each wavelet by VR (Eq 7 in [1])
8770
wavelet_smooth = np.zeros_like(wavelet)
@@ -101,6 +84,68 @@ def fn(x):
10184
return smoothed, wavelet, tmscales
10285

10386

87+
def _compute_vr(positions, cloud_speed, tmscales):
88+
"""
89+
Compute the variability reduction factors for each wavelet mode for the
90+
Wavelet Variability Model [1-3].
91+
92+
Parameters
93+
----------
94+
positions : numeric
95+
Array of coordinate distances as (x,y) pairs representing the
96+
easting, northing of the site positions in meters [m]. Distributed
97+
plants could be simulated by gridded points throughout the plant
98+
footprint.
99+
100+
cloud_speed : numeric
101+
Speed of cloud movement in meters per second [m/s].
102+
103+
tmscales: numeric
104+
The timescales associated with the wavelets in seconds [s].
105+
106+
Returns
107+
-------
108+
vr : numeric
109+
an array of variability reduction factors for each tmscale.
110+
111+
References
112+
----------
113+
.. [1] M. Lave, J. Kleissl and J.S. Stein. A Wavelet-Based Variability
114+
Model (WVM) for Solar PV Power Plants. IEEE Transactions on Sustainable
115+
Energy, vol. 4, no. 2, pp. 501-509, 2013.
116+
117+
.. [2] M. Lave and J. Kleissl. Cloud speed impact on solar variability
118+
scaling - Application to the wavelet variability model. Solar Energy,
119+
vol. 91, pp. 11-21, 2013.
120+
121+
.. [3] Wavelet Variability Model - Matlab Code:
122+
https://github.com/sandialabs/wvm
123+
"""
124+
125+
# Added by Joe Ranalli (@jranalli), Penn State Hazleton, 2021
126+
127+
pos = np.array(positions)
128+
dist = pdist(pos, 'euclidean')
129+
130+
# Find effective length of position vector, 'dist' is full pairwise
131+
n_pairs = len(dist)
132+
133+
def fn(x):
134+
return np.abs((x ** 2 - x) / 2 - n_pairs)
135+
136+
n_dist = np.round(scipy.optimize.fmin(fn, np.sqrt(n_pairs), disp=False))
137+
# Compute VR
138+
A = cloud_speed / 2 # Resultant fit for A from [2]
139+
vr = np.zeros(tmscales.shape)
140+
for i, tmscale in enumerate(tmscales):
141+
rho = np.exp(-1 / A * dist / tmscale) # Eq 5 from [1]
142+
143+
# 2*rho is because rho_ij = rho_ji. +n_dist accounts for sum(rho_ii=1)
144+
denominator = 2 * np.sum(rho) + n_dist
145+
vr[i] = n_dist ** 2 / denominator # Eq 6 of [1]
146+
return vr
147+
148+
104149
def latlon_to_xy(coordinates):
105150
"""
106151
Convert latitude and longitude in degrees to a coordinate system measured

pvlib/tests/test_scaling.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,13 @@ def expect_cs_smooth():
9292
return np.array([1., 1., 1.05774, 0.94226, 1.])
9393

9494

95+
@pytest.fixture
96+
def expect_vr():
97+
# Expected VR for expecttmscale
98+
return np.array([3., 3., 3., 3., 3., 3., 2.9997844, 2.9708118, 2.6806291,
99+
2.0726611, 1.5653324, 1.2812714, 1.1389995])
100+
101+
95102
def test_latlon_to_xy_zero():
96103
coord = [0, 0]
97104
pos_e = [0, 0]
@@ -172,6 +179,11 @@ def test_compute_wavelet_dwttheory(clear_sky_index, time,
172179
assert_almost_equal(np.sum(wavelet, 0), csi_series)
173180

174181

182+
def test_compute_vr(positions, expect_tmscale, expect_vr):
183+
vr = scaling._compute_vr(positions, cloud_speed, np.array(expect_tmscale))
184+
assert_almost_equal(vr, expect_vr)
185+
186+
175187
def test_wvm_series(clear_sky_index, time, positions, expect_cs_smooth):
176188
csi_series = pd.Series(clear_sky_index, index=time)
177189
cs_sm, _, _ = scaling.wvm(csi_series, positions, cloud_speed)

0 commit comments

Comments
 (0)