Spectrum sub-package

py:
  • __init__.py

  • spdx_ietm2714.py

  • basics/
    • __init__.py

    • cmf.py

    • spectral.py

    • spectral_databases.py

namespace:

luxpy

spectrum: sub-package supporting basic spectral calculations

spectrum/cmf.py

luxpy._CMF:
Dict with keys ‘types’ and x
x are dicts with keys ‘bar’, ‘K’, ‘M’

* luxpy._CMF[‘types’] = [‘1931_2’,’1964_10’,
‘2006_2’,’2006_10’,’2015_2’,’2015_10’,
‘1931_2_judd1951’,’1931_2_juddvos1978’,
‘1951_20_scotopic’]
* luxpy._CMF[x][‘bar’] = numpy array with CMFs for type x
between 360 nm and 830 nm (has shape: (4,471))
* luxpy._CMF[x][‘K’] = Constant converting Watt to lumen for CMF type x.
* luxpy._CMF[x][‘M’] = XYZ to LMS conversion matrix for CMF type x.
Matrix is numpy array with shape: (3,3)
* luxpy._CMF[x][‘N’] = XYZ to RGB conversion matrix for CMF type x.
Matrix is numpy array with shape: (3,3)

Notes:

  1. All functions have been expanded (when necessary) using zeros to a

    full 360-830 range. This way those wavelengths do not contribute in the calculation, AND are not extrapolated using the closest known value, as per CIE recommendation.

  2. There is no XYZ to LMS conversion matrices defined for the

    1931 2° Judd corrected (1951) cmf sets. The Hunt-Pointer-Estevez conversion matrix of the 1931 2° is therefore used as an approximation!

  3. The XYZ to LMS conversion matrix M for the Judd-Vos XYZ CMFs is the one

    that converts to the 1979 Smith-Pokorny cone fundamentals.

  4. The XYZ to LMS conversion matrix for the 1964 10° XYZ CMFs is set

    to the one of the CIE 2006 10° cone fundamentals, as not matrix has been officially defined for this CMF set.

  1. The K lm to Watt conversion factors for the Judd and Judd-Vos cmf

    sets have been set to 683.002 lm/W (same as for standard 1931 2°).

  2. The 1951 scoptopic V’ function has been replicated in the 3

    xbar, ybar, zbar columns to obtain a data format similar to the photopic color matching functions. This way V’ can be called in exactly the same way as other V functions can be called from the X,Y,Z cmf sets. The K value has been set to 1700.06 lm/W and the conversion matrix has been filled with NaN’s.

  3. The ‘2015_x’ (with x = 2 or 10) are the same XYZ-CMFs as stored in ‘2006_x’.

  4. _CMF[x][‘M’] for x equal to ‘2006_2’ (=’2015_2’) or ‘2006_10’ (=’2015_10’) is NOT

    normalized to illuminant E! These are the original matrices as defined by [1] & [2].

  5. _CMF[x][‘N’] stores known or calculated conversion matrices from

    xyz to rgb. If not available, N has been filled with NaNs.

spectrum/spectral.py

_WL3:

Default wavelength specification in vector-3 format: numpy.array([start, end, spacing])

_INTERP_REFERENCE:

Sets the specific interpolation for spectrum types: [‘spd’,’cmf’,’rfl’,’none’]

_INTERP_SETTINGS_ALL:

Nested Dict with interpolation settings per spectral type [‘spd’,’cmf’,’rfl’,’none’] for various interp_reference keys.

_INTERP_SETTINGS:

Nested Dict with interpolation settings per spectral type [‘spd’,’cmf’,’rfl’,’none’].

_INTERP_TYPES:

Dict with interpolation types associated with various types of spectral data according to CIE recommendation:

getwlr():

Get/construct a wavelength range from a (start, stop, spacing) 3-vector.

getwld():

Get wavelength spacing of numpy.ndarray with wavelengths.

spd_normalize():

Spectrum normalization (supports: area, max, lambda, radiometric, photometric and quantal energy units).

cie_interp():

Interpolate / extrapolate spectral data following standard [CIE15:2018, “Colorimetry,” CIE, Vienna, Austria, 2018.]

spd():
All-in-one function that can:
1. Read spectral data from data file or take input directly as ndarray.
2. Interpolate spectral data.
3. Normalize spectral data.
xyzbar():

Get color matching functions.

vlbar():

Get Vlambda function.

vlbar_cie_mesopic():

Get CIE mesopic luminous efficiency function Vmesm according to CIE191:2010

get_cie_mesopic_adaptation():

Get the mesopic adaptation state according to CIE191:2010

spd_to_xyz_legacy():

Calculates xyz tristimulus values from spectral data. (luxpy version <= 1.11.4)

spd_to_xyz_barebones():

Calculates xyz tristimulus values from equal wavelength spectral data (no additional processing)

spd_to_xyz():

Calculates xyz tristimulus values from spectral data.

spd_to_ler():

Calculates Luminous efficacy of radiation (LER) from spectral data.

spd_to_power():

Calculate power of spectral data in radiometric, photometric or quantal energy units.

detect_peakwl():

Detect peak wavelengths and fwhm of peaks in spectrum spd.

spectrum/spectral_databases.py

_S_PATH:

Path to light source spectra data.

_R_PATH:

Path to with spectral reflectance data

_IESTM3015:

Database with spectral reflectances related to and light source spectra contained excel calculator of IES TM30-15 publication.

_IESTM3018:

Database with spectral reflectances related to and light source spectra contained excel calculator of IES TM30-18 publication.

_IESTM3015_S:

Database with only light source spectra contained in the IES TM30-15 excel calculator.

_IESTM3018_S:

Database with only light source spectra contained in the IES TM30-18 excel calculator.

_CIE_ILLUMINANTS:
Database with CIE illuminants:
* ‘E’, ‘D65’, ‘A’, ‘C’,
* ‘F1’, ‘F2’, ‘F3’, ‘F4’, ‘F5’, ‘F6’, ‘F7’, ‘F8’, ‘F9’, ‘F10’, ‘F11’, ‘F12’
_CIE_E, _CIE_D65, _CIE_A, _CIE_C, _CIE_F4:

Some CIE illuminants for easy use.

_CRI_RFL:
_MUNSELL:

Database (dict) with 1269 Munsell spectral reflectance functions and Value (V), Chroma (C), hue (h) and (ab) specifications.

_RFL:
Database (dict) with RFLs, including:
* all those in _CRI_RFL,
* the 1269 Matt Munsell samples (see also _MUNSELL),
* the 24 Macbeth ColorChecker samples,
* the 215 samples proposed by Opstelten, J.J. , 1983, The establishment of a representative set of test colours
for the specification of the colour rendering properties of light sources, CIE-20th session, Amsterdam.
* the 114120 RFLs from capbone.com/spectral-reflectance-database/

spectrum/illuminants.py

_BB:

Dict with constants for blackbody radiator calculation constant are (c1, c2, n, na, c, h, k).

