diff --git a/colour/colorimetry/generation.py b/colour/colorimetry/generation.py index 9ece8e42d..3a2cf11b1 100644 --- a/colour/colorimetry/generation.py +++ b/colour/colorimetry/generation.py @@ -409,8 +409,8 @@ def sd_gaussian_normal( >>> sd = sd_gaussian_normal(555, 25) >>> sd.shape SpectralShape(360.0, 780.0, 1.0) - >>> sd[555] # doctest: +ELLIPSIS - 1... + >>> sd[555] # doctest: +SKIP + 1.0 >>> sd[530] # doctest: +ELLIPSIS 0.6065306... """ @@ -465,16 +465,17 @@ def sd_gaussian_fwhm( >>> sd = sd_gaussian_fwhm(555, 25) >>> sd.shape SpectralShape(360.0, 780.0, 1.0) - >>> sd[555] # doctest: +ELLIPSIS - 1... - >>> sd[530] # doctest: +ELLIPSIS - 0.3678794... + >>> sd[555] # doctest: +SKIP + 1.0 + >>> sd[530] + 0.0625 """ settings = {"name": f"{peak_wavelength}nm - {fwhm} FWHM - Gaussian"} settings.update(kwargs) - values = np.exp(-(((shape.wavelengths - peak_wavelength) / fwhm) ** 2)) + mu, sigma = peak_wavelength, fwhm / (2 * np.sqrt(2 * np.log(2))) + values = np.exp(-((shape.wavelengths - mu) ** 2) / (2 * sigma**2)) return SpectralDistribution(values, shape.wavelengths, **settings) @@ -505,7 +506,7 @@ def sd_gaussian( peak at. sigma_fwhm Standard deviation :math:`sigma` of the gaussian spectral distribution - or Full width at half maximum, i.e. width of the gaussian spectral + or full width at half maximum, i.e. width of the gaussian spectral distribution measured between those points on the *y* axis which are half the maximum amplitude. shape @@ -535,17 +536,17 @@ def sd_gaussian( >>> sd = sd_gaussian(555, 25) >>> sd.shape SpectralShape(360.0, 780.0, 1.0) - >>> sd[555] # doctest: +ELLIPSIS - 1... + >>> sd[555] # doctest: +SKIP + 1.0 >>> sd[530] # doctest: +ELLIPSIS 0.6065306... >>> sd = sd_gaussian(555, 25, method="FWHM") >>> sd.shape SpectralShape(360.0, 780.0, 1.0) - >>> sd[555] # doctest: +ELLIPSIS - 1... - >>> sd[530] # doctest: +ELLIPSIS - 0.3678794... + >>> sd[555] # doctest: +SKIP + 1.0 + >>> sd[530] + 0.0625 """ method = validate_method(method, tuple(SD_GAUSSIAN_METHODS)) @@ -557,31 +558,29 @@ def sd_gaussian( def sd_single_led_Ohno2005( peak_wavelength: float, - fwhm: float, + half_spectral_width: float, shape: SpectralShape = SPECTRAL_SHAPE_DEFAULT, **kwargs: Any, ) -> SpectralDistribution: """ Return a single *LED* spectral distribution of given spectral shape at - given peak wavelength and full width at half maximum according to - *Ohno (2005)* method. + given peak wavelength and half spectral width :math:`\\Delta\\lambda_{0.5}` + according to *Ohno (2005)* method. Parameters ---------- peak_wavelength Wavelength the single *LED* spectral distribution will peak at. - fwhm - Full width at half maximum, i.e. width of the underlying gaussian - spectral distribution measured between those points on the *y* axis - which are half the maximum amplitude. + half_spectral_width + Half spectral width :math:`\\Delta\\lambda_{0.5}`. shape Spectral shape used to create the spectral distribution. Other Parameters ---------------- kwargs - {:func:`colour.colorimetry.sd_gaussian_fwhm`}, - See the documentation of the previously listed definition. + {:class:`colour.SpectralDistribution`}, + See the documentation of the previously listed class. Returns ------- @@ -606,14 +605,18 @@ def sd_single_led_Ohno2005( 1... """ - settings = {"name": f"{peak_wavelength}nm - {fwhm} FWHM LED - Ohno (2005)"} + settings = { + "name": f"{peak_wavelength}nm - {half_spectral_width} " + f"Half Spectral Width LED - Ohno (2005)" + } settings.update(kwargs) - sd = sd_gaussian_fwhm(peak_wavelength, fwhm, shape, **kwargs) - - sd.values = (sd.values + 2 * sd.values**5) / 3 + values = np.exp( + -(((shape.wavelengths - peak_wavelength) / half_spectral_width) ** 2) + ) + values = (values + 2 * values**5) / 3 - return sd + return SpectralDistribution(values, shape.wavelengths, **settings) SD_SINGLE_LED_METHODS: CanonicalMapping = CanonicalMapping( @@ -628,24 +631,18 @@ def sd_single_led_Ohno2005( def sd_single_led( peak_wavelength: float, - fwhm: float, shape: SpectralShape = SPECTRAL_SHAPE_DEFAULT, method: Literal["Ohno 2005"] | str = "Ohno 2005", **kwargs: Any, ) -> SpectralDistribution: """ Return a single *LED* spectral distribution of given spectral shape at - given peak wavelength and full width at half maximum according to given - method. + given peak wavelength according to given method. Parameters ---------- peak_wavelength Wavelength the single *LED* spectral distribution will peak at. - fwhm - Full width at half maximum, i.e. width of the underlying gaussian - spectral distribution measured between those points on the *y* - axis which are half the maximum amplitude. shape Spectral shape used to create the spectral distribution. method @@ -673,7 +670,7 @@ def sd_single_led( Examples -------- - >>> sd = sd_single_led(555, 25) + >>> sd = sd_single_led(555, half_spectral_width=25) >>> sd.shape SpectralShape(360.0, 780.0, 1.0) >>> sd[555] # doctest: +ELLIPSIS @@ -681,23 +678,22 @@ def sd_single_led( """ method = validate_method(method, tuple(SD_SINGLE_LED_METHODS)) + kwargs["shape"] = shape - return SD_SINGLE_LED_METHODS[method]( - peak_wavelength, fwhm, shape, **kwargs - ) + return SD_SINGLE_LED_METHODS[method](peak_wavelength, **kwargs) def sd_multi_leds_Ohno2005( peak_wavelengths: ArrayLike, - fwhm: ArrayLike, + half_spectral_widths: ArrayLike, peak_power_ratios: ArrayLike | None = None, shape: SpectralShape = SPECTRAL_SHAPE_DEFAULT, **kwargs: Any, ) -> SpectralDistribution: """ Return a multi *LED* spectral distribution of given spectral shape at - given peak wavelengths and full widths at half maximum according to - *Ohno (2005)* method. + given peak wavelengths, half spectral widths :math:`\\Delta\\lambda_{0.5}` + and peak power ratios according to *Ohno (2005)* method. The multi *LED* spectral distribution is generated using many single *LED* spectral distributions generated with :func:`colour.sd_single_led_Ohno2005` @@ -708,10 +704,8 @@ def sd_multi_leds_Ohno2005( peak_wavelengths Wavelengths the multi *LED* spectral distribution will peak at, i.e. the peaks for each generated single *LED* spectral distributions. - fwhm - Full widths at half maximum, i.e. widths of the underlying gaussian - spectral distributions measured between those points on the *y* axis - which are half the maximum amplitude. + half_spectral_widths + Half spectral widths :math:`\\Delta\\lambda_{0.5}`. peak_power_ratios Peak power ratios for each generated single *LED* spectral distributions. @@ -752,7 +746,9 @@ def sd_multi_leds_Ohno2005( """ peak_wavelengths = as_float_array(peak_wavelengths) - fwhm = np.resize(fwhm, peak_wavelengths.shape) + half_spectral_widths = np.resize( + half_spectral_widths, peak_wavelengths.shape + ) if peak_power_ratios is None: peak_power_ratios = ones(peak_wavelengths.shape) else: @@ -762,11 +758,13 @@ def sd_multi_leds_Ohno2005( sd = sd_zeros(shape) - for peak_wavelength, fwhm_s, peak_power_ratio in zip( - peak_wavelengths, fwhm, peak_power_ratios + for peak_wavelength, half_spectral_width, peak_power_ratio in zip( + peak_wavelengths, half_spectral_widths, peak_power_ratios ): sd += ( - sd_single_led_Ohno2005(peak_wavelength, fwhm_s, **kwargs) + sd_single_led_Ohno2005( + peak_wavelength, half_spectral_width, **kwargs + ) * peak_power_ratio ) @@ -777,7 +775,7 @@ def _format_array(a: NDArrayFloat) -> str: sd.name = ( f"{_format_array(peak_wavelengths)}nm - " - f"{_format_array(fwhm)} FWHM - " + f"{_format_array(half_spectral_widths)} FWHM - " f"{_format_array(peak_power_ratios)} Peak Power Ratios - " f"LED - Ohno (2005)" ) @@ -797,29 +795,19 @@ def _format_array(a: NDArrayFloat) -> str: def sd_multi_leds( peak_wavelengths: ArrayLike, - fwhm: ArrayLike, - peak_power_ratios: ArrayLike | None = None, shape: SpectralShape = SPECTRAL_SHAPE_DEFAULT, method: Literal["Ohno 2005"] | str = "Ohno 2005", **kwargs: Any, ) -> SpectralDistribution: """ Return a multi *LED* spectral distribution of given spectral shape at - given peak wavelengths and full widths at half maximum according to given - method. + given peak wavelengths. Parameters ---------- peak_wavelengths Wavelengths the multi *LED* spectral distribution will peak at, i.e. the peaks for each generated single *LED* spectral distributions. - fwhm - Full widths at half maximum, i.e. widths of the underlying gaussian - spectral distributions measured between those points on the *y* axis - which are half the maximum amplitude. - peak_power_ratios - Peak power ratios for each generated single *LED* spectral - distributions. shape Spectral shape used to create the spectral distribution. method @@ -849,8 +837,8 @@ def sd_multi_leds( -------- >>> sd = sd_multi_leds( ... np.array([457, 530, 615]), - ... np.array([20, 30, 20]), - ... np.array([0.731, 1.000, 1.660]), + ... half_spectral_widths=np.array([20, 30, 20]), + ... peak_power_ratios=np.array([0.731, 1.000, 1.660]), ... ) >>> sd.shape SpectralShape(360.0, 780.0, 1.0) @@ -859,7 +847,6 @@ def sd_multi_leds( """ method = validate_method(method, tuple(SD_MULTI_LEDS_METHODS)) + kwargs["shape"] = shape - return SD_MULTI_LEDS_METHODS[method]( - peak_wavelengths, fwhm, peak_power_ratios, shape, **kwargs - ) + return SD_MULTI_LEDS_METHODS[method](peak_wavelengths, **kwargs) diff --git a/colour/colorimetry/tests/test_generation.py b/colour/colorimetry/tests/test_generation.py index 583c58520..5c26d941d 100644 --- a/colour/colorimetry/tests/test_generation.py +++ b/colour/colorimetry/tests/test_generation.py @@ -187,17 +187,18 @@ class TestSdGaussianFwhm(unittest.TestCase): def test_sd_gaussian_fwhm(self): """ - Test :func:`colour.colorimetry.generation.sd_gaussian_fwhm` - definition. + Test :func:`colour.colorimetry.generation.sd_gaussian_fwhm` definition. """ sd = sd_gaussian_fwhm(555, 25) - self.assertAlmostEqual(sd[530], 0.367879441171443, places=7) + self.assertAlmostEqual(sd[530], 0.0625, places=7) self.assertAlmostEqual(sd[555], 1, places=7) - self.assertAlmostEqual(sd[580], 0.367879441171443, places=7) + self.assertAlmostEqual(sd[580], 0.062499999999999, places=7) + + self.assertAlmostEqual(sd[555 - 25 / 2], 0.5, places=7) class TestSdSingleLedOhno2005(unittest.TestCase):