Source code for colour.colorimetry.illuminants

"""
Illuminants
===========

Define the *CIE* illuminants computation related objects:

-   :func:`colour.sd_CIE_standard_illuminant_A`
-   :func:`colour.sd_CIE_illuminant_D_series`
-   :func:`colour.daylight_locus_function`

References
----------
-   :cite:`CIETC1-482004` : CIE TC 1-48. (2004). EXPLANATORY COMMENTS - 5. In
    CIE 015:2004 Colorimetry, 3rd Edition (pp. 68-68). ISBN:978-3-901906-33-6
-   :cite:`CIETC1-482004n` : CIE TC 1-48. (2004). 3.1 Recommendations
    concerning standard physical data of illuminants. In CIE 015:2004
    Colorimetry, 3rd Edition (pp. 12-13). ISBN:978-3-901906-33-6
-   :cite:`Wyszecki2000a` : Wyszecki, Günther, & Stiles, W. S. (2000).
    Equation I(1.2.1). In Color Science: Concepts and Methods, Quantitative
    Data and Formulae (p. 8). Wiley. ISBN:978-0-471-39918-6
-   :cite:`Wyszecki2000z` : Wyszecki, Günther, & Stiles, W. S. (2000). CIE
    Method of Calculating D-Illuminants. In Color Science: Concepts and
    Methods, Quantitative Data and Formulae (pp. 145-146). Wiley.
    ISBN:978-0-471-39918-6
"""

from __future__ import annotations

import numpy as np

from colour.algebra import LinearInterpolator
from colour.colorimetry import (
    SDS_BASIS_FUNCTIONS_CIE_ILLUMINANT_D_SERIES,
    SPECTRAL_SHAPE_DEFAULT,
    SpectralDistribution,
    SpectralShape,
    reshape_sd,
)
from colour.hints import ArrayLike, NDArrayFloat
from colour.utilities import as_float, as_float_array, tsplit

__author__ = "Colour Developers"
__copyright__ = "Copyright 2013 Colour Developers"
__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
__maintainer__ = "Colour Developers"
__email__ = "colour-developers@colour-science.org"
__status__ = "Production"

__all__ = [
    "sd_CIE_standard_illuminant_A",
    "sd_CIE_illuminant_D_series",
    "daylight_locus_function",
]


