Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

PR: Fix incorrect colour.colorimetry.sd_gaussian_fwhm definition output. #1184

Merged
merged 1 commit into from
Jul 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 54 additions & 67 deletions colour/colorimetry/generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -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...
"""
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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))
Expand All @@ -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
-------
Expand All @@ -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(
Expand All @@ -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
Expand Down Expand Up @@ -673,31 +670,30 @@ 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
1...
"""

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`
Expand All @@ -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.
Expand Down Expand Up @@ -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:
Expand All @@ -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
)

Expand All @@ -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)"
)
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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)
9 changes: 5 additions & 4 deletions colour/colorimetry/tests/test_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down