Skip to content

Commit 532a6f9

Browse files
committed
Ensure that jagged pulses generated by "colour.volume.generate_pulse_waves" definition can be easily filtered.
1 parent 2c27d42 commit 532a6f9

File tree

2 files changed

+85
-4
lines changed

2 files changed

+85
-4
lines changed

colour/volume/spectrum.py

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
_CACHE_OUTER_SURFACE_XYZ_POINTS = {}
5353

5454

55-
def generate_pulse_waves(bins, pulse_order='Bins'):
55+
def generate_pulse_waves(bins, pulse_order='Bins', filter_jagged_pulses=False):
5656
"""
5757
Generates the pulse waves of given number of bins necessary to totally
5858
stimulate the colour matching functions and produce the *Rösch-MacAdam*
@@ -94,6 +94,23 @@ def generate_pulse_waves(bins, pulse_order='Bins'):
9494
*Pulse Wave Width* ordering, instead of iterating over the pulse wave
9595
widths first, iteration occurs over the bins, producing blocks of pulse
9696
waves with increasing width.
97+
filter_jagged_pulses : bool, optional
98+
Whether to filter jagged pulses. When ``pulse_order`` is set to
99+
*Pulse Wave Width*, the pulses are ordered by increasing width. Because
100+
of the discrete nature of the underlying signal, the resulting pulses
101+
will be jagged. For example assuming 5 bins, the center block with
102+
the two extreme values added would be as follows::
103+
104+
0 0 0 0 0
105+
0 0 1 0 0
106+
0 0 1 1 0 <--
107+
0 1 1 1 0
108+
0 1 1 1 1 <--
109+
1 1 1 1 1
110+
111+
Setting the ``filter_jagged_pulses`` parameter to `True` will result
112+
in the removal of the two marked pulses above which avoid jagged lines
113+
when plotting and having to resort to excessive ``bins`` values.
97114
98115
Returns
99116
-------
@@ -130,6 +147,29 @@ def generate_pulse_waves(bins, pulse_order='Bins'):
130147
[ 1., 1., 1., 0., 1.],
131148
[ 1., 1., 1., 1., 1.]])
132149
>>> generate_pulse_waves(5, 'Pulse Wave Width')
150+
array([[ 0., 0., 0., 0., 0.],
151+
[ 1., 0., 0., 0., 0.],
152+
[ 1., 1., 0., 0., 0.],
153+
[ 1., 1., 0., 0., 1.],
154+
[ 1., 1., 1., 0., 1.],
155+
[ 0., 1., 0., 0., 0.],
156+
[ 0., 1., 1., 0., 0.],
157+
[ 1., 1., 1., 0., 0.],
158+
[ 1., 1., 1., 1., 0.],
159+
[ 0., 0., 1., 0., 0.],
160+
[ 0., 0., 1., 1., 0.],
161+
[ 0., 1., 1., 1., 0.],
162+
[ 0., 1., 1., 1., 1.],
163+
[ 0., 0., 0., 1., 0.],
164+
[ 0., 0., 0., 1., 1.],
165+
[ 0., 0., 1., 1., 1.],
166+
[ 1., 0., 1., 1., 1.],
167+
[ 0., 0., 0., 0., 1.],
168+
[ 1., 0., 0., 0., 1.],
169+
[ 1., 0., 0., 1., 1.],
170+
[ 1., 1., 0., 1., 1.],
171+
[ 1., 1., 1., 1., 1.]])
172+
>>> generate_pulse_waves(5, 'Pulse Wave Width', True)
133173
array([[ 0., 0., 0., 0., 0.],
134174
[ 1., 0., 0., 0., 0.],
135175
[ 1., 1., 0., 0., 0.],
@@ -167,6 +207,9 @@ def generate_pulse_waves(bins, pulse_order='Bins'):
167207
for j, square_wave_basis in enumerate(square_waves_basis):
168208
square_waves.append(np.roll(square_wave_basis, i - j // 2))
169209

210+
if filter_jagged_pulses:
211+
square_waves = square_waves[::2]
212+
170213
return np.vstack([
171214
zeros(bins),
172215
np.vstack(square_waves),
@@ -178,6 +221,7 @@ def XYZ_outer_surface(cmfs=MSDS_CMFS['CIE 1931 2 Degree Standard Observer']
178221
.copy().align(SPECTRAL_SHAPE_OUTER_SURFACE_XYZ),
179222
illuminant=sd_ones(SPECTRAL_SHAPE_OUTER_SURFACE_XYZ),
180223
point_order='Bins',
224+
filter_jagged_points=False,
181225
**kwargs):
182226
"""
183227
Generates the *Rösch-MacAdam* colour solid, i.e. *CIE XYZ* colourspace
@@ -192,10 +236,28 @@ def XYZ_outer_surface(cmfs=MSDS_CMFS['CIE 1931 2 Degree Standard Observer']
192236
Illuminant spectral distribution.
193237
point_order : unicode, optional
194238
**{'Bins', 'Pulse Wave Width'}**,
195-
Method for ordering the pulse waves. *Bins* is the default order, with
239+
Method for ordering the underlying pulse waves used to generate the
240+
*Rösch-MacAdam* colour solid. *Bins* is the default order, with
196241
*Pulse Wave Width* ordering, instead of iterating over the pulse wave
197242
widths first, iteration occurs over the bins, producing blocks of pulse
198243
waves with increasing width.
244+
filter_jagged_points : bool, optional
245+
Whether to filter the underlying jagged pulses. When ``point_order`` is
246+
set to *Pulse Wave Width*, the pulses are ordered by increasing width.
247+
Because of the discrete nature of the underlying signal, the resulting
248+
pulses will be jagged. For example assuming 5 bins, the center block
249+
with the two extreme values added would be as follows::
250+
251+
0 0 0 0 0
252+
0 0 1 0 0
253+
0 0 1 1 0 <--
254+
0 1 1 1 0
255+
0 1 1 1 1 <--
256+
1 1 1 1 1
257+
258+
Setting the ``filter_jagged_points`` parameter to `True` will result
259+
in the removal of the two marked pulses above which avoid jagged lines
260+
when plotting and having to resort to excessive ``bins`` values.
199261
200262
Other Parameters
201263
----------------
@@ -257,11 +319,13 @@ def XYZ_outer_surface(cmfs=MSDS_CMFS['CIE 1931 2 Degree Standard Observer']
257319
settings = {'method': 'Integration', 'shape': cmfs.shape}
258320
settings.update(kwargs)
259321

260-
key = (hash(cmfs), hash(illuminant), point_order, str(settings))
322+
key = (hash(cmfs), hash(illuminant), point_order, filter_jagged_points,
323+
str(settings))
261324
XYZ = _CACHE_OUTER_SURFACE_XYZ.get(key)
262325

263326
if XYZ is None:
264-
pulse_waves = generate_pulse_waves(len(cmfs.wavelengths), point_order)
327+
pulse_waves = generate_pulse_waves(
328+
len(cmfs.wavelengths), point_order, filter_jagged_points)
265329
XYZ = msds_to_XYZ(pulse_waves, cmfs, illuminant, **settings) / 100
266330

267331
_CACHE_OUTER_SURFACE_XYZ[key] = XYZ

colour/volume/tests/test_spectrum.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,23 @@ def test_generate_pulse_waves(self):
9696
np.sort(generate_pulse_waves(5), axis=0),
9797
np.sort(generate_pulse_waves(5, 'Pulse Wave Width'), axis=0))
9898

99+
np.testing.assert_array_equal(
100+
generate_pulse_waves(5, 'Pulse Wave Width', True),
101+
np.array([
102+
[0.0, 0.0, 0.0, 0.0, 0.0],
103+
[1.0, 0.0, 0.0, 0.0, 0.0],
104+
[1.0, 1.0, 0.0, 0.0, 1.0],
105+
[0.0, 1.0, 0.0, 0.0, 0.0],
106+
[1.0, 1.0, 1.0, 0.0, 0.0],
107+
[0.0, 0.0, 1.0, 0.0, 0.0],
108+
[0.0, 1.0, 1.0, 1.0, 0.0],
109+
[0.0, 0.0, 0.0, 1.0, 0.0],
110+
[0.0, 0.0, 1.0, 1.0, 1.0],
111+
[0.0, 0.0, 0.0, 0.0, 1.0],
112+
[1.0, 0.0, 0.0, 1.0, 1.0],
113+
[1.0, 1.0, 1.0, 1.0, 1.0],
114+
]))
115+
99116

100117
class TestXYZOuterSurface(unittest.TestCase):
101118
"""

0 commit comments

Comments
 (0)