@@ -40,25 +40,35 @@ def eff_gap_parameters(
40
40
Weather data for a single location.
41
41
meta : pd.DataFrame
42
42
Meta data for a single location.
43
- tilt : float,
44
- Tilt angle of PV system relative to horizontal.
45
- azimuth : float, optional
46
- Azimuth angle of PV system relative to north.
43
+
47
44
sky_model : str, optional
48
45
Options: 'isotropic', 'klucher', 'haydavies', 'reindl', 'king', 'perez'.
49
46
temp_model : str, optional
50
47
Options: 'sapm'. 'pvsyst' and 'faiman' will be added later.
51
- conf_0 : str, optional
48
+ Performs the calculation for the cell temperature.
49
+ conf_0 : str, optional Model for the high temperature module on the exponential decay curve.
52
50
Default: 'insulated_back_glass_polymer'
53
51
conf_inf : str, optional
52
+ Model for the lowest temperature module on the exponential decay curve.
54
53
Default: 'open_rack_glass_polymer'
55
54
wind_speed_factor : float, optional
56
55
Wind speed correction factor to account for different wind speed measurement heights
57
56
between weather database (e.g. NSRDB) and the tempeature model (e.g. SAPM)
58
57
The NSRD provides calculations at 2m (i.e module height) but SAPM uses a 10m height.
59
- It is recommended that a power-law relationship between height and wind speed of 0.33 be used.
60
- This results in a wind_speed_factor of 1.7. It is acknowledged that this can vary significantly.
61
-
58
+ It is recommended that a power-law relationship between height and wind speed of 0.33
59
+ be used. This results in a wind_speed_factor of 1.7. It is acknowledged that this can
60
+ vary significantly.
61
+
62
+ Meta data
63
+ ------------------
64
+ tilt : float,
65
+ Tilt angle of PV system relative to horizontal. [°] Required
66
+ azimuth : float,
67
+ Azimuth angle of PV system relative to north. [°] Required
68
+ Anemomenter_Height_m : float,
69
+ if wind_speed_factor is "None", it will run a calculation based on this height and a
70
+ power factor of 0.33. If neither are supplied a wind speed factor of 1 will be used.
71
+
62
72
Returns
63
73
-------
64
74
T_0 : float
@@ -69,10 +79,12 @@ def eff_gap_parameters(
69
79
An array of temperature values for a module that is rack mounted, [°C].
70
80
T_measured : float
71
81
An array of values for the test module in the system, [°C] interest.
82
+ poa : float
83
+ An array of values for the plane of array irradiance, [W/m²]
72
84
73
85
"""
74
86
75
- parameters = ["temp_air" , "wind_speed" , "dhi" , "ghi" , "dni" , "temp_measured " ]
87
+ parameters = ["temp_air" , "wind_speed" , "dhi" , "ghi" , "dni" , "Module_Temperature " ]
76
88
77
89
if isinstance (weather_df , dd .DataFrame ):
78
90
weather_df = weather_df [parameters ].compute ()
@@ -87,15 +99,22 @@ def eff_gap_parameters(
87
99
weather_df ,
88
100
meta ,
89
101
sol_position = solar_position ,
90
- tilt = meta . tilt ,
91
- azimuth = meta . azimuth ,
102
+ tilt = float ( meta [ 'Tilt' ]) ,
103
+ azimuth = float ( meta [ 'Azimuth' ]) ,
92
104
sky_model = sky_model , )
93
- T_0 = temperature .module (
94
- weather_df , meta , poa , temp_model , conf_0 , wind_speed_factor )
95
- T_inf = temperature .module (
96
- weather_df , meta , poa , temp_model , conf_inf , wind_speed_factor )
105
+ if wind_speed_factor is None :
106
+ if 'Anemometer_Height_m' in meta ():
107
+ wind_speed_factor = (meta ('Anemometer_Height_m' )/ 2 ) ** 0.33 #Assumes a 2 meter height used in the module temperature model
108
+ else :
109
+ wind_speed_factor = 1
110
+ T_0 = temperature .cell (
111
+ weather_df = weather_df , meta = meta , poa = poa , temp_model = temp_model , conf = conf_0 ,
112
+ wind_speed_factor = wind_speed_factor )
113
+ T_inf = temperature .cell (
114
+ weather_df = weather_df , meta = meta , poa = poa , temp_model = temp_model , conf = conf_inf ,
115
+ wind_speed_factor = wind_speed_factor )
97
116
T_measured = weather_df .Module_Temperature
98
- T_ambient = weather_df .temperature
117
+ T_ambient = weather_df .temp_air
99
118
100
119
return T_0 , T_inf , T_measured , T_ambient , poa
101
120
@@ -118,7 +137,7 @@ def eff_gap(T_0, T_inf, T_measured, T_ambient, poa, x_0=6.5, poa_min=100, t_amb_
118
137
An array of values for the measured module temperature, [°C].
119
138
T_ambient : float
120
139
An array of values for the ambient temperature, [°C].
121
- poa : float
140
+ poa : float
122
141
An array of values for the plane of array irradiance, [W/m²]
123
142
x_0 : float, optional
124
143
Thermal decay constant [cm], [Kempe, PVSC Proceedings 2023].
@@ -139,18 +158,18 @@ def eff_gap(T_0, T_inf, T_measured, T_ambient, poa, x_0=6.5, poa_min=100, t_amb_
139
158
140
159
n = 0
141
160
summ = 0
142
- for i in range (0 , len (t_0 )):
143
- if T_ambient > t_amb_min :
144
- if poa > poa_min :
161
+ for i in range (0 , len (T_0 )):
162
+ if T_ambient . iloc [ i ] > t_amb_min :
163
+ if poa . poa_global . iloc [ i ] > poa_min :
145
164
n = n + 1
146
- summ = summ + (T_0 [i ] - T_module [i ]) / (T_0 [i ] - T_inf [i ])
165
+ summ = summ + (T_0 . iloc [i ] - T_measured . iloc [i ]) / (T_0 . iloc [i ] - T_inf . iloc [i ])
147
166
148
167
try :
149
168
x_eff = - x_0 * np .log (1 - summ / n )
150
169
except RuntimeWarning as e :
151
170
x_eff = np .nan # results if the specified T₉₈ is cooler than an open_rack temperature
152
- if x < 0 :
153
- x_eff = 0
171
+ if x_eff < 0 :
172
+ x_eff = 0
154
173
155
174
return x_eff
156
175
@@ -159,20 +178,23 @@ def standoff(
159
178
weather_df = None ,
160
179
meta = None ,
161
180
weather_kwarg = None ,
162
- tilt = None ,
163
- azimuth = 180 ,
181
+ tilt = 0 ,
182
+ azimuth = None ,
164
183
sky_model = "isotropic" ,
165
184
temp_model = "sapm" ,
166
- #module_type="glass_polymer", # This is removed forcing one to specify alternatives if desired
167
185
conf_0 = "insulated_back_glass_polymer" ,
168
186
conf_inf = "open_rack_glass_polymer" ,
169
- #level=1, # I am removing this because it is unnecessarily complicated
170
187
T98 = 70 , # [°C]
171
188
x_0 = 6.5 , # [cm]
172
189
wind_speed_factor = 1.7 ,
173
190
):
174
191
"""
175
- Calculate a minimum standoff distance for roof mounded PV systems.
192
+ Calculate a minimum standoff distance for roof mounded PV systems.
193
+ Will default to horizontal tilt. If the azimuth is not provided, it
194
+ will use equator facing.
195
+ You can use customized temperature models for the building integrated
196
+ and the rack mounted configuration, but it will still assume an
197
+ exponential decay.
176
198
177
199
Parameters
178
200
----------
@@ -181,16 +203,19 @@ def standoff(
181
203
meta : pd.DataFrame
182
204
Meta data for a single location.
183
205
tilt : float, optional
184
- Tilt angle of PV system relative to horizontal.
206
+ Tilt angle of PV system relative to horizontal. [°]
185
207
azimuth : float, optional
186
- Azimuth angle of PV system relative to north.
208
+ Azimuth angle of PV system relative to north. [°]
187
209
sky_model : str, optional
188
210
Options: 'isotropic', 'klucher', 'haydavies', 'reindl', 'king', 'perez'.
189
211
temp_model : str, optional
190
212
Options: 'sapm'. 'pvsyst' and 'faiman' will be added later.
213
+ Performs the calculations for the cell temperature.
191
214
conf_0 : str, optional
215
+ Model for the high temperature module on the exponential decay curve.
192
216
Default: 'insulated_back_glass_polymer'
193
217
conf_inf : str, optional
218
+ Model for the lowest temperature module on the exponential decay curve.
194
219
Default: 'open_rack_glass_polymer'
195
220
x0 : float, optional
196
221
Thermal decay constant (cm), [Kempe, PVSC Proceedings 2023]
@@ -208,14 +233,19 @@ def standoff(
208
233
Effective gap "x" for the lower limit for Level 1 or Level 0 modules (IEC TS 63216)
209
234
T98_0 : float [°C]
210
235
This is the 98th percential temperature of a theoretical module with no standoff.
211
- T98_inf : float [°C]
236
+ T98_inf : float [°C]
212
237
This is the 98th percential temperature of a theoretical rack mounted module.
213
238
214
239
References
215
240
----------
216
241
M. Kempe, et al. Close Roof Mounted System Temperature Estimation for Compliance
217
242
to IEC TS 63126, PVSC Proceedings 2023
218
243
"""
244
+ if azimuth == None : #Sets the default orientation to equator facing.
245
+ if float (meta ['latitude' ]) < 0 :
246
+ azimuth = 0
247
+ else :
248
+ azimuth = 180
219
249
220
250
parameters = ["temp_air" , "wind_speed" , "dhi" , "ghi" , "dni" ]
221
251
@@ -229,17 +259,17 @@ def standoff(
229
259
230
260
solar_position = spectral .solar_position (weather_df , meta )
231
261
poa = spectral .poa_irradiance (
232
- weather_df ,
233
- meta ,
262
+ weather_df = weather_df ,
263
+ meta = meta ,
234
264
sol_position = solar_position ,
235
265
tilt = tilt ,
236
266
azimuth = azimuth ,
237
267
sky_model = sky_model , )
238
- T_0 = temperature .module (
239
- weather_df , meta , poa , temp_model , conf_0 , wind_speed_factor )
268
+ T_0 = temperature .cell (
269
+ weather_df = weather_df , meta = meta , poa = poa , temp_model = temp_model , conf = conf_0 , wind_speed_factor = wind_speed_factor )
240
270
T98_0 = T_0 .quantile (q = 0.98 , interpolation = "linear" )
241
- T_inf = temperature .module (
242
- weather_df , meta , poa , temp_model , conf_inf , wind_speed_factor )
271
+ T_inf = temperature .cell (
272
+ weather_df = weather_df , meta = meta , poa = poa , temp_model = temp_model , conf = conf_inf , wind_speed_factor = wind_speed_factor )
243
273
T98_inf = T_inf .quantile (q = 0.98 , interpolation = "linear" )
244
274
245
275
try :
@@ -265,8 +295,10 @@ def T98_estimate(
265
295
conf_0 = "insulated_back_glass_polymer" ,
266
296
conf_inf = "open_rack_glass_polymer" ,
267
297
wind_speed_factor = 1.7 ,
298
+ tilt = 0 ,
299
+ azimuth = None ,
268
300
x_eff = None ,
269
- x_0 = 6.5 ):
301
+ x_0 = 6.5 , ):
270
302
271
303
"""
272
304
Calculate and set up data necessary to calculate the effective standoff distance for rooftop mounded PV system
@@ -276,24 +308,27 @@ def T98_estimate(
276
308
Parameters
277
309
----------
278
310
x_eff : float
279
- This is the effective module standoff distance according to the model.
311
+ This is the effective module standoff distance according to the model. [cm]
280
312
x_0 : float, optional
281
- Thermal decay constant [cm],
313
+ Thermal decay constant. [cm]
282
314
weather_df : pd.DataFrame
283
- Weather data for a single location.
315
+ Weather data for a single location.
284
316
meta : pd.DataFrame
285
317
Meta data for a single location.
286
318
tilt : float,
287
- Tilt angle of PV system relative to horizontal.
319
+ Tilt angle of PV system relative to horizontal. [°]
288
320
azimuth : float, optional
289
- Azimuth angle of PV system relative to north.
321
+ Azimuth angle of PV system relative to north. [°]
290
322
sky_model : str, optional
291
323
Options: 'isotropic', 'klucher', 'haydavies', 'reindl', 'king', 'perez'.
292
324
temp_model : str, optional
293
325
Options: 'sapm'. 'pvsyst' and 'faiman' will be added later.
326
+ Performs the calculations for the cell temperature.
294
327
conf_0 : str, optional
328
+ Model for the high temperature module on the exponential decay curve.
295
329
Default: 'insulated_back_glass_polymer'
296
330
conf_inf : str, optional
331
+ Model for the lowest temperature module on the exponential decay curve.
297
332
Default: 'open_rack_glass_polymer'
298
333
wind_speed_factor : float, optional
299
334
Wind speed correction factor to account for different wind speed measurement heights
@@ -308,8 +343,13 @@ def T98_estimate(
308
343
This is the 98th percential temperature for the module at the given tilt, azimuth, and x_eff.
309
344
310
345
"""
346
+ if azimuth == None : #Sets the default orientation to equator facing.
347
+ if float (meta ['latitude' ]) < 0 :
348
+ azimuth = 0
349
+ else :
350
+ azimuth = 180
311
351
312
- parameters = ["temp_air" , "wind_speed" , "dhi" , "ghi" , "dni" , "temp_measured" ]
352
+ parameters = ["temp_air" , "wind_speed" , "dhi" , "ghi" , "dni" ]
313
353
314
354
if isinstance (weather_df , dd .DataFrame ):
315
355
weather_df = weather_df [parameters ].compute ()
@@ -321,89 +361,23 @@ def T98_estimate(
321
361
322
362
solar_position = spectral .solar_position (weather_df , meta )
323
363
poa = spectral .poa_irradiance (
324
- weather_df ,
325
- meta ,
364
+ weather_df = weather_df ,
365
+ meta = meta ,
326
366
sol_position = solar_position ,
327
- tilt = meta . tilt ,
328
- azimuth = meta . azimuth ,
367
+ tilt = tilt ,
368
+ azimuth = azimuth ,
329
369
sky_model = sky_model , )
330
- T_0 = temperature .module (
331
- weather_df , meta , poa , temp_model , conf_0 , wind_speed_factor )
370
+ T_0 = temperature .cell (
371
+ weather_df , meta , poa , temp_model , conf_0 , wind_speed_factor , )
332
372
T98_0 = T_0 .quantile (q = 0.98 , interpolation = "linear" )
333
- T_inf = temperature .module (
334
- weather_df , meta , poa , temp_model , conf_inf , wind_speed_factor )
373
+ T_inf = temperature .cell (
374
+ weather_df , meta , poa , temp_model , conf_inf , wind_speed_factor , )
335
375
T98_inf = T_inf .quantile (q = 0.98 , interpolation = "linear" )
336
376
337
- T98 = T_0 - (T_0 - T_inf )* (1 - np .exp (- x_eff / x_0 ))
377
+ T98 = T98_0 - (T98_0 - T98_inf )* (1 - np .exp (- x_eff / x_0 ))
338
378
339
379
return T98
340
380
341
- def standoff_tilt_azimuth_scan (
342
- weather_df = None ,
343
- meta = None ,
344
- weather_kwarg = None ,
345
- tilt_count = 18 ,
346
- azimuth_count = 72 ,
347
- sky_model = "isotropic" ,
348
- temp_model = "sapm" ,
349
- conf_0 = "insulated_back_glass_polymer" ,
350
- conf_inf = "open_rack_glass_polymer" ,
351
- T98 = 70 , # [°C]
352
- x_0 = 6.5 , # [cm]
353
- wind_speed_factor = 1.7 ):
354
-
355
- """
356
- Calculate a minimum standoff distance for roof mounded PV systems as a function of tilt and azimuth.
357
-
358
- Parameters
359
- ----------
360
- weather_df : pd.DataFrame
361
- Weather data for a single location.
362
- meta : pd.DataFrame
363
- Meta data for a single location.
364
- tilt_count : integer
365
- Step in degrees of change in tilt angle of PV system between calculations.
366
- azimuth_count : integer
367
- Step in degrees of change in Azimuth angle of PV system relative to north.
368
- sky_model : str, optional
369
- Options: 'isotropic', 'klucher', 'haydavies', 'reindl', 'king', 'perez'.
370
- temp_model : str, optional
371
- Options: 'sapm'. 'pvsyst' and 'faiman' will be added later.
372
- conf_0 : str, optional
373
- Default: 'insulated_back_glass_polymer'
374
- conf_inf : str, optional
375
- Default: 'open_rack_glass_polymer'
376
- x_0 : float, optional
377
- Thermal decay constant [cm], [Kempe, PVSC Proceedings 2023]
378
- wind_speed_factor : float, optional
379
- Wind speed correction factor to account for different wind speed measurement heights
380
- between weather database (e.g. NSRDB) and the tempeature model (e.g. SAPM)
381
- The NSRD provides calculations at 2m (i.e module height) but SAPM uses a 10m height.
382
- It is recommended that a power-law relationship between height and wind speed of 0.33 be used.
383
- This results in a wind_speed_factor of 1.7. It is acknowledged that this can vary significantly.
384
- Returns
385
- standoff_series : 2-D array with each row consiting of tilt, azimuth, then standoff
386
- """
387
-
388
- standoff_series = np .array ([(azimuth_count + 1 )* (tilt_count + 1 )][3 ])
389
- for x in range (0 , azimuth_count + 1 ):
390
- for y in range (0 ,tilt_count + 1 ):
391
- standoff_series [x + y ][0 ]= azimuth_count * 180 / azimuth_count
392
- standoff_series [x + y ][1 ]= tilt_count * 90 / azimuth_count
393
- standoff_series [x + y ][2 ]= standards .standoff (
394
- weather_df = weather_df ,
395
- meta = meta ,
396
- T98 = T98 ,
397
- tilt = y * 90 / tilt_count ,
398
- azimuth = x * 180 / azimuth_count ,
399
- sky_model = sky_model ,
400
- temp_model = temp_model ,
401
- conf_0 = conf_0 ,
402
- conf_inf = conf_inf ,
403
- x_0 = x_0 ,
404
- wind_speed_factor = wind_speed_factor )
405
-
406
- return standoff_series
407
381
408
382
# def run_calc_standoff(
409
383
# project_points,
0 commit comments