[docs] def sd_CIE_standard_illuminant_A( shape: SpectralShape = SPECTRAL_SHAPE_DEFAULT, ) -> SpectralDistribution: """ *CIE Standard Illuminant A* is intended to represent typical, domestic, tungsten-filament lighting. Its spectral distribution is that of a Planckian radiator at a temperature of approximately 2856 K. *CIE Standard Illuminant A* should be used in all applications of colorimetry involving the use of incandescent lighting, unless there are specific reasons for using a different illuminant. Parameters ---------- shape Spectral shape used to create the spectral distribution of the *CIE Standard Illuminant A*. Returns ------- :class:`colour.SpectralDistribution` *CIE Standard Illuminant A*. spectral distribution. References ---------- :cite:`CIETC1-482004n` Examples -------- >>> from colour import SpectralShape >>> sd_CIE_standard_illuminant_A(SpectralShape(400, 700, 10)) ... # doctest: +ELLIPSIS SpectralDistribution([[ 400. , 14.7080384...], [ 410. , 17.6752521...], [ 420. , 20.9949572...], [ 430. , 24.6709226...], [ 440. , 28.7027304...], [ 450. , 33.0858929...], [ 460. , 37.8120566...], [ 470. , 42.8692762...], [ 480. , 48.2423431...], [ 490. , 53.9131532...], [ 500. , 59.8610989...], [ 510. , 66.0634727...], [ 520. , 72.4958719...], [ 530. , 79.1325945...], [ 540. , 85.9470183...], [ 550. , 92.9119589...], [ 560. , 100. ...], [ 570. , 107.1837952...], [ 580. , 114.4363383...], [ 590. , 121.7312009...], [ 600. , 129.0427389...], [ 610. , 136.3462674...], [ 620. , 143.6182057...], [ 630. , 150.8361944...], [ 640. , 157.9791857...], [ 650. , 165.0275098...], [ 660. , 171.9629200...], [ 670. , 178.7686175...], [ 680. , 185.4292591...], [ 690. , 191.9309499...], [ 700. , 198.2612232...]], SpragueInterpolator, {}, Extrapolator, {'method': 'Constant', 'left': None, 'right': None}) """ values = ( 100 * (560 / shape.wavelengths) ** 5 * ( np.expm1((1.435 * 10**7) / (2848 * 560)) / np.expm1((1.435 * 10**7) / (2848 * shape.wavelengths)) ) ) return SpectralDistribution( values, shape.wavelengths, name="CIE Standard Illuminant A" )
[docs] def sd_CIE_illuminant_D_series( xy: ArrayLike, M1_M2_rounding: bool = True, shape: SpectralShape | None = None, ) -> SpectralDistribution: """ Return the spectral distribution of given *CIE Illuminant D Series* using given *CIE xy* chromaticity coordinates. Parameters ---------- xy *CIE xy* chromaticity coordinates. M1_M2_rounding Whether to round :math:`M1` and :math:`M2` variables to 3 decimal places in order to yield the internationally agreed values. shape Specifies the shape of the returned SpectralDistribution. Optional, default None. Returns ------- :class:`colour.SpectralDistribution` *CIE Illuminant D Series* spectral distribution. Notes ----- - The nominal *CIE xy* chromaticity coordinates which have been computed with :func:`colour.temperature.CCT_to_xy_CIE_D` must be given according to *CIE 015:2004* recommendation and thus multiplied by 1.4388 / 1.4380. - :math:`M1` and :math:`M2` variables are rounded to 3 decimal places according to *CIE 015:2004* recommendation. References ---------- :cite:`CIETC1-482004`, :cite:`Wyszecki2000z` Examples -------- >>> from colour.utilities import numpy_print_options >>> from colour.temperature import CCT_to_xy_CIE_D >>> CCT_D65 = 6500 * 1.4388 / 1.4380 >>> xy = CCT_to_xy_CIE_D(CCT_D65) >>> with numpy_print_options(suppress=True): ... sd_CIE_illuminant_D_series(xy) # doctest: +ELLIPSIS SpectralDistribution([[ 300. , 0.0341...], [ 305. , 1.6643...], [ 310. , 3.2945...], [ 315. , 11.7652...], [ 320. , 20.236 ...], [ 325. , 28.6447...], [ 330. , 37.0535...], [ 335. , 38.5011...], [ 340. , 39.9488...], [ 345. , 42.4302...], [ 350. , 44.9117...], [ 355. , 45.775 ...], [ 360. , 46.6383...], [ 365. , 49.3637...], [ 370. , 52.0891...], [ 375. , 51.0323...], [ 380. , 49.9755...], [ 385. , 52.3118...], [ 390. , 54.6482...], [ 395. , 68.7015...], [ 400. , 82.7549...], [ 405. , 87.1204...], [ 410. , 91.486 ...], [ 415. , 92.4589...], [ 420. , 93.4318...], [ 425. , 90.0570...], [ 430. , 86.6823...], [ 435. , 95.7736...], [ 440. , 104.8649...], [ 445. , 110.9362...], [ 450. , 117.0076...], [ 455. , 117.4099...], [ 460. , 117.8122...], [ 465. , 116.3365...], [ 470. , 114.8609...], [ 475. , 115.3919...], [ 480. , 115.9229...], [ 485. , 112.3668...], [ 490. , 108.8107...], [ 495. , 109.0826...], [ 500. , 109.3545...], [ 505. , 108.5781...], [ 510. , 107.8017...], [ 515. , 106.2957...], [ 520. , 104.7898...], [ 525. , 106.2396...], [ 530. , 107.6895...], [ 535. , 106.0475...], [ 540. , 104.4055...], [ 545. , 104.2258...], [ 550. , 104.0462...], [ 555. , 102.0231...], [ 560. , 100. ...], [ 565. , 98.1671...], [ 570. , 96.3342...], [ 575. , 96.0611...], [ 580. , 95.788 ...], [ 585. , 92.2368...], [ 590. , 88.6856...], [ 595. , 89.3459...], [ 600. , 90.0062...], [ 605. , 89.8026...], [ 610. , 89.5991...], [ 615. , 88.6489...], [ 620. , 87.6987...], [ 625. , 85.4936...], [ 630. , 83.2886...], [ 635. , 83.4939...], [ 640. , 83.6992...], [ 645. , 81.863 ...], [ 650. , 80.0268...], [ 655. , 80.1207...], [ 660. , 80.2146...], [ 665. , 81.2462...], [ 670. , 82.2778...], [ 675. , 80.281 ...], [ 680. , 78.2842...], [ 685. , 74.0027...], [ 690. , 69.7213...], [ 695. , 70.6652...], [ 700. , 71.6091...], [ 705. , 72.9790...], [ 710. , 74.349 ...], [ 715. , 67.9765...], [ 720. , 61.604 ...], [ 725. , 65.7448...], [ 730. , 69.8856...], [ 735. , 72.4863...], [ 740. , 75.087 ...], [ 745. , 69.3398...], [ 750. , 63.5927...], [ 755. , 55.0054...], [ 760. , 46.4182...], [ 765. , 56.6118...], [ 770. , 66.8054...], [ 775. , 65.0941...], [ 780. , 63.3828...], [ 785. , 63.8434...], [ 790. , 64.304 ...], [ 795. , 61.8779...], [ 800. , 59.4519...], [ 805. , 55.7054...], [ 810. , 51.959 ...], [ 815. , 54.6998...], [ 820. , 57.4406...], [ 825. , 58.8765...], [ 830. , 60.3125...]], LinearInterpolator, {}, Extrapolator, {'method': 'Constant', 'left': None, 'right': None}) """ xy = as_float_array(xy) x, y = tsplit(xy) M = 0.0241 + 0.2562 * x - 0.7341 * y M1 = (-1.3515 - 1.7703 * x + 5.9114 * y) / M M2 = (0.0300 - 31.4424 * x + 30.0717 * y) / M if M1_M2_rounding: M1 = np.around(M1, 3) M2 = np.around(M2, 3) S0 = SDS_BASIS_FUNCTIONS_CIE_ILLUMINANT_D_SERIES["S0"] S1 = SDS_BASIS_FUNCTIONS_CIE_ILLUMINANT_D_SERIES["S1"] S2 = SDS_BASIS_FUNCTIONS_CIE_ILLUMINANT_D_SERIES["S2"] if shape is not None: S0 = reshape_sd(S0, shape=shape, copy=False) S1 = reshape_sd(S1, shape=shape, copy=False) S2 = reshape_sd(S2, shape=shape, copy=False) distribution = S0.values + M1 * S1.values + M2 * S2.values return SpectralDistribution( distribution, S0.wavelengths, name=f"CIE xy ({xy[0]}, {xy[1]}) - CIE Illuminant D Series", interpolator=LinearInterpolator, )
[docs] def daylight_locus_function(x_D: ArrayLike) -> NDArrayFloat: """ Return the daylight locus as *CIE xy* chromaticity coordinates. Parameters ---------- x_D Chromaticity coordinate :math:`x_D`. Returns ------- :class:`numpy.ndarray` Daylight locus as *CIE xy* chromaticity coordinates. References ---------- :cite:`Wyszecki2000a` Examples -------- >>> daylight_locus_function(0.31270) # doctest: +ELLIPSIS 0.3291051... """ x_D = as_float_array(x_D) y_D = -3.000 * x_D**2 + 2.870 * x_D - 0.275 return as_float(y_D)