Skip to content

Commit 01fe853

Browse files
committed
Updates to the _compute_wavelet algorithm to make the coefficients match their intended levels.
1 parent e86ad55 commit 01fe853

File tree

1 file changed

+24
-16
lines changed

1 file changed

+24
-16
lines changed

pvlib/scaling.py

Lines changed: 24 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,12 @@ def latlon_to_xy(coordinates):
159159

160160
def _compute_wavelet(clearsky_index, dt=None):
161161
"""
162-
Compute the wavelet transform on the input clear_sky time series.
162+
Compute the wavelet transform on the input clear_sky time series. Uses a
163+
Haar wavelet based on moving average. Output resembles a Stationary Wavelet
164+
Transform (SWT), but has shifted time positions on the averages relative to
165+
output from other wavelet codes. Returns one level of approximation
166+
coefficient (CAn) and n levels of detail coefficients (CD1, CD2, ...,
167+
CDn-1, CDn). Maximum scale is 4096 s (12 levels at a signal dt of 1s).
163168
164169
Parameters
165170
----------
@@ -174,7 +179,8 @@ def _compute_wavelet(clearsky_index, dt=None):
174179
Returns
175180
-------
176181
wavelet: numeric
177-
The individual wavelets for the time series
182+
The individual wavelets for the time series. Format follows increasing
183+
scale (decreasing frequency): [CD1, CD2, ..., CDn, CAn]
178184
179185
tmscales: numeric
180186
The timescales associated with the wavelets in seconds [s]
@@ -211,29 +217,31 @@ def _compute_wavelet(clearsky_index, dt=None):
211217
min_tmscale = np.ceil(np.log(dt)/np.log(2)) # Minimum wavelet timescale
212218
max_tmscale = int(12 - min_tmscale) # maximum wavelet timescale
213219

214-
tmscales = np.zeros(max_tmscale)
215-
csi_mean = np.zeros([max_tmscale, len(cs_long)])
216-
# Loop for all time scales we will consider
217-
for i in np.arange(0, max_tmscale):
218-
j = i+1
219-
tmscales[i] = 2**j * dt # Wavelet integration time scale
220-
intvlen = 2**j # Wavelet integration time series interval
220+
# Compute approximation coefficients via moving average (Haar wavelet)
221+
csi_mean = np.zeros([max_tmscale+1, len(cs_long)])
222+
csi_mean[0, :] = cs_long.values.flatten() # CA0, the original signal
223+
for i in np.arange(1, max_tmscale+1):
224+
intvlen = 2**i # Wavelet integration time series interval
221225
# Rolling average, retains only lower frequencies than interval
222226
df = cs_long.rolling(window=intvlen, center=True, min_periods=1).mean()
223227
# Fill nan's in both directions
224228
df = df.fillna(method='bfill').fillna(method='ffill')
225229
# Pop values back out of the dataframe and store
226-
csi_mean[i, :] = df.values.flatten()
230+
csi_mean[i, :] = df.values.flatten() # Approximation Coeffs CA0,CA1,...
227231

228-
# Calculate the wavelets by isolating the rolling mean frequency ranges
232+
# Calculate detail coeffs by difference between approximation levels
229233
wavelet_long = np.zeros(csi_mean.shape)
230-
for i in np.arange(0, max_tmscale-1):
234+
tmscales = np.zeros(max_tmscale+1)
235+
for i in np.arange(0, max_tmscale):
236+
# Compute detail coeffs, beginning with CD1 through CDn
231237
wavelet_long[i, :] = csi_mean[i, :] - csi_mean[i+1, :]
232-
wavelet_long[max_tmscale-1, :] = csi_mean[max_tmscale-1, :] # Lowest freq
238+
tmscales[i] = 2**(i+1) * dt # Wavelet integration time scale
239+
wavelet_long[max_tmscale, :] = csi_mean[max_tmscale, :] # Lowest freq (CAn)
240+
tmscales[max_tmscale] = tmscales[max_tmscale-1] # CAn and CDn share scale
233241

234242
# Clip off the padding and just return the original time window
235-
wavelet = np.zeros([max_tmscale, len(vals)])
236-
for i in np.arange(0, max_tmscale):
237-
wavelet[i, :] = wavelet_long[i, len(vals)+1: 2*len(vals)+1]
243+
wavelet = np.zeros([max_tmscale+1, len(vals)])
244+
for i in np.arange(0, max_tmscale+1):
245+
wavelet[i, :] = wavelet_long[i, len(vals): 2*len(vals)]
238246

239247
return wavelet, tmscales

0 commit comments

Comments
 (0)