Exemple #1
0
 def getwld_(self):
     """
     Get wavelength spacing of SPD instance. 
                
     Returns:
         :returns:
             | float:  for equal wavelength spacings
             |     ndarray (.shape = (n,)): for unequal wavelength spacings
     """
     return getwld(self.wl)
Exemple #2
0
def _cri_ref_i(cct,
               wl3=_WL,
               ref_type='iestm30',
               mix_range=[4000, 5000],
               cieobs='1931_2',
               force_daylight_below4000K=False,
               n=None,
               daylight_locus=None):
    """
    Calculates a reference illuminant spectrum based on cct 
    for color rendering index calculations.
    """
    if mix_range is None:
        mix_range = _CRI_REF_TYPES[ref_type]
    if (cct < mix_range[0]) | (ref_type == 'BB'):
        return blackbody(cct, wl3, n=n)
    elif (cct > mix_range[0]) | (ref_type == 'DL'):
        return daylightphase(
            cct,
            wl3,
            force_daylight_below4000K=force_daylight_below4000K,
            cieobs=cieobs,
            daylight_locus=daylight_locus)
    else:
        SrBB = blackbody(cct, wl3, n=n)
        SrDL = daylightphase(
            cct,
            wl3,
            verbosity=None,
            force_daylight_below4000K=force_daylight_below4000K,
            cieobs=cieobs,
            daylight_locus=daylight_locus)
        cmf = _CMF[cieobs]['bar'] if isinstance(cieobs, str) else cieobs
        wl = SrBB[0]
        ld = getwld(wl)

        SrBB = 100.0 * SrBB[1] / np.array(np.sum(SrBB[1] * cmf[2] * ld))
        SrDL = 100.0 * SrDL[1] / np.array(np.sum(SrDL[1] * cmf[2] * ld))
        Tb, Te = float(mix_range[0]), float(mix_range[1])
        cBB, cDL = (Te - cct) / (Te - Tb), (cct - Tb) / (Te - Tb)
        if cBB < 0.0:
            cBB = 0.0
        elif cBB > 1:
            cBB = 1.0
        if cDL < 0.0:
            cDL = 0.0
        elif cDL > 1:
            cDL = 1.0

        Sr = SrBB * cBB + SrDL * cDL
        Sr[Sr == float('NaN')] = 0.0
        Sr = np.vstack((wl, (Sr / Sr[_POS_WL560])))

        return Sr
Exemple #3
0
def fCLa(wl, Elv, integral, Norm = None, k = None, a_b_y = None, a_rod = None, RodSat = None,\
        Vphotl = None, Vscotl = None, Vl_mpl = None, Scl_mpl = None, Mcl = None, WL = None):
    """
    Local helper function that calculate CLa from El based on Eq. 1 
    in Rea et al (2012).
    
    Args:
        The various model parameters as described in the paper and contained 
        in the dict _LRC_CONST.
        
    Returns:
        ndarray with CLa values.
        
    References:
        1. `Rea MS, Figueiro MG, Bierman A, and Hamner R (2012). 
        Modelling the spectral sensitivity of the human circadian system. 
        Light. Res. Technol. 44, 386–396.  
        <https://doi.org/10.1177/1477153511430474>`_
            
        2. `Rea MS, Figueiro MG, Bierman A, and Hamner R (2012). 
        Erratum: Modeling the spectral sensitivity of the human circadian system 
        (Lighting Research and Technology (2012) 44:4 (386-396)). 
        Light. Res. Technol. 44, 516.
        <https://doi.org/10.1177/1477153512467607>`_
        
        
    """
    dl = getwld(wl)

    # Calculate piecewise function in Eq. 1 in Rea et al. 2012:

    #calculate value of condition function (~second term of 1st fcn):
    cond_number = integral(
        Elv * Scl_mpl * dl) - k * integral(Elv * Vl_mpl * dl)

    # Calculate second fcn:
    fcn2 = integral(Elv * Mcl * dl)

    # Calculate last term of 1st fcn:
    fcn1_3 = a_rod * (1 - np.exp(-integral(Vscotl * Elv * dl) / RodSat))

    # Satisfying cond. is effectively adding fcn1_2 and fcn1_3 to fcn1_1:
    CLa = Norm * (fcn2 + 1 * (cond_number >= 0) *
                  (a_b_y * cond_number - fcn1_3))

    return CLa