_S012_DAYLIGHTPHASE:

ndarray with CIE S0,S1, S2 curves for daylight phase calculation (linearly interpolated to 1 nm).

_CRI_REF_TYPES:

Dict with blackbody to daylight transition (mixing) ranges for various types of reference illuminants used in color rendering index calculations.

blackbody():

Calculate blackbody radiator spectrum.

_DAYLIGHT_LOCI_PARAMETERS:

dict with parameters for daylight loci for various CMF sets; used by daylightlocus().

_DAYLIGHT_M12_COEFFS:

dict with coefficients in weights M1 & M2 for daylight phases for various CMF sets.

get_daylightloci_parameters():

Get parameters for the daylight loci functions xD(1000/CCT) and yD(xD); used by daylightlocus().

get_daylightphase_Mi_coeffs():

Get coefficients of Mi weights of daylight phase for specific cieobs following Judd et al. (1964).

_get_daylightphase_Mi_values():

Get daylight phase coefficients M1, M2 following Judd et al. (1964).

_get_daylightphase_Mi():

Get daylight phase coefficients M1, M2 following Judd et al. (1964)

daylightlocus():

Calculates daylight chromaticity from cct.

daylightphase():

Calculate daylight phase spectrum.

cri_ref():
Calculates a reference illuminant spectrum based on cct for color

rendering index calculations.

