12
12
import pandas as pd
13
13
from pvlib .tools import cosd , sind , tand , asind
14
14
15
-
16
15
# a dict of required parameter names for each IAM model
17
16
# keys are the function names for the IAM models
18
17
IAM_MODEL_PARAMS = {
@@ -220,8 +219,8 @@ def martin_ruiz(aoi, a_r=0.16):
220
219
-----
221
220
`martin_ruiz` calculates the incidence angle modifier (IAM) as described in
222
221
[1]. The information required is the incident angle (AOI) and the angular
223
- losses coefficient (a_r). Note that [1] has a corrigendum [2] which makes
224
- the document much simpler to understand .
222
+ losses coefficient (a_r). Note that [1] has a corrigendum [2] which
223
+ clarifies a mix-up of 'alpha's and 'a's in the former .
225
224
226
225
The incident angle modifier is defined as
227
226
@@ -249,6 +248,7 @@ def martin_ruiz(aoi, a_r=0.16):
249
248
250
249
See Also
251
250
--------
251
+ iam.martin_ruiz_diffuse
252
252
iam.physical
253
253
iam.ashrae
254
254
iam.interp
@@ -262,7 +262,7 @@ def martin_ruiz(aoi, a_r=0.16):
262
262
a_r = np .asanyarray (a_r )
263
263
264
264
if np .any (np .less_equal (a_r , 0 )):
265
- raise RuntimeError ("The parameter 'a_r' cannot be zero or negative." )
265
+ raise ValueError ("The parameter 'a_r' cannot be zero or negative." )
266
266
267
267
with np .errstate (invalid = 'ignore' ):
268
268
iam = (1 - np .exp (- cosd (aoi ) / a_r )) / (1 - np .exp (- 1 / a_r ))
@@ -274,6 +274,111 @@ def martin_ruiz(aoi, a_r=0.16):
274
274
return iam
275
275
276
276
277
+ def martin_ruiz_diffuse (surface_tilt , a_r = 0.16 , c1 = 0.4244 , c2 = None ):
278
+ '''
279
+ Determine the incidence angle modifiers (iam) for diffuse sky and
280
+ ground-reflected irradiance using the Martin and Ruiz incident angle model.
281
+
282
+ Parameters
283
+ ----------
284
+ surface_tilt: float or array-like, default 0
285
+ Surface tilt angles in decimal degrees.
286
+ The tilt angle is defined as degrees from horizontal
287
+ (e.g. surface facing up = 0, surface facing horizon = 90)
288
+ surface_tilt must be in the range [0, 180]
289
+
290
+ a_r : numeric
291
+ The angular losses coefficient described in equation 3 of [1].
292
+ This is an empirical dimensionless parameter. Values of a_r are
293
+ generally on the order of 0.08 to 0.25 for flat-plate PV modules.
294
+ a_r must be greater than zero.
295
+
296
+ c1 : float
297
+ First fitting parameter for the expressions that approximate the
298
+ integral of diffuse irradiance coming from different directions.
299
+ c1 is given as the constant 4 / 3 / pi (0.4244) in [1].
300
+
301
+ c2 : float
302
+ Second fitting parameter for the expressions that approximate the
303
+ integral of diffuse irradiance coming from different directions.
304
+ If c2 is None, it will be calculated according to the linear
305
+ relationship given in [3].
306
+
307
+ Returns
308
+ -------
309
+ iam_sky : numeric
310
+ The incident angle modifier for sky diffuse
311
+
312
+ iam_ground : numeric
313
+ The incident angle modifier for ground-reflected diffuse
314
+
315
+ Notes
316
+ -----
317
+ Sky and ground modifiers are complementary: iam_sky for tilt = 30 is
318
+ equal to iam_ground for tilt = 180 - 30. For vertical surfaces,
319
+ tilt = 90, the two factors are equal.
320
+
321
+ References
322
+ ----------
323
+ [1] N. Martin and J. M. Ruiz, "Calculation of the PV modules angular
324
+ losses under field conditions by means of an analytical model", Solar
325
+ Energy Materials & Solar Cells, vol. 70, pp. 25-38, 2001.
326
+
327
+ [2] N. Martin and J. M. Ruiz, "Corrigendum to 'Calculation of the PV
328
+ modules angular losses under field conditions by means of an
329
+ analytical model'", Solar Energy Materials & Solar Cells, vol. 110,
330
+ pp. 154, 2013.
331
+
332
+ [3] "IEC 61853-3 Photovoltaic (PV) module performance testing and energy
333
+ rating - Part 3: Energy rating of PV modules". IEC, Geneva, 2018.
334
+
335
+ See Also
336
+ --------
337
+ iam.martin_ruiz
338
+ iam.physical
339
+ iam.ashrae
340
+ iam.interp
341
+ iam.sapm
342
+ '''
343
+ # Contributed by Anton Driesse (@adriesse), PV Performance Labs. Oct. 2019
344
+
345
+ if isinstance (surface_tilt , pd .Series ):
346
+ out_index = surface_tilt .index
347
+ else :
348
+ out_index = None
349
+
350
+ surface_tilt = np .asanyarray (surface_tilt )
351
+
352
+ # avoid undefined results for horizontal or upside-down surfaces
353
+ zeroang = 1e-06
354
+
355
+ surface_tilt = np .where (surface_tilt == 0 , zeroang , surface_tilt )
356
+ surface_tilt = np .where (surface_tilt == 180 , 180 - zeroang , surface_tilt )
357
+
358
+ if c2 is None :
359
+ # This equation is from [3] Sect. 7.2
360
+ c2 = 0.5 * a_r - 0.154
361
+
362
+ beta = np .radians (surface_tilt )
363
+
364
+ from numpy import pi , sin , cos , exp
365
+
366
+ # because sin(pi) isn't exactly zero
367
+ sin_beta = np .where (surface_tilt < 90 , sin (beta ), sin (pi - beta ))
368
+
369
+ trig_term_sky = sin_beta + (pi - beta - sin_beta ) / (1 + cos (beta ))
370
+ trig_term_gnd = sin_beta + (beta - sin_beta ) / (1 - cos (beta )) # noqa: E222 E261 E501
371
+
372
+ iam_sky = 1 - exp (- (c1 + c2 * trig_term_sky ) * trig_term_sky / a_r )
373
+ iam_gnd = 1 - exp (- (c1 + c2 * trig_term_gnd ) * trig_term_gnd / a_r )
374
+
375
+ if out_index is not None :
376
+ iam_sky = pd .Series (iam_sky , index = out_index , name = 'iam_sky' )
377
+ iam_gnd = pd .Series (iam_gnd , index = out_index , name = 'iam_ground' )
378
+
379
+ return iam_sky , iam_gnd
380
+
381
+
277
382
def interp (aoi , theta_ref , iam_ref , method = 'linear' , normalize = True ):
278
383
r'''
279
384
Determine the incidence angle modifier (IAM) by interpolating a set of
0 commit comments