def spd_to_aopicE(sid, Ee = None, E = None, Q = None, cieobs = _CIEOBS, sid_units = 'W/m2', out = 'Eeas,Eas'):
    """
    Calculate alpha-opic irradiance (Ee,α) and equivalent luminance (Eα) values
    for the l-cone, m-cone, s-cone, rod and iprgc (α) photoreceptor cells 
    following CIE technical note TN 003:2015.
    
    Args:
        :sid: 
            | numpy.ndarray with retinal spectral irradiance in :sid_units: 
            | (if 'uW/cm2', sid will be converted to SI units 'W/m2')
        :Ee: 
            | None, optional
            | If not None: normalize :sid: to an irradiance of :Ee:
        :E: 
            | None, optional
            | If not None: normalize :sid: to an illuminance of :E:
            | Note that E is calculate using a Km factor corrected to standard air.
        :Q: 
            | None, optional
            | If not None: nNormalize :sid: to a quantal energy of :Q:
        :cieobs:
            | _CIEOBS or str, optional
            | Type of cmf set to use for photometric units.
        :sid_units:
            | 'W/m2', optional
            | Other option 'uW/m2', input units of :sid:
        :out: 
            | 'Eeas, Eas' or str, optional
            | Determines values to return.
            
    Returns:
        :returns: 
            | (Eeas, Eas) with Eeas and Eas resp. numpy.ndarrays with the 
              α-opic irradiance and equivalent illuminance values 
              of all spectra in :sid: in SI-units. 
         
            | (other choice can be set using :out:)
    """
    outlist = out.split(',')
    
    # Convert to Watt/m²:
    if sid_units == 'uW/cm2':
        sid[1:] = sid[1:]/100

    elif sid_units == 'W/m2':
        pass
    else:
        raise Exception("spd_to_aopicE(): {} unsupported units for SID.".format(sid_units))
    
    
    # Normalize sid to Ee:
    if Ee is not None:
        sid = spd_normalize(sid, norm_type = 'ru', norm_f = Ee)  
    elif E is not None:
        sid = spd_normalize(sid, norm_type = 'pusa', norm_f = E) 
    elif Q is not None:
        sid = spd_normalize(sid, norm_type = 'qu', norm_f = Q) 
    
    
    # Get sid irradiance (W/m²):
    if 'Ee' in outlist:
        Ee = spd_to_power(sid, cieobs = cieobs, ptype = 'ru')
    
    # Get sid illuminance (lx):
    if 'E' in outlist:
        E = spd_to_power(sid, cieobs = cieobs, ptype = 'pusa') #photometric units (Km corrected to standard air)
    
    # Get sid quantal energy (photons/m²/s):
    if 'Q' in outlist:
        Q = spd_to_power(sid, cieobs = cieobs, ptype = 'qu')


    # get SI actinic action spectra, sa:
    sa = spd(_ACTIONSPECTRA, wl = sid[0], interpolation = 'cmf', norm_type = 'max')
    
    # get wavelength spacing:
    dl = getwld(sid[0])
    
    # Calculate all alpha-opics Ee's:
    Eeas = (np.dot((sa[1:]*dl),sid[1:].T)).T

    # Calculate equivalent alpha-opic E's:
    Vl, Km = vlbar(cieobs = cieobs, wl_new = sid[0], out = 2)
    Eas = Km*Km_correction_factor*Eeas*(Vl[1].sum()/sa[1:].sum(axis = 1))

    #Prepare output:
    if out == 'Eeas,Eas':
        return Eeas,Eas
    elif out == 'Eeas':
        return Eeas
    elif out == 'Eas':
        return Eas
    else:
        eval(out)
