_PHOTORECEPTORS = ['l-cone', 'm-cone', 's-cone', 'rod', 'iprgc'] _Ee_SYMBOLS = ['Ee,lc', 'Ee,mc', 'Ee,sc', 'Ee,r', 'Ee,z'] _E_SYMBOLS = ['E,lc', 'E,mc', 'E,sc', 'E,r', 'E,z'] _Q_SYMBOLS = ['Q,lc', 'Q,mc', 'Q,sc', 'Q,r', 'Q,z'] _Ee_UNITS = ['W⋅m−2', 'W⋅m−2', 'W⋅m−2', 'W⋅m−2', 'W⋅m−2'] _E_UNITS = ['lux', 'lux', 'lux', 'lux', 'lux'] _Q_UNITS = [ 'photons/m2/s', 'photons/m2/s', 'photons/m2/s', 'photons/m2/s', 'photons/m2/s' ] _QUANTITIES = ['erythropic', 'chloropic', 'cyanopic', 'rhodopic', 'melanopic'] #irradiance, illuminance _ACTIONSPECTRA = getdata(_PKG_PATH + _SEP + 'toolboxes' + _SEP + 'photbiochem' + _SEP + 'data' + _SEP + 'cie_tn003_2015_SI_action_spectra.dat', header='infer', kind='np', verbosity=0).T # Calculate correction factor for Km in standard air: na = _BB['na'] # n for standard air c = _BB['c'] # m/s light speed lambdad = c / (na * 54 * 1e13) / (1e-9) # 555 nm lambda in standard air Km_correction_factor = 1 / (1 - (1 - 0.9998567) * (lambdad - 555) ) # correction factor for Km in standard air def spd_to_aopicE(sid, Ee=None, E=None, Q=None,
from luxpy.utils import np, sp, plt, _PKG_PATH, _SEP, getdata __all__ = [ '_INDVCMF_DATA_PATH', '_INDVCMF_DATA', '_INDVCMF_STD_DEV_ALL_PARAM', '_INDVCMF_CATOBSPFCTR', '_INDVCMF_M_2d', '_INDVCMF_M_10d' ] __all__ += [ 'cie2006cmfsEx', 'getMonteCarloParam', 'genMonteCarloObs', 'getCatObs' ] _INDVCMF_DATA_PATH = _PKG_PATH + _SEP + 'toolboxes' + _SEP + 'indvcmf' + _SEP + 'data' + _SEP # Load data from files: _INDVCMF_DATA = {} _INDVCMF_DATA['rmd'] = getdata(_INDVCMF_DATA_PATH + 'asano_cie2006_RelativeMacularDensity.dat', header=None).T _INDVCMF_DATA['LMSa'] = getdata(_INDVCMF_DATA_PATH + 'asano_cie2006_Alms.dat', header=None).T _INDVCMF_DATA['docul'] = getdata(_INDVCMF_DATA_PATH + 'asano_cie2006_docul.dat', header=None).T _INDVCMF_DATA['USCensus2010population'] = getdata( _INDVCMF_DATA_PATH + 'asano_USCensus2010Population.dat', header='infer', verbosity=0).T _INDVCMF_DATA['CatObsPfctr'] = getdata(_INDVCMF_DATA_PATH + 'asano_CatObsPfctr.dat', header=None).T # Store var of. physiological parameters in dict:
def spd_to_xyz(data, relative=True, rfl=None, cieobs=_CIEOBS, K=None, out=None, cie_std_dev_obs=None): """ Calculates xyz tristimulus values from spectral data. Args: :data: | ndarray or pandas.dataframe with spectral data | (.shape = (number of spectra + 1, number of wavelengths)) | Note that :data: is never interpolated, only CMFs and RFLs. | This way interpolation errors due to peaky spectra are avoided. | Conform CIE15-2018. :relative: | True or False, optional | Calculate relative XYZ (Yw = 100) or absolute XYZ (Y = Luminance) :rfl: | ndarray with spectral reflectance functions. | Will be interpolated if wavelengths do not match those of :data: :cieobs: | luxpy._CIEOBS or str, optional | Determines the color matching functions to be used in the | calculation of XYZ. :K: | None, optional | e.g. K = 683 lm/W for '1931_2' (relative == False) | or K = 100/sum(spd*dl) (relative == True) :out: | None or 1 or 2, optional | Determines number and shape of output. (see :returns:) :cie_std_dev_obs: | None or str, optional | - None: don't use CIE Standard Deviate Observer function. | - 'f1': use F1 function. Returns: :returns: | If rfl is None: | If out is None: ndarray of xyz values | (.shape = (data.shape[0],3)) | If out == 1: ndarray of xyz values | (.shape = (data.shape[0],3)) | If out == 2: (ndarray of xyz, ndarray of xyzw) values | Note that xyz == xyzw, with (.shape = (data.shape[0],3)) | If rfl is not None: | If out is None: ndarray of xyz values | (.shape = (rfl.shape[0],data.shape[0],3)) | If out == 1: ndarray of xyz values | (.shape = (rfl.shape[0]+1,data.shape[0],3)) | The xyzw values of the light source spd are the first set | of values of the first dimension. The following values | along this dimension are the sample (rfl) xyz values. | If out == 2: (ndarray of xyz, ndarray of xyzw) values | with xyz.shape = (rfl.shape[0],data.shape[0],3) | and with xyzw.shape = (data.shape[0],3) References: 1. `CIE15:2018, “Colorimetry,” CIE, Vienna, Austria, 2018. <https://doi.org/10.25039/TR.015.2018>`_ """ data = getdata(data, kind='np') if isinstance(data, pd.DataFrame) else np2d( data) # convert to np format and ensure 2D-array # get wl spacing: dl = getwld(data[0]) # get cmf,k for cieobs: if isinstance(cieobs, str): if K is None: K = _CMF[cieobs]['K'] scr = 'dict' else: scr = 'cieobs' if (K is None) & (relative == False): K = 1 # Interpolate to wl of data: cmf = xyzbar(cieobs=cieobs, scr=scr, wl_new=data[0], kind='np') # Add CIE standard deviate observer function to cmf if requested: if cie_std_dev_obs is not None: cmf_cie_std_dev_obs = xyzbar(cieobs='cie_std_dev_obs_' + cie_std_dev_obs.lower(), scr=scr, wl_new=data[0], kind='np') cmf[1:] = cmf[1:] + cmf_cie_std_dev_obs[1:] # Rescale xyz using k or 100/Yw: if relative == True: K = 100.0 / np.dot(data[1:], cmf[2, :] * dl) # Interpolate rfls to lambda range of spd and calculate xyz: if rfl is not None: rfl = cie_interp(data=np2d(rfl), wl_new=data[0], kind='rfl') rfl = np.concatenate((np.ones((1, data.shape[1])), rfl[1:])) #add rfl = 1 for light source spectrum xyz = K * np.array( [np.dot(rfl, (data[1:] * cmf[i + 1, :] * dl).T) for i in range(3)]) #calculate tristimulus values rflwasnotnone = 1 else: rfl = np.ones((1, data.shape[1])) xyz = (K * (np.dot((cmf[1:] * dl), data[1:].T))[:, None, :]) rflwasnotnone = 0 xyz = np.transpose(xyz, [1, 2, 0]) #order [rfl,spd,xyz] # Setup output: if out == 2: xyzw = xyz[0, ...] xyz = xyz[rflwasnotnone:, ...] if rflwasnotnone == 0: xyz = np.squeeze(xyz, axis=0) return xyz, xyzw elif out == 1: if rflwasnotnone == 0: xyz = np.squeeze(xyz, axis=0) return xyz else: xyz = xyz[rflwasnotnone:, ...] if rflwasnotnone == 0: xyz = np.squeeze(xyz, axis=0) return xyz
def spd(data = None, interpolation = None, kind = 'np', wl = None,\ columns = None, sep = ',',header = None, datatype = 'S', \ norm_type = None, norm_f = None): """ | All-in-one function that can: | 1. Read spectral data from data file or take input directly as pandas.dataframe or ndarray. | 2. Convert spd-like data from ndarray to pandas.dataframe and back. | 3. Interpolate spectral data. | 4. Normalize spectral data. Args: :data: | - str with path to file containing spectral data | - ndarray with spectral data | - pandas.dataframe with spectral data | (.shape = (number of spectra + 1, number of original wavelengths)) :interpolation: | None, optional | - None: don't interpolate | - str with interpolation type or spectrum type :kind: | str ['np','df'], optional | Determines type(:returns:), np: ndarray, df: pandas.dataframe :wl: | None, optional | New wavelength range for interpolation. | Defaults to wavelengths specified by luxpy._WL3. :columns: | - None or list[str] of column names for dataframe, optional :header: | None or 'infer', optional | - None: no header in file | - 'infer': infer headers from file :sep: | ',' or '\t' or other char, optional | Column separator in case :data: specifies a data file. :datatype': | 'S' (light source) or 'R' (reflectance) or other, optional | Specifies a type of spectral data. | Is used when creating column headers when :column: is None. :norm_type: | None, optional | - 'lambda': make lambda in norm_f equal to 1 | - 'area': area-normalization times norm_f | - 'max': max-normalization times norm_f | - 'ru': to :norm_f: radiometric units | - 'pu': to :norm_f: photometric units | - 'pusa': to :norm_f: photometric units (with Km corrected | to standard air, cfr. CIE TN003-2015) | - 'qu': to :norm_f: quantal energy units :norm_f: | 1, optional | Normalization factor that determines the size of normalization for 'max' and 'area' or which wavelength is normalized to 1 for 'lambda' option. Returns: :returns: | ndarray or pandas.dataframe | with interpolated and/or normalized spectral data. """ transpose = True if isinstance( data, str ) else False #when spd comes from file -> transpose (columns in files should be different spectra) # Wavelength definition: wl = getwlr(wl) # Data input: if data is not None: if (interpolation is None) & (norm_type is None): data = getdata(data=data, kind='np', columns=columns, sep=sep, header=header, datatype=datatype, copy=True) if (transpose == True): data = data.T else: data = getdata( data=data, kind='np', columns=columns, sep=sep, header=header, datatype=datatype, copy=True) #interpolation requires np-array as input if (transpose == True): data = data.T data = cie_interp(data=data, wl_new=wl, kind=interpolation) data = spd_normalize(data, norm_type=norm_type, norm_f=norm_f, wl=True) if isinstance(data, pd.DataFrame): columns = data.columns #get possibly updated column names else: data = np2d(wl) if ((data.shape[0] - 1) == 0): columns = None #only wavelengths if kind == 'df': data = data.T # convert to desired kind: data = getdata( data=data, kind=kind, columns=columns, datatype=datatype, copy=False) # already copy when data is not None, else new anyway return data
Reference: AS/NZS1680.2.5 (1997). INTERIOR LIGHTING PART 2.5: HOSPITAL AND MEDICAL TASKS. .. codeauthor:: Kevin A.G. Smet (ksmet1977 at gmail.com) """ from luxpy import deltaE, _CIE_ILLUMINANTS, spd_to_xyz, blackbody, xyz_to_cct from luxpy.utils import np, _PKG_PATH, _SEP, getdata __all__ = [ '_COI_RFL_BLOOD', '_COI_CIEOBS', '_COI_CSPACE', 'spd_to_COI_ASNZS1680' ] # Reflectance spectra of 100% and 50% oxygenated blood _COI_RFL_BLOOD = getdata(_PKG_PATH + _SEP + 'toolboxes' + _SEP + 'photbiochem' + _SEP + 'data' + _SEP + 'ASNZS_1680.2.5_1997_cyanosisindex_100_50.dat', header=None, kind='np', verbosity=0).T _COI_CIEOBS = '1931_2' # default CMF set _COI_CSPACE = 'lab' _COI_REF = blackbody(4000, ) def spd_to_COI_ASNZS1680(S=None, tf=_COI_CSPACE, cieobs=_COI_CIEOBS, out='COI,cct', extrapolate_rfl=False):
Light. Res. Technol. 44, 516. <https://doi.org/10.1177/1477153512467607>`_ Also see notes in doc_string of spd_to_CS_CLa_lrc() .. codeauthor:: Kevin A.G. Smet (ksmet1977 at gmail.com) """ from luxpy import _CIE_ILLUMINANTS, getwld, cie_interp, _IESTM3015, blackbody, spd_to_power from luxpy.utils import np, _PKG_PATH, _SEP, getdata from scipy import integrate __all__=['_LRC_CLA_CS_CONST','spd_to_CS_CLa_lrc'] _LRC_CLA_CS_EFF_FCN = getdata(_PKG_PATH + _SEP + 'toolboxes' + _SEP + 'photbiochem' + _SEP + 'data' + _SEP + 'LRC2012_CS_CLa_efficiency_functions.dat', header = 'infer', kind ='np', verbosity = 0).T _LRC_CLA_CS_CONST = {'CLa_2012' : {'Norm' : 1622, 'k': 0.2616, 'a_b_y':0.6201, 'a_rod' : 3.2347, 'RodSat' : 6.52,\ 'Vphotl': _LRC_CLA_CS_EFF_FCN[1], 'Vscotl': _LRC_CLA_CS_EFF_FCN[2], \ 'Vl_mpl': _LRC_CLA_CS_EFF_FCN[3], 'Scl_mpl': _LRC_CLA_CS_EFF_FCN[4],\ 'Mcl' : _LRC_CLA_CS_EFF_FCN[5], 'WL' : _LRC_CLA_CS_EFF_FCN[0]},\ 'CLa': {'Norm' : 1547.9, 'k': 0.2616, 'a_b_y':0.7, 'a_rod' : 3.3, 'RodSat' : 6.5215,\ 'Vphotl': _LRC_CLA_CS_EFF_FCN[1], 'Vscotl': _LRC_CLA_CS_EFF_FCN[2], \ 'Vl_mpl': _LRC_CLA_CS_EFF_FCN[3], 'Scl_mpl': _LRC_CLA_CS_EFF_FCN[4],\ 'Mcl' : _LRC_CLA_CS_EFF_FCN[5], 'WL' : _LRC_CLA_CS_EFF_FCN[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):