|
5 | 5 |
|
6 | 6 | import numpy as np
|
7 | 7 | import pandas as pd
|
8 |
| -from pvlib.tools import sind |
| 8 | +from pvlib.tools import sind, cosd, tand |
9 | 9 |
|
10 | 10 |
|
11 | 11 | def _time_delta_in_hours(times):
|
@@ -185,3 +185,140 @@ def dc_loss_nrel(snow_coverage, num_strings):
|
185 | 185 | Available at https://www.nrel.gov/docs/fy18osti/67399.pdf
|
186 | 186 | '''
|
187 | 187 | return np.ceil(snow_coverage * num_strings) / num_strings
|
| 188 | + |
| 189 | + |
| 190 | +def _townsend_effective_snow(snow_total, snow_events): |
| 191 | + ''' |
| 192 | + Calculates effective snow using the total snowfall received each month and |
| 193 | + the number of snowfall events each month. |
| 194 | +
|
| 195 | + Parameters |
| 196 | + ---------- |
| 197 | + snow_total : array-like |
| 198 | + Snow received each month. Referred to as S in [1]_. [cm] |
| 199 | +
|
| 200 | + snow_events : array-like |
| 201 | + Number of snowfall events each month. Referred to as N in [1]_. [-] |
| 202 | +
|
| 203 | + Returns |
| 204 | + ------- |
| 205 | + effective_snowfall : array-like |
| 206 | + Effective snowfall as defined in the Townsend model. [cm] |
| 207 | +
|
| 208 | + References |
| 209 | + ---------- |
| 210 | + .. [1] Townsend, Tim & Powers, Loren. (2011). Photovoltaics and snow: An |
| 211 | + update from two winters of measurements in the SIERRA. 37th IEEE |
| 212 | + Photovoltaic Specialists Conference, Seattle, WA, USA. |
| 213 | + :doi:`10.1109/PVSC.2011.6186627` |
| 214 | + ''' |
| 215 | + snow_events_no_zeros = np.maximum(snow_events, 1) |
| 216 | + effective_snow = 0.5 * snow_total * (1 + 1 / snow_events_no_zeros) |
| 217 | + return np.where(snow_events > 0, effective_snow, 0) |
| 218 | + |
| 219 | + |
| 220 | +def loss_townsend(snow_total, snow_events, surface_tilt, relative_humidity, |
| 221 | + temp_air, poa_global, slant_height, lower_edge_height, |
| 222 | + angle_of_repose=40): |
| 223 | + ''' |
| 224 | + Calculates monthly snow loss based on the Townsend monthly snow loss |
| 225 | + model [1]_. |
| 226 | +
|
| 227 | + Parameters |
| 228 | + ---------- |
| 229 | + snow_total : array-like |
| 230 | + Snow received each month. Referred to as S in [1]_. [cm] |
| 231 | +
|
| 232 | + snow_events : array-like |
| 233 | + Number of snowfall events each month. Referred to as N in [1]_. [-] |
| 234 | +
|
| 235 | + surface_tilt : float |
| 236 | + Tilt angle of the array. [deg] |
| 237 | +
|
| 238 | + relative_humidity : array-like |
| 239 | + Monthly average relative humidity. [%] |
| 240 | +
|
| 241 | + temp_air : array-like |
| 242 | + Monthly average ambient temperature. [C] |
| 243 | +
|
| 244 | + poa_global : array-like |
| 245 | + Monthly plane of array insolation. [Wh/m2] |
| 246 | +
|
| 247 | + slant_height : float |
| 248 | + Row length in the slanted plane of array dimension. [m] |
| 249 | +
|
| 250 | + lower_edge_height : float |
| 251 | + Distance from array lower edge to the ground. [m] |
| 252 | +
|
| 253 | + angle_of_repose : float, default 40 |
| 254 | + Piled snow angle, assumed to stabilize at 40°, the midpoint of |
| 255 | + 25°-55° avalanching slope angles. [deg] |
| 256 | +
|
| 257 | + Returns |
| 258 | + ------- |
| 259 | + loss : array-like |
| 260 | + Monthly average DC capacity loss fraction due to snow coverage. |
| 261 | +
|
| 262 | + Notes |
| 263 | + ----- |
| 264 | + This model has not been validated for tracking arrays; however, for |
| 265 | + tracking arrays [1]_ suggests using the maximum rotation angle in place |
| 266 | + of ``surface_tilt``. |
| 267 | +
|
| 268 | + References |
| 269 | + ---------- |
| 270 | + .. [1] Townsend, Tim & Powers, Loren. (2011). Photovoltaics and snow: An |
| 271 | + update from two winters of measurements in the SIERRA. 37th IEEE |
| 272 | + Photovoltaic Specialists Conference, Seattle, WA, USA. |
| 273 | + :doi:`10.1109/PVSC.2011.6186627` |
| 274 | + ''' |
| 275 | + |
| 276 | + C1 = 5.7e04 |
| 277 | + C2 = 0.51 |
| 278 | + |
| 279 | + snow_total_prev = np.roll(snow_total, 1) |
| 280 | + snow_events_prev = np.roll(snow_events, 1) |
| 281 | + |
| 282 | + effective_snow = _townsend_effective_snow(snow_total, snow_events) |
| 283 | + effective_snow_prev = _townsend_effective_snow( |
| 284 | + snow_total_prev, |
| 285 | + snow_events_prev |
| 286 | + ) |
| 287 | + effective_snow_weighted = ( |
| 288 | + 1 / 3 * effective_snow_prev |
| 289 | + + 2 / 3 * effective_snow |
| 290 | + ) |
| 291 | + effective_snow_weighted_m = effective_snow_weighted / 100 |
| 292 | + |
| 293 | + lower_edge_height_clipped = np.maximum(lower_edge_height, 0.01) |
| 294 | + gamma = ( |
| 295 | + slant_height |
| 296 | + * effective_snow_weighted_m |
| 297 | + * cosd(surface_tilt) |
| 298 | + / (lower_edge_height_clipped**2 - effective_snow_weighted_m**2) |
| 299 | + * 2 |
| 300 | + * tand(angle_of_repose) |
| 301 | + ) |
| 302 | + |
| 303 | + ground_interference_term = 1 - C2 * np.exp(-gamma) |
| 304 | + relative_humidity_fraction = relative_humidity / 100 |
| 305 | + temp_air_kelvin = temp_air + 273.15 |
| 306 | + effective_snow_weighted_in = effective_snow_weighted / 2.54 |
| 307 | + poa_global_kWh = poa_global / 1000 |
| 308 | + |
| 309 | + # Calculate Eqn. 3 in the reference. |
| 310 | + # Although the reference says Eqn. 3 calculates percentage loss, the y-axis |
| 311 | + # of Figure 7 indicates Eqn. 3 calculates fractional loss. Since the slope |
| 312 | + # of the line in Figure 7 is the same as C1 in Eqn. 3, it is assumed that |
| 313 | + # Eqn. 3 calculates fractional loss. |
| 314 | + loss_fraction = ( |
| 315 | + C1 |
| 316 | + * effective_snow_weighted_in |
| 317 | + * cosd(surface_tilt)**2 |
| 318 | + * ground_interference_term |
| 319 | + * relative_humidity_fraction |
| 320 | + / temp_air_kelvin**2 |
| 321 | + / poa_global_kWh**0.67 |
| 322 | + ) |
| 323 | + |
| 324 | + return np.clip(loss_fraction, 0, 1) |
0 commit comments