Exemple #5
0
def spd_to_CS_CLa_lrc(El = None, E = None, \
                          sum_sources = False, interpolate_sources = True):
    """
    Calculate Circadian Stimulus (CS) and Circadian Light [LRC: Rea et al 2012].
    
    
    Args:
        :El:
            | ndarray, optional
            | Defaults to D65
            | light source spectral irradiance distribution
        :E: 
            | None, float or ndarray, optional
            | Illuminance of light sources.
            | If None: El is used as is, otherwise El is renormalized to have
              an illuminance equal to E.
        :sum_sources:
            | False, optional
            |   - False: calculate CS and CLa for all sources in El array.
            |   - True: sum sources in El to a single source and perform calc.
        :interpolate_sources:
            | True, optional
            |  - True: El is interpolated to wavelength range of efficiency 
            |          functions (as in LRC calculator). 
            |  - False: interpolate efficiency functions to source range. 
            |           Source interpolation is not recommended due to possible
            |           errors for peaky spectra. 
            |           (see CIE15-2004, "Colorimetry").
            
    Returns:
        :CS:
            | ndarray with Circadian stimulus values
        :CLa:
            | ndarray with Circadian Light values
            
    Notes:
        1. The original 2012 (E.q. 1) had set the peak wavelength of the 
        melanopsin at 480 nm. Rea et al. later published a corrigendum with 
        updated model parameters for k, a_{b-y} and a_rod. The comparison table
        between showing values calculated for a number of sources with the old
        and updated parameters were very close (~1 unit voor CLa). 
        
        2. In that corrrection paper they did not mention a change in the
        factor (1622) that multiplies the (sum of) the integral(s) in Eq. 1. 
        HOWEVER, the excel calculator released in 2017 and the online 
        calculator show that factor to have a value of 1547.9. The change in
        values due to the new factor is much larger than their the updated 
        mentioned in note 1!
        
        3. For reasons of consistency the calculator uses the latest model 
        parameters, as could be read from the excel calculator. They values 
        adopted are: multiplier 1547.9, k = 0.2616, a_{b-y} = 0.7 and 
        a_rod = 3.3. 
        
        4. The parameter values to convert CLa to CS were also taken from the 
        2017 excel calculator.
        
    References:
        
        1. `LRC Online Circadian stimulus calculator <http://www.lrc.rpi.edu/cscalculator/>`_
        
        2. `LRC Excel based Circadian stimulus calculator. <http://www.lrc.rpi.edu/resources/CSCalculator_2017_10_03_Mac.xlsm>`_
        
        3. `Rea MS, Figueiro MG, Bierman A, and Hamner R (2012). 
        Modelling the spectral sensitivity of the human circadian system. 
        Light. Res. Technol. 44, 386–396.  
        <https://doi.org/10.1177/1477153511430474>`_
            
        4. `Rea MS, Figueiro MG, Bierman A, and Hamner R (2012). 
        Erratum: Modeling the spectral sensitivity of the human circadian system 
        (Lighting Research and Technology (2012) 44:4 (386-396)). 
        Light. Res. Technol. 44, 516.
        <https://doi.org/10.1177/1477153512467607>`_
    """
    # Create copy of dict with model parameters and spectral data:
    cs_cl_lrs = _LRC_CLA_CS_CONST['CLa'].copy()

    # Interpolate efficiency functions to light source wl-range:
    if interpolate_sources is False:
        cs_cl_lrs = interpolate_efficiency_functions(El[0], cs_cl_lrs)
    else:
        El = cie_interp(El, cs_cl_lrs['WL'], kind='spd')

    # Get wavelength spacing:
    dl = getwld(El[0])

    # Separate wavelengths and data:
    wl = El[0]
    Elv = El[1:].copy()

    # define integral function:
    integral = lambda x: integrate.trapz(x, x=wl, axis=-1)
    #integral = lambda x: np.sum(x,  axis = -1)

    # Rescale El to E (if not None):
    if E is not None:

        # Calculate current E value of El:
        E_cv = np.atleast_2d(683.002 *
                             integral(cs_cl_lrs['Vphotl'] * Elv * dl))

        # Rescale El to supplied E:
        Elv = (E / E_cv).T * Elv

    # Sum all sources in array if requested:
    if sum_sources == True:
        Elv = Elv.sum(axis=0, keepdims=True)

    # Calculate Circadian light using model param. and spectral data:
    CLa = fCLa(wl, Elv, integral, **cs_cl_lrs)

    # Calculate Circadian stimulus:
    CS = 0.7 * (1 - (1 / (1 + (CLa / 355.7)**1.1026)))

    return CS, CLa