(CIE15:2018, “Colorimetry,” CIE, Vienna, Austria, 2018.,

cie224:2017, CIE 2017 Colour Fidelity Index for accurate scientific use. (2017), ISBN 978-3-902842-61-9., IES-TM-30-15: Method for Evaluating Light Source Color Rendition. New York, NY: The Illuminating Engineering Society of North America.

spd_to_indoor():

Convert spd to indoor variant by multiplying it with the CIE spectral transmission for glass.

spectrum/spdx_iestm2714.py

_SPDX_TEMPLATE:

template dictionary for SPDX data.

read_spdx():

Read xml file or convert xml string with spdx data to dictionary.

write_spdx():

Convert spdx dictionary to xml string (and write to .spdx file)

References


luxpy.spectrum.getwlr(wl3=None)[source]

Get/construct a wavelength range from a 3-vector (start, stop, spacing).

Args:
wl3:
list[start, stop, spacing], optional
(defaults to luxpy._WL3)
Returns:
returns:
ndarray (.shape = (n,)) with n wavelengths ranging from
start to stop, with wavelength interval equal to spacing.
luxpy.spectrum.getwld(wl)[source]

Get wavelength spacing.

Args:
wl:
ndarray with wavelengths
Returns:
returns:
- float: for equal wavelength spacings
- ndarray (.shape = (n,)): for unequal wavelength spacings
luxpy.spectrum.spd_normalize(data, norm_type=None, norm_f=1, wl=True, cieobs='1931_2', K=None, interp_settings=None)[source]

Normalize a spectral power distribution (SPD).

Args:
data:
ndarray
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.
wl:
True or False, optional
If True, the first column of data contains wavelengths.
cieobs:
_CIEOBS or str or ndarray, optional
Type of cmf set to use for normalization using photometric units
(norm_type == ‘pu’)
K:
None, optional
Luminous efficacy of radiation.
Must be supplied if cieobs is an array for norm_type == ‘pu’
Returns:
returns:
ndarray with normalized data.
luxpy.spectrum.spectral_interp(data, wl_new, stype='cmf', interp_settings={'cmf': {'etype': 'linear', 'fill_value': None, 'itype': 'linear', 'negative_values_allowed': False}, 'general': {'choose_most_efficient_interpolator': False, 'extrap_log': False, 'force_scipy_interpolator': False, 'interp_log': False, 'scipy_interpolator': 'interp1d', 'sprague_allowed': False, 'sprague_method': 'spargue_cie224_2017'}, 'none': {'etype': 'linear', 'fill_value': None, 'itype': 'cubic', 'negative_values_allowed': False}, 'rfl': {'etype': 'linear', 'fill_value': None, 'itype': 'cubic', 'negative_values_allowed': False}, 'spd': {'etype': 'linear', 'fill_value': None, 'itype': 'cubic', 'negative_values_allowed': False}}, itype=None, etype=None, fill_value=None, negative_values_allowed=False, delete_nans=True, force_scipy_interpolator=False, scipy_interpolator='InterpolatedUnivariateSpline', interp_log=False, extrap_log=False, choose_most_efficient_interpolator=False, verbosity=0)[source]

Perform a 1-dimensional interpolation of spectral data

Args:
data:
ndarray with (n+1,N)-dimensional spectral data (0-row: wavelengths, remaining n rows: data)
wl_new:
ndarray of new wavelengths (N,)
stype:
None, optional
Type of spectral data: None or (‘spd’, ‘cmf’, ‘rfl’)
If None: itype, etype and fill_value kwargs should not be none!
itype:
None or str, optional
supported options for str: ‘linear’, ‘quadratic’, ‘cubic’
If None: use value in interp_settings.
etype:
None, or str, optional
options:
- ‘extrapolate’,’ext’: use method specified in :itype: to extrapolate.
- ‘zeros’: out-of-bounds values are filled with zeros
- ‘const’: out-of-bounds values are filled with nearest value
- ‘fill_value’: value of tuple (2,) of values is used to fill out-of-bounds values
- ‘linear’,’quadratic’,’cubic’: use of of these methods (slows down function
if this method is different from the one in :itype:)
If None: use value in intp_settings.
fill_value:
None or str or float or int or tupple, optional
If etype == ‘fill_value’: use fill_value to set lower- and upper-out-of-bounds values when extrapolating
(‘extrapolate’ when etype requires extrapolation)
If None: use value in interp_settings.
negative_values_allowed:
False, optional
If False: negative values are clipped to zero.
delete_nans:
True, optional
If NaNs are present, remove them and (and try to) interpolate without them.
force_scipy_interpolator:
False, optional
If False: numpy.interp function is used for linear interpolation when no or linear extrapolation is used/required (fast!).
scipy_interpolator:
‘InterpolatedUnivariateSpline’, optional
options: ‘InterpolatedUnivariateSpline’, ‘interp1d’
w,bbox,check_finite:
see scipy.interpolate.InterpolatedUnivariateSpline()
interp_log:
Perform interpolation method (‘linear’, ‘quadratic’, or ‘cubic’) in log space.
extrap_log:
Perform extrapolation method (‘linear’, ‘quadratic’, or ‘cubic’) in log space.
Returns:
data_new:
ndarray with interpolated (n+1,N)-dimensional spectral data
(0-row: wavelengths, remaining n rows: interpolated data)
Note:
  1. ‘numpy.interp’ is fastest (but only works for linear interpolation and linear or no extrapolation)

  2. For linear interpolation: ‘interp1d’ is faster for Y (N,…) with N > 1, else ‘InterpolatedUnivariateSpline’ is faster

  3. For ‘cubic’ interpolation: ‘InterpolatedUnivariateSpline’ is faster for Y (N,…) with N > 1, else ‘interp1d’ is faster

luxpy.spectrum.cie_interp(data, wl_new, datatype='none', interp_settings={'cmf': {'etype': 'linear', 'fill_value': None, 'itype': 'linear', 'negative_values_allowed': False}, 'general': {'choose_most_efficient_interpolator': False, 'extrap_log': False, 'force_scipy_interpolator': False, 'interp_log': False, 'scipy_interpolator': 'interp1d', 'sprague_allowed': False, 'sprague_method': 'spargue_cie224_2017'}, 'none': {'etype': 'linear', 'fill_value': None, 'itype': 'linear', 'negative_values_allowed': False}, 'rfl': {'etype': 'linear', 'fill_value': None, 'itype': 'cubic', 'negative_values_allowed': False}, 'spd': {'etype': 'linear', 'fill_value': None, 'itype': 'cubic', 'negative_values_allowed': False}}, kind=None, extrap_kind=None, extrap_values=None, sprague_allowed=None, sprague_method='sprague_cie224_2017', negative_values_allowed=None, interp_log=None, extrap_log=None, force_scipy_interpolator=None, scipy_interpolator=None, choose_most_efficient_interpolator=None, verbosity=0)[source]

Interpolate / extrapolate spectral data following standard CIE15-2018.

The kind of interpolation depends on the spectrum type defined in :datatype:
(or in :kind: for legacy puprposes-> overrules :datatype:).
Args:
data:
ndarray with spectral data
(.shape = (number of spectra + 1, number of original wavelengths))
wl_new:
None or ndarray with new wavelengths or [start wavelength, stop wavelength, wavelength interval]
If None: no interpolation is done, a copy of the original data is returned.
datatype:
‘spd’ (light source) or ‘rfl’ (reflectance) or ‘cmf’ (color matching functions) or ‘none’ (undefined), optional
Specifies a type of spectral data.
Is used to select the interpolation and extrapolation defaults, specified
in :interp_settings:.
interp_settings:
_INTERP_SETTINGS or dict, optional
Dictionary of dictionaries (see _INTERP_SETTINGS), with at least a key entry
with the interpolation and extrapolation settings for the type specified in
:datatype: (or :kind: if string with spectrum datatype) and one key entry ‘none’
(‘none’ is used in case :extrap_kind: is None or ‘ext’).

kind:
None, optional
- If None: the value from interp_settings is used, based on the value of :datatype:.
- If :kind: is a spectrum type (see :interp_settings:), the correct
interpolation type is automatically chosen based on the values in :interp_settings:
(The use of the slow(er) ‘sprague5’ or ‘sprague_cie224_2017’ can be toggled on using :sprague_allowed:).
- Or :kind: can be ‘linear’, ‘quadratic’, ‘cubic’ (or ‘sprague5’, or ‘sprague_cie224_2017, or ‘lagrange5’).
(see luxpy.spectral_interp?)
sprague_allowed:
None, optional
If None: the value from interp_settings is used.
If True: When kind is a spectral data type that corresponds to ‘cubic’ interpolation,
then a cubic spline interpolation will be used in case of
unequal wavelength spacings, otherwise a 5th order Sprague or Sprague as defined in CIE224-2017 will be used.
If False: always use ‘cubic’, don’t use ‘sprague5’ or ‘sprague_cie224_2017’.
This is the default, as differences are minimal and
use of the ‘sprague’ functions is a lot slower (‘sprague5’ = slowest )!
sprague_method:
‘sprague_cie224_2017’, optional
Specific sprague method used for interpolation. (Only for equal spacings, ‘sprague_cie224_2017’ also on for 5 nm -> 1nm)
- options: ‘sprague5’ (use luxpy.math.interp1_sprague5), ‘sprague_cie224_2017’ (use luxpy.interp1_sprague_cie224_2017)
negative_values_allowed:
None, optional
If None: the value from interp_settings is used.
If False: negative values are clipped to zero.
extrap_kind:
None, optional
If None or ‘ext’: use the method specified interp_settings[datatype].
If ‘kind’ or ‘itype’:
- If possible, use the same method as the interpolation method
(only for ‘linear’, ‘quadratic’, ‘cubic’),
- otherwise: use the method specified :interp_settings[‘none’]:.
Other options: ‘linear’ (or ‘cie167:2005’), ‘quadratic’ (or ‘cie15:2018’),
‘nearest’ (or ‘cie15:2004’ or ‘const’ or ‘flat’), ‘cubic’, ‘fill_value’ (use value(s)n in extrap_values)
- If ‘linear’,’quadratic’,’cubic’: slow down of function
in case this method is different from the interpolation method used.
CIE15:2018 states that based on a 2017 paper by Wang that ‘quadratic’ is ‘better’.
However, no significant difference was found between ‘quadratic’ and ‘linear’ methods.
Also see note 1 below, for why the CIE67:2005 recommended ‘linear’ extrapolation
is set as the default.
extrap_values:
None, optional
If float or list or ndarray, use those values to fill extrapolated value(s) when :extrap_kind:S == ‘fill_value’.
extrap_log:
None, optional
If None: the value from interp_settings is used.
If True: extrap the log of the spectral values
(not CIE recommended but in most cases seems to give a
more realistic estimate, but can sometimes seriously fail,
especially for the ‘quadratic’ extrapolation case (see note 1)!!!)
If any zero or negative values are present in a spectrum, then the log is NOT taken.
interp_log:
None, optional
If None: the value from interp_settings is used.
Take log before interpolating the spectral data, afterwards take exp of interpolated data.
If any zero or negative values are present in a spectrum, then the log is NOT taken.
force_scipy_interpolator:
None, optional
If None: the value from interp_settings is used.
If False: numpy.interp function is used for linear interpolation when no or linear extrapolation is used/required (fast!).
scipy_interpolator:
None, optional
If None: the value from interp_settings is used.
options: ‘InterpolatedUnivariateSpline’, ‘interp1d’
Returns:
returns:
ndarray of interpolated spectral data.
(.shape = (number of spectra + 1, number of wavelength in wl_new))
Notes:
1. Type of extrapolation: ‘quadratic’ vs ‘linear’; impact of extrapolating log spectral values:
Using a ‘linear’ or ‘quadratic’ extrapolation, as mentioned in
CIE167:2005 and CIE15:2018, resp., can lead to extreme large values
when setting :extrap_log: (not CIE recommended) to True.
A quick test with the IES TM30 spectra (400 nm - 700 nm, 5 nm spacing)
shows that ‘linear’ is better than ‘quadratic’ in terms of
mean, median and max DEu’v’ with the original spectra (380 nm - 780 nm, 5 nm spacing).
This conferms the recommendation from CIE167:2005 to use ‘linear’ extrapolation.
Setting :extrap_log: to True reduces the median, but inflates the mean due to some
extremely large DEu’v’ values. However, the increase in mean and max DEu’v’ is much
larger for the ‘quadratic’ case, suggesting that ‘linear’ extrapolation
is likely a more suitable recommendation. When using a 1 nm spacing
‘linear’ is more similar to ‘quadratic’ when :extrap_log: is False, otherwise ‘linear’
remains the ‘best’. Hence the choice to use the CIE167:2005 recommended linear extrapolation as default!
luxpy.spectrum.spd(data=None, wl=None, interp_settings=None, kind=None, extrap_kind=None, extrap_values=None, sep=',', header=None, datatype='spd', norm_type=None, norm_f=None, **kwargs)[source]
All-in-one function that can:
1. Read spectral data from data file or take input directly as ndarray.
2. Interpolate spectral data.
3. Normalize spectral data.
Args:
data:
- str with path to file containing spectral data
- ndarray with spectral data
(.shape = (number of spectra + 1, number of original wavelengths))
wl:
None, optional
New wavelength range for interpolation.
If None: no interpolation will be done.
kind:
None, optional
- None: use defaults in interp_settings for specified datatype.
- str with interpolation type or spectrum type (if spectrum type: overrides anything set in :datatype:)
extrap_kind:
None, optional
- None: use defaults in interp_settings for specified datatype.
- str with extrapolation type
extrap_values:
None, optional
Controls extrapolation. See cie_interp.
header:
None or ‘infer’, optional
- None: no header in file
- ‘infer’: infer headers from file
sep:
‘,’ or ‘ ‘ or other char, optional
Column separator in case :data: specifies a data file.
datatype’:
‘spd’ (light source) or ‘rfl’ (reflectance) or ‘cmf’ (color matching functions) or ‘none’ (undefined), optional
Specifies a type of spectral data.
Is used to determine interpolation and extrapolation defaults.
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 with interpolated and/or normalized spectral data.
luxpy.spectrum.xyzbar(cieobs='1931_2', src='dict', wl_new=None, interp_settings=None, kind=None, extrap_kind=None, extrap_values=None)[source]

Get color matching functions.

Args:
cieobs:
luxpy._CIEOBS, optional
Sets the type of color matching functions to load.
src:
‘dict’ or ‘file’, optional
Determines whether to load cmfs from file (./data/cmfs/)
or from dict defined in .cmf.py
wl:
None, optional
New wavelength range for interpolation.
If None: no interpolation is done.
kind:
None, optional
- None: use defaults in interp_settings for “cmf” datatype.
- str with interpolation type
extrap_kind:
None, optional
- None: use defaults in interp_settings for specified datatype.
- str with extrapolation type
extrap_values:
None, optional
Controls extrapolation. See cie_interp.
Returns:
returns:
ndarray with CMFs
References:
  1. CIE15:2018, “Colorimetry,” CIE, Vienna, Austria, 2018.

luxpy.spectrum.vlbar(cieobs='1931_2', K=None, src='dict', wl_new=None, interp_settings=None, kind=None, extrap_kind=None, extrap_values=None, out=1)[source]

Get Vlambda functions.

Args:
cieobs:
str or ndarray, optional
If str: Sets the type of Vlambda function to obtain.
K:
None, optional
Luminous efficacy of radiation.
Must be supplied if cieobs is an array
src:
‘dict’ or array, optional
- ‘dict’: get from ybar from _CMF
- ‘array’: ndarray in :cieobs:
Determines whether to load cmfs from file (./data/cmfs/)
or from dict defined in .cmf.py
Vlambda is obtained by collecting Ybar.
wl:
None, optional
New wavelength range for interpolation.
If None: no interpolation is done.
kind:
None, optional
- None: use defaults in interp_settings for “cmf” datatype.
- str with interpolation type
extrap_kind:
None, optional
- None: use defaults in interp_settings for specified datatype.
- str with extrapolation type
extrap_values:
None, optional
Controls extrapolation. See cie_interp.
out:
1 or 2, optional
1: returns Vlambda
2: returns (Vlambda, Km)
Returns:
returns:
ndarray with Vlambda of type :cieobs:
References:
  1. CIE15:2018, “Colorimetry,” CIE, Vienna, Austria, 2018.

luxpy.spectrum.vlbar_cie_mesopic(m=[1], wl_new=None, out=1, Lp=None, Ls=None, SP=None, interp_settings=None, kind=None, extrap_kind=None, extrap_values=None)[source]

Get CIE mesopic luminous efficiency function Vmesm according to CIE191:2010

Args:
m:
float or list or ndarray with mesopic adaptation coefficients
wl:
None, optional
New wavelength range for interpolation.
If None: no interpolation is done.
out:
1 or 2, optional
1: returns Vmesm
2: returns (Vmes, Kmesm)
Lp:
None, optional
float or ndarray with photopic adaptation luminance
If not None: use this (and SP or Ls) to calculate the
mesopic adaptation coefficient
Ls:
None, optional
float or ndarray with scotopic adaptation luminance
If None: SP must be supplied.
SP:
None, optional
S/P ratio
If None: Ls must be supplied.
kind:
None, optional
- None: use defaults in interp_settings for “cmf” datatype.
- str with interpolation type
extrap_kind:
None, optional
- None: use defaults in interp_settings for specified datatype.
- str with extrapolation type
extrap_values:
None, optional
Controls extrapolation. See cie_interp.
Returns:
Vmes:
ndarray with mesopic luminous efficiency function
for adaptation coefficient(s) m
Kmes:
ndarray with luminous efficacies of 555 nm monochromatic light
for for adaptation coefficient(s) m
Reference:

1. CIE 191:2010 Recommended System for Mesopic Photometry Based on Visual Performance. (ISBN 978-3-901906-88-6 ),

luxpy.spectrum.get_cie_mesopic_adaptation(Lp, Ls=None, SP=None)[source]

Get the mesopic adaptation state according to CIE191:2010

Args:
Lp:
float or ndarray with photopic adaptation luminance
Ls:
None, optional
float or ndarray with scotopic adaptation luminance
If None: SP must be supplied.
SP:
None, optional
S/P ratio
If None: Ls must be supplied.
Returns:
Lmes:
mesopic adaptation luminance
m:
mesopic adaptation coefficient
Reference:

1. CIE 191:2010 Recommended System for Mesopic Photometry Based on Visual Performance. (ISBN 978-3-901906-88-6 ),

luxpy.spectrum.spd_to_xyz(spds, cieobs='1931_2', K=None, relative=True, rfl=None, out=None, cie_std_dev_obs=None, rounding=None, matmul=True, interpolate_to='spd', interp_settings={'cmf': {'etype': 'linear', 'fill_value': None, 'itype': 'linear', 'negative_values_allowed': False}, 'general': {'choose_most_efficient_interpolator': False, 'extrap_log': False, 'force_scipy_interpolator': False, 'interp_log': False, 'scipy_interpolator': 'interp1d', 'sprague_allowed': False, 'sprague_method': 'spargue_cie224_2017'}, 'none': {'etype': 'linear', 'fill_value': None, 'itype': 'linear', 'negative_values_allowed': False}, 'rfl': {'etype': 'linear', 'fill_value': None, 'itype': 'cubic', 'negative_values_allowed': False}, 'spd': {'etype': 'linear', 'fill_value': None, 'itype': 'cubic', 'negative_values_allowed': False}}, kind=None, extrap_kind=None, extrap_values=None, negative_values_allowed=None, sprague_allowed=None, sprague_method='sprague_cie224_2017', force_scipy_interpolator=None, scipy_interpolator=None, choose_most_efficient_interpolator=None, verbosity=0)[source]

Calculate tristimulus values from spectral data.

Args:
spds:
ndarray with (N+1,number of wavelengths)-dimensional spectral data (0-row: wavelengths, remaining n rows: data)
cieobs:
luxpy._CIEOBS or str or ndarray, optional
Determines the color matching functions to be used in the
calculation of XYZ.
If ndarray: color matching functions (3+1,number of wavelengths). (0-row: spectral wavelengths)
K:
None, optional
e.g. K = 683 lm/W for ‘1931_2’ (relative == False)
or K = 100/sum(spd*dl) (relative == True)
relative:
True, optional
If False: use K, else calculate K = 100 ./ Yw
rfl:
None, optional
If not None, must be ndarray with (M+1,number of wavelengths)-dimensional spectral reflectance data (0-row: wavelengths, remaining n rows: data)
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.
matmul:
True, optional
If True: use matrix multiplication and broadcasting to calculate tristimulus values, else use sumproduct with loop over cmfs.
rounding:
None, optional
if not None: round xyz output to this many decimals. (see math.round for more options).
interpolate_to:
‘spd’, optional
Interpolate other spectral data to the wavelengths of specified spectral type.
Options: ‘spd’ or ‘cmf’
interp_settings:
Nested Dict with interpolation settings per spectral type [‘spd’,’cmf’,’rfl’,’none’].
Keys per spectrum type:
- ‘itype’: str
supported options for str: ‘linear’, ‘quadratic’, ‘cubic’
- ‘etype’: str
supported options:
+ ‘extrapolate’
+ ‘zeros’: out-of-bounds values are filled with zeros
+ ‘const’: out-of-bounds values are filled with nearest value
+ ‘fill_value’: value of tuple (2,) of values is used to fill out-of-bounds values
- ‘fill_value’: str or float or int or tupple, optional
If ext == ‘fill_value’: use fill_value to set lower- and upper-out-of-bounds values when extrapolating
(‘extrapolate’ when etype requires extrapolation)
negative_values_allowed:
None, optional
If False: after interpolation/extrapolation, any negative values are clipped to zero.
If None: use the value in the interp_settings dictionary.
force_scipy_interpolator:
None, optional
If False: numpy.interp function is used for linear interpolation when no or linear extrapolation is used/required (fast!).
If None: use the value in the interp_settings dictionary.
scipy_interpolator:
None, optional
options: ‘InterpolatedUnivariateSpline’, ‘interp1d’
If None: use the value in the interp_settings dictionary.
choose_most_efficient_interpolator:
None, optional
If True: Choose most efficient interpolator
If None: use the value in the interp_settings dictionary.
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.

luxpy.spectrum.spd_to_xyz_barebones(spd, cmf, K=1.0, relative=True, rfl=None, wl=None, matmul=True)[source]

Calculate tristimulus values from equal wavelength spectral data.

Args:
spd:
ndarray with (N+1,number of wavelengths)-dimensional spectral data (0-row: wavelengths, remaining n rows: data)
cmf:
color matching functions (3+1,number of wavelengths). (0-row: spectral wavelengths)
K:
1.0, optional
e.g. K = 683 lm/W for ‘1931_2’ (relative == False)
or K = 100/sum(spd*dl) (relative == True)
relative:
False, optional
If False: use K, else calculate K = 100 ./ Yw
rfl:
None, optional
If not None, must be ndarray with (M+1,number of wavelengths)-dimensional spectral reflectance data (0-row: wavelengths, remaining n rows: data)
wl:
None, optional
If None: first row of all spectral data are the wavelengths, else wl is ndarray with corresponding wavelengths of shape (number of wavelength,).
matmul:
True, optional
If True: use matrix multiplication and broadcasting to calculate tristimulus values, else use sumproduct with loop over cmfs.
Returns:
XYZ, XYZw:
ndarrays with tristimulus values (X,Y,Z are on last dimension)
- XYZ: tristim. values of all rfls (if rfl is None: same as XYZw) [M,N,3]
- XYZw: tristim. values of all white points (purely spds are used) [N,3]
luxpy.spectrum.spd_to_ler(data, cieobs='1931_2', K=None, interp_settings=None, kind=None, extrap_kind=None, extrap_values=None)[source]

Calculates Luminous efficacy of radiation (LER) from spectral data.

Args:
data:
ndarray 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.
cieobs:
luxpy._CIEOBS, optional
Determines the color matching function set used in the
calculation of LER. For cieobs = ‘1931_2’ the ybar CMF curve equals
the CIE 1924 Vlambda curve.
K:
None, optional
e.g. K = 683 lm/W for ‘1931_2’
Returns:
ler:
ndarray of LER values.
References:
  1. CIE15:2018, “Colorimetry,” CIE, Vienna, Austria, 2018.

luxpy.spectrum.spd_to_power(data, ptype='ru', cieobs='1931_2', K=None, interp_settings=None, kind=None, extrap_kind=None, extrap_values=None)[source]

Calculate power of spectral data in radiometric, photometric or quantal energy units.

Args:
data:
ndarray with spectral data
ptype:
‘ru’ or str, optional
str: - ‘ru’: in radiometric units
- ‘pu’: in photometric units
- ‘pusa’: in photometric units with Km corrected
to standard air (cfr. CIE TN003-2015)
- ‘qu’: in quantal energy units
cieobs:
_CIEOBS or str or ndarray, optional
Type of cmf set to use for photometric units.
K:
None, optional
Luminous efficacy of radiation, must be supplied if cieobs is an array.
Returns:
returns:
ndarray with normalized spectral data (SI units)
luxpy.spectrum.detect_peakwl(spd, n=1, verbosity=1, **kwargs)[source]

Detect primary peak wavelengths and fwhm in spectrum spd.

Args:
spd:
ndarray with spectral data (2xN).
First row should be wavelengths.
n:
1, optional
The number of peaks to try to detect in spd.
verbosity:
Make a plot of the detected peaks, their fwhm, etc.
kwargs:
Additional input arguments for scipy.signal.find_peaks.
Returns:
prop:
list of dictionaries with keys:
- ‘peaks_idx’ : index of detected peaks
- ‘peaks’ : peak wavelength values (nm)
- ‘heights’ : height of peaks
- ‘fwhms’ : full-width-half-maxima of peaks
- ‘fwhms_mid’ : wavelength at the middle of the fwhm-range of the peaks (if this is different from the values in ‘peaks’, then their is some non-symmetry in the peaks)
- ‘fwhms_mid_heights’ : height at the middle of the peak
luxpy.spectrum.create_spectral_interpolator(S, wl=None, kind=1, ext=0)[source]

Create an interpolator of kind for spectral data S.

Args:
S:
Spectral data array
Row 0 should contain wavelengths if :wl: is None.
wl:
None, optional
Wavelengths
If wl is None: row 0 of S should contain wavelengths.
kind:
1, optional
Order of spline functions used in interpolator (1<=kind<=5)
Interpolator = scipy.interpolate.InterpolatedUnivariateSpline
Returns:
interpolators:
List of interpolator functions for each row in S (minus wl-row if present).
Note:
  1. Nan’s, +infs, -infs will be ignored when generating the interpolators.

luxpy.spectrum.wls_shift(shfts, log_shft=False, wl=None, S=None, interpolators=None, kind=1, ext=0)[source]

Wavelength-shift array S over shft wavelengths.

Args:
shfts:
array with wavelength shifts.
log_shft:
False, optional
If True: shift in log10 wavelength space.
wl:
None, optional
Wavelengths to return
If wl is None: S will be used and row 0 should contain wavelengths.
S:
None, optional
Spectral data array.
Row 0 should contain wavelengths if :wl: is None.
If None: interpolators should be precalculated + wl must contain wavelength array !
interpolators:
None, optional
Pre-calculated interpolators for the (non-wl) rows in S.
If None: will be generated from :S: (which should contain wavelengths on row 0)
with specified :kind: using scipy.interpolate.InterpolatedUnivariateSpline
If not None and S is not None: interpolators take precedence
kind:
1, optional
Order of spline functions used in interpolator (1<=kind<=5)
Returns:
wavelength_shifted:
array with wavelength-shifted S (or interpolators) evaluated at wl.
(row 0 contains)
Note:
  1. Nan’s, +infs, -infs will be ignored when generating the interpolators.

luxpy.spectrum.spd_to_xyz_legacy(data, relative=True, rfl=None, cieobs='1931_2', K=None, out=None, cie_std_dev_obs=None)[source]

Calculates xyz tristimulus values from spectral data.

Args:
data:
ndarray 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.

luxpy.spectrum.cri_ref(ccts, wl3=None, ref_type='ciera', mix_range=None, cieobs=None, cieobs_Y_normalization=None, norm_type=None, norm_f=None, force_daylight_below4000K=False, n=None, daylight_locus=None, round_daylightphase_Mi_to_cie_recommended=False, interp_settings=None)[source]

Calculates a reference illuminant spectrum based on cct for color rendering index calculations .

Args:
ccts:
list of int/floats or ndarray with ccts.
wl3:
None, optional
New wavelength range for interpolation.
Defaults to wavelengths specified by luxpy._WL3.
ref_type:
str or list[str], optional
Specifies the type of reference spectrum to be calculated.
Defaults to luxpy._CRI_REF_TYPE.
If :ref_type: is list of strings, then for each cct in :ccts:
a different reference illuminant can be specified.
If :ref_type: == ‘spd’, then :ccts: is assumed to be an ndarray
of reference illuminant spectra.
mix_range:
None or ndarray, optional
Determines the cct range between which the reference illuminant is
a weigthed mean of a Planckian and Daylight Phase spectrum.
Weighthing is done as described in IES TM30:
SPDreference = (Te-T)/(Te-Tb)*Planckian+(T-Tb)/(Te-Tb)*daylight
with Tb and Te are resp. the starting and end CCTs of the
mixing range and whereby the Planckian and Daylight SPDs
have been normalized for equal luminous flux.
If None: use the default specified for :ref_type:.
Can be a ndarray with shape[0] > 1, in which different mixing
ranges will be used for cct in :ccts:.
cieobs:
None, optional
Required when calculating daylightphase (adjust locus parameters to cieobs)
If None: value in _CRI_REF_TYPES will be used (with None here corresponding to _CIEOBS).
cieobs_Y_normalization:
None, optional
Required for the normalization of the Planckian and Daylight SPDs
when calculating a ‘mixed’ reference illuminant.
If None: value in _CRI_REF_TYPES will be used,
with None here resulting in the use of the value as specified in :cieobs:
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.
force_daylight_below4000K:
False or True, optional
Daylight locus approximation is not defined below 4000 K,
but by setting this to True, the calculation can be forced to
calculate it anyway.
n:
None, optional
Refractive index (for use in calculation of blackbody radiators).
If None: use the one stored in _BB[‘n’]
daylight_locus:
None, optional
dict with xD(T) and yD(xD) parameters to calculate daylight locus
for specified cieobs.
If None: use pre-calculated values.
If ‘calc’: calculate them on the fly.
round_daylightphase_Mi_to_cie_recommended:
False, optional
If True: Round M1, M2 values to 3 decimals as recommended by CIE (not that TM30 does not do this, which gives slight errors when calculating a daylight phase (equivalent of around 0.75 K for 6500 K illuminant))
Rounding causes larger errors from target CCT! Therefore, the default is set to False!
Note that neither CIE224-2017 or IES TM30 rounds M1 and M2 to 3 decimals!
Returns:
returns:
ndarray with reference illuminant spectra.
(:returns:[0] contains wavelengths)
Note:

Future versions will have the ability to take a dict as input for ref_type. This way other reference illuminants can be specified than the ones in _CRI_REF_TYPES.

luxpy.spectrum.blackbody(cct, wl3=None, n=None, relative=True)[source]

Calculate blackbody radiator spectrum for correlated color temperature (cct).

Args:
cct:
int or float
(for list of cct values, use cri_ref() with ref_type = ‘BB’)
wl3:
None, optional
New wavelength range for interpolation.
Defaults to wavelengths specified by luxpy._WL3.
n:
None, optional
Refractive index.
If None: use the one stored in _BB[‘n’]
relative:
False, optional
True: return relative spectrum normalized to 560 nm
False: return absolute spectral radiance (Planck’s law; W/(sr.m².nm))
Returns:
returns:
ndarray with blackbody radiator spectrum
(:returns:[0] contains wavelengths)
References:
  1. CIE15:2018, “Colorimetry,” CIE, Vienna, Austria, 2018.

luxpy.spectrum.spd_to_indoor(spd, interp_settings=None)[source]

Convert spd to indoor variant by multiplying it with the CIE spectral transmission for glass.

luxpy.spectrum.daylightlocus(cct, force_daylight_below4000K=False, cieobs=None, daylight_locus=None, use_published_daylightlocus_coeffs_when_cieobs_is_1931_2=True, interp_settings=None)[source]

Calculates daylight chromaticity (xD,yD) from correlated color temperature (cct).

Args:
cct:
int or float or list of int/floats or ndarray
force_daylight_below4000K:
False or True, optional
Daylight locus approximation is not defined below 4000 K,
but by setting this to True, the calculation can be forced to
calculate it anyway.
cieobs:
CMF set corresponding to xD, yD output.
If None: use default CIE15-20xx locus for ‘1931_2’
Else: use the locus specified in :daylight_locus:
daylight_locus:
None, optional
dict with xD(T) and yD(xD) parameters to calculate daylight locus
for specified cieobs.
If None: use pre-calculated values.
If ‘calc’: calculate them on the fly.
use_published_daylightlocus_coeffs_when_cieobs_is_1931_2:
True, optional
Use published coefficients for CIE 1931 2° CMFs (see CIE015 colorimetry)
Returns:
(xD, yD):
(ndarray of x-coordinates, ndarray of y-coordinates)
References:
  1. CIE15:2018, “Colorimetry,” CIE, Vienna, Austria, 2018.

luxpy.spectrum.daylightphase(cct, wl3=None, nominal_cct=False, force_daylight_below4000K=False, verbosity=None, n=None, cieobs=None, daylight_locus=None, daylight_Mi_coeffs=None, force_tabulated_xyD_Mi_when_cieobs_is_1931_2=True, round_Mi_to_cie_recommended=False, interp_settings=None)[source]

Calculate daylight phase spectrum for correlated color temperature (cct).

Args:
cct:
int or float
(for list of cct values, use cri_ref() with ref_type = ‘DL’)
wl3:
None, optional
New wavelength range for interpolation.
Defaults to wavelengths specified by luxpy._WL3.
nominal_cct:
False, optional
If cct is nominal (e.g. when calculating D65): multiply cct first
by 1.4388/1.4380 to account for change in ‘c2’ in definition of Planckian.
cieobs:
None or str or ndarray, optional
CMF set to use when calculating coefficients for daylight locus and for M1, M2 weights.
If None: use standard coefficients for CIE 1931 2° CMFs (for Si at 10 nm).
Else: calculate coefficients following Appendix C of CIE15-2004 and Judd (1964).
force_daylight_below4000K:
False or True, optional
Daylight locus approximation is not defined below 4000 K,
but by setting this to True, the calculation can be forced to
calculate it anyway.
verbosity:
None, optional
If None: do not print warning when CCT < 4000 K.
n:
None, optional
Refractive index (for use in calculation of blackbody radiators).
If None: use the one stored in _BB[‘n’]
daylight_locus:
None, optional
dict with xD(T) and yD(xD) parameters to calculate daylight locus
for specified cieobs.
If None: use pre-calculated values.
If ‘calc’: calculate them on the fly.
daylight_Mi_coeffs:
None, optional
dict with coefficients for M1 & M2 weights for specified cieobs.
If None: use pre-calculated values.
If ‘calc’: calculate them on the fly.
force_tabulated_xyD_Mi_when_cieobs_is_1931_2:
True, optional
If cieobs is ‘1931_2’, then use tabulated values for xD, yD and Mi coefficients.
round_daylightphase_Mi_to_cie_recommended:
False, optional
If True: Round M1, M2 values to 3 decimals as recommended by CIE (not that TM30 does not do this, which gives slight errors when calculating a daylight phase (equivalent of around 0.75 K for 6500 K illuminant))
Rounding causes larger errors from target CCT! Therefore, the default is set to False!
Note that neither CIE224-2017 or IES TM30 rounds M1 and M2 to 3 decimals!
Returns:
returns:
ndarray with daylight phase spectrum
(:returns:[0] contains wavelengths)
References:
  1. CIE15:2018, “Colorimetry,” CIE, Vienna, Austria, 2018.

2. Judd, MacAdam, Wyszecki, Budde, Condit, Henderson, & Simonds (1964). Spectral Distribution of Typical Daylight as a Function of Correlated Color Temperature. J. Opt. Soc. Am., 54(8), 1031–1040.

luxpy.spectrum.get_daylightloci_parameters(ccts=None, cieobs=None, wl3=[300, 830, 10], verbosity=0, use_1931_2_published_daylightlocus_coeffs=False, interp_settings=None)[source]

Get parameters for the daylight loci functions xD(1000/CCT) and yD(xD).

Args:
ccts:
None, optional
ndarray with CCTs, if None: ccts = np.arange(4000,25000,250)
cieobs:
None or list of str or list of ndarrays, optional
CMF sets to determine parameters for.
If None: get for all CMFs sets in _CMF (except scoptopic and deviate observer)
wl3:
[300,830,10], optional
Wavelength range and spacing of daylight phases to be determined
from ‘1931_2’. The default setting results in parameters very close
to that in CIE15-2004/2018.
use_1931_2_published_daylightlocus_coeffs:
False, optional
Use published coefficients for CIE 1931 2° CMFs (see CIE015 colorimetry)
verbosity:
0, optional
print parameters and make plots.
Returns:
dayloci:
dict with parameters for each cieobs
If cieobs contains ndarrays, then keys in dict will be
labeled ‘cmf_0’, ‘cmf_1’, …
luxpy.spectrum.get_daylightphase_Mi_coeffs(cieobs=None, wl3=None, S012_daylightphase=None, use_1931_2_published_Mcoeffs=False, interp_settings=None)[source]

Get coefficients of Mi weights of daylight phase for specific cieobs

Args:
cieobs:
None or str or ndarray or list of str or list of ndarrays, optional
CMF set to get coefficients for.
If None: get coeffs for all CMFs in _CMF
wl3:
None, optional
Wavelength range to interpolate S012_daylightphase to.
S012_daylightphase:
None, optional
Daylight phase component functions.
If None: use _S012_DAYLIGHTPHASE
use_1931_2_published_Mcoeffs:
False, optional
Use published coefficients of CIE 1931 2° CMFs (see CIE015 colorimetry), even when cieobs is not ‘1931_2’!
Returns:
Mcoeffs:
Dictionary with i,j,k,i1,j1,k1,i2,j2,k2 for each cieobs in :cieobs:
If cieobs contains ndarrays, then keys in dict will be
labeled ‘cmf_0’, ‘cmf_1’, …
luxpy.spectrum.read_spdx(spdx)[source]

Read xml file or convert xml string with spdx data to dictionary.

Args:
spdx:
xml string or file with spdx data.
Returns:
spdx_dict:
spdx data in a dictionary.
luxpy.spectrum.write_spdx(spdx_dict, filename=None)[source]

Convert spdx dictionary to xml string (and write to .spdx file).

Args:
spdx_dict:
dictionary with spdx keys (see _SPDX for keys).
filename:
None, optional
string with filename to write xml data to.
Returns:
spdx_xml:
string with xml data in spdx dictionary.

SPD class

py:
  • SPD.py

namespace:

luxpy

class luxpy.spectrum.SPD.SPD(spd=None, wl=None, ax0iswl=True, dtype='spd', wl_new=None, interp_method='auto', negative_values_allowed=False, extrap_values='ext', norm_type=None, norm_f=1, header=None, sep=',')[source]
read_csv_(file, header=None, sep=',')[source]

Reads spectral data from file.

Args:
file:
filename
header:
None or ‘infer’, optional
If ‘infer’: headers will be inferred from file itself.
If None: no headers are expected from file.
sep:
‘,’, optional
Column separator.
Returns:
returns:
ndarray with spectral data (first row are wavelengths)
Note:

Spectral data in file should be organized in columns with the first column containing the wavelengths.

plot(ylabel='Spectrum', wavelength_bar=True, *args, **kwargs)[source]

Make a plot of the spectral data in SPD instance.

Returns:
returns:
handle to current axes.
mean()[source]

Take mean of all spectra in SPD instance.

sum()[source]

Sum all spectra in SPD instance.

dot(S)[source]

Take dot product with instance of SPD.

add(S)[source]

Add instance of SPD.

sub(S)[source]

Subtract instance of SPD.

mul(S)[source]

Multiply by instance of SPD.

div(S)[source]

Divide by instance of SPD.

pow(n)[source]

Raise SPD instance to power n.

get_()[source]

Get spd as ndarray in instance of SPD.

setwlv(spd)[source]

Store spd ndarray in fields wl and values of instance of SPD.

getwld_()[source]

Get wavelength spacing of SPD instance.

Returns:
returns:
float: for equal wavelength spacings
ndarray (.shape = (n,)): for unequal wavelength spacings
normalize(norm_type=None, norm_f=1, cieobs='1931_2', K=None, interp_settings=None)[source]

Normalize spectral power distributions in SPD instance.

Args:
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
Determines size of normalization for ‘max’ and ‘area’ or which wavelength is normalized to 1 for ‘lambda’ option.
cieobs:
_CIEOBS or str, optional
Type of cmf set to use for normalization using photometric units (norm_type == ‘pu’)
cie_interp(wl_new, kind='auto', sprague_allowed=False, sprague_method='sprague_cie224_2017', negative_values_allowed=False, extrap_values='ext', extrap_kind='linear', extrap_log=False)[source]

Interpolate / extrapolate spectral data following standard CIE15-2018.

The interpolation type depends on the spectrum type defined in :kind:.
Args:
wl_new:
ndarray with new wavelengths
kind:
‘auto’, optional
If :kind: is None, return original data.
If :kind: is a spectrum type, the correct
interpolation type if automatically chosen.
(The use of the slow(er) ‘sprague5’ can be toggled on using :sprague_allowed:).
If kind = ‘auto’: use self.dtype
Or :kind: can be any interpolation type supported by
luxpy.math.interp1
or can be ‘sprague’ (uses luxpy.math.interp1_sprague5) or ‘sprague_cie224_2017’ (uses luxpy.math.interp1_sprague_cie224_2017).
sprague_allowed:
None, optional
If None: the value from interp_settings is used.
If True: When kind is a spectral data type that corresponds to ‘cubic’ interpolation,
then a cubic spline interpolation will be used in case of
unequal wavelength spacings, otherwise a 5th order Sprague or Sprague as defined in CIE224-2017 will be used.
If False: always use ‘cubic’, don’t use ‘sprague5’ or ‘sprague_cie224_2017’.
This is the default, as differences are minimal and
use of the ‘sprague’ functions is a lot slower (‘sprague5’ = slowest )!
sprague_method:
‘sprague_cie224_2017’, optional
Specific sprague method used for interpolation. (Only for equal spacings, ‘sprague_cie224_2017’ also on for 5 nm -> 1nm)
- options: ‘sprague5’ (use luxpy.math.interp1_sprague5), ‘sprague_cie224_2017’ (use luxpy.interp1_sprague_cie224_2017)
negative_values_allowed:
False, optional
If False: negative values are clipped to zero
extrap_values:
‘ext’, optional
If ‘ext’: extrapolate using ‘linear’ (‘cie167:2005’ r), ‘quadratic’ (‘cie15:2018’)
‘nearest’ (‘cie15:2004’) recommended or other (e.g. ‘cubic’) methods.
If None: use CIE15:2004 recommended ‘nearest value’ approach when extrapolating.
If float or list or ndarray, use those values to fill extrapolated value(s).
extrap_kind:
‘linear’, optional
Extrapolation method used when :extrap_values: is set to ‘ext’.
Options: ‘linear’ (‘cie167:2005’), ‘quadratic’ (‘cie15:2018’),
‘nearest’ (‘cie15:2004’), ‘cubic’
CIE15:2018 states that based on a 2017 paper by Wang that ‘quadratic’ is ‘better’.
However, no significant difference was found between ‘quadratic’ and ‘linear’ methods.
Also see note 1 below, for why the CIE67:2005 recommended ‘linear’ extrapolation
is set as the default.
extrap_log:
False, optional
If True: extrap the log of the spectral values
(not CIE recommended but in most cases seems to give a
more realistic estimate, but can sometimes seriously fail,
especially for the ‘quadratic’ extrapolation case (see note 1)!!!)
Returns:
returns:
ndarray of interpolated spectral data.
(.shape = (number of spectra+1, number of wavelength in wl_new))
Notes:
1. Type of extrapolation: ‘quadratic’ vs ‘linear’; impact of extrapolating log spectral values:
Using a ‘linear’ or ‘quadratic’ extrapolation, as mentioned in
CIE167:2005 and CIE15:2018, resp., can lead to extreme large values
when setting :extrap_log: (not CIE recommended) to True.
A quick test with the IES TM30 spectra (400 nm - 700 nm, 5 nm spacing)
shows that ‘linear’ is better than ‘quadratic’ in terms of
mean, median and max DEu’v’ with the original spectra (380 nm - 780 nm, 5 nm spacing).
This conferms the recommendation from CIE167:2005 to use ‘linear’ extrapolation.
Setting :extrap_log: to True reduces the median, but inflates the mean due to some
extremely large DEu’v’ values. However, the increase in mean and max DEu’v’ is much
larger for the ‘quadratic’ case, suggesting that ‘linear’ extrapolation
is likely a more suitable recommendation. When using a 1 nm spacing
‘linear’ is more similar to ‘quadratic’ when :extrap_log: is False, otherwise ‘linear’
remains the ‘best’. Hence the choice to use the CIE167:2005 recommended linear extrapolation as default!
to_xyz(relative=True, rfl=None, cieobs='1931_2', out=None)[source]

Calculates xyz tristimulus values from spectral data and return as instance of XYZ.

Args:
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 don’t match those of :data:
cieobs:
luxpy._CIEOBS, optional
Determines the color matching functions to be used in the calculation of XYZ.
out:
None or 1 or 2, optional
Determines number and shape of output. (see :returns:)
Returns:
returns:
luxpy.XYZ instance with ndarray .value field:
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.