Skip to content

Commit bf4428f

Browse files
authored
feat: Tonality IS/TS 20065 (#239)
1 parent 9073ef3 commit bf4428f

File tree

7 files changed

+912
-73
lines changed

7 files changed

+912
-73
lines changed

doc/changelog.d/239.added.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
feat: Tonality IS/TS 20065

doc/source/api/psychoacoustics.rst

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Psychoacoustics
2121
ToneToNoiseRatio
2222
ToneToNoiseRatioForOrdersOverTime
2323
TonalityDIN45681
24+
TonalityISOTS20065
2425
TonalityECMA418_2
2526
TonalityISO1996_2
2627
TonalityISO1996_2_OverTime

src/ansys/sound/core/psychoacoustics/__init__.py

+2
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
from .tonality_ecma_418_2 import TonalityECMA418_2
4444
from .tonality_iso_1996_2 import TonalityISO1996_2
4545
from .tonality_iso_1996_2_over_time import TonalityISO1996_2_OverTime
46+
from .tonality_iso_ts_20065 import TonalityISOTS20065
4647
from .tone_to_noise_ratio import ToneToNoiseRatio
4748
from .tone_to_noise_ratio_for_orders_over_time import ToneToNoiseRatioForOrdersOverTime
4849

@@ -60,6 +61,7 @@
6061
"Roughness",
6162
"FluctuationStrength",
6263
"TonalityDIN45681",
64+
"TonalityISOTS20065",
6365
"TonalityISO1996_2_OverTime",
6466
"TonalityAures",
6567
"SpectralCentroid",

src/ansys/sound/core/psychoacoustics/tonality_din_45681.py

+70-63
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,16 @@
2323
"""Computes DIN 45681 tonality."""
2424
import warnings
2525

26-
from ansys.dpf.core import Field, GenericDataContainersCollection, Operator
26+
from ansys.dpf.core import Field, GenericDataContainersCollection, Operator, types
2727
import matplotlib.pyplot as plt
2828
import numpy as np
2929

3030
from . import PsychoacousticsParent
3131
from .._pyansys_sound import PyAnsysSoundException, PyAnsysSoundWarning
3232

33+
# Name of the DPF Sound operator used in this module.
34+
ID_COMPUTE_TONALITY_DIN_45681 = "compute_tonality_din45681"
35+
3336
TONE_TYPES = ("", "FG")
3437

3538

@@ -46,7 +49,7 @@ def __init__(self, signal: Field = None, window_length: float = 3.0, overlap: fl
4649
Parameters
4750
----------
4851
signal: Field, default: None
49-
Signal in Pa on which to calculate the tonality, as a DPF field.
52+
Signal in Pa on which to calculate the tonality.
5053
window_length: float, default: 3.0
5154
Length, in s, of each slice of the signal used to calculate an average spectrum.
5255
overlap: float, default: 0.0
@@ -58,24 +61,24 @@ def __init__(self, signal: Field = None, window_length: float = 3.0, overlap: fl
5861
self.signal = signal
5962
self.window_length = window_length
6063
self.overlap = overlap
61-
self.__operator = Operator("compute_tonality_din45681")
64+
self.__operator = Operator(ID_COMPUTE_TONALITY_DIN_45681)
6265

6366
def __str__(self):
6467
"""Overloads the __str__ method."""
6568
return (
6669
f"{__class__.__name__} object.\n"
6770
"Data\n"
68-
f'Signal name: "{self.signal.name}"\n'
69-
f"Window length: {self.window_length} s\n"
70-
f"Overlap: {self.overlap} %\n"
71-
f"Mean difference DL: "
71+
f'\tSignal name: "{self.signal.name}"\n'
72+
f"\tWindow length: {self.window_length} s\n"
73+
f"\tOverlap: {self.overlap} %\n"
74+
f"Mean tonality (difference DL): "
7275
f"{self.get_mean_difference():.1f} (+/-{self.get_uncertainty():.1f}) dB\n"
73-
f"Tonal adjustment Kt: {self.get_tonal_adjustment():.0f} dB\n"
76+
f"Tonal adjustment Kt: {self.get_tonal_adjustment():.0f} dB"
7477
)
7578

7679
@property
7780
def signal(self) -> Field:
78-
"""Signal in Pa, as a DPF field. Default is None."""
81+
"""Signal in Pa. Default is None."""
7982
return self.__signal
8083

8184
@signal.setter
@@ -121,7 +124,7 @@ def process(self):
121124
"""
122125
if self.signal == None:
123126
raise PyAnsysSoundException(
124-
f"No input signal defined. Use ``{__class__.__name__}.signal``."
127+
f"No input signal defined. Use `{__class__.__name__}.signal`."
125128
)
126129

127130
# Connect the operator input(s).
@@ -134,13 +137,13 @@ def process(self):
134137

135138
# Store the operator outputs in a tuple.
136139
self._output = (
137-
self.__operator.get_output(0, "double"),
138-
self.__operator.get_output(1, "double"),
139-
self.__operator.get_output(2, "double"),
140-
self.__operator.get_output(3, "field"),
141-
self.__operator.get_output(4, "field"),
142-
self.__operator.get_output(5, "field"),
143-
self.__operator.get_output(6, "field"),
140+
self.__operator.get_output(0, types.double),
141+
self.__operator.get_output(1, types.double),
142+
self.__operator.get_output(2, types.double),
143+
self.__operator.get_output(3, types.field),
144+
self.__operator.get_output(4, types.field),
145+
self.__operator.get_output(5, types.field),
146+
self.__operator.get_output(6, types.field),
144147
self.__operator.get_output(7, GenericDataContainersCollection),
145148
)
146149

@@ -150,29 +153,29 @@ def get_output(self) -> tuple:
150153
Returns
151154
-------
152155
tuple
153-
First element (float) is the DIN 45681 tonality (mean difference DL), in dB.
156+
- First element (float) is the DIN 45681 tonality (mean difference DL), in dB.
154157
155-
Second element (float) is the DIN 45681 tonality uncertainty, in dB.
158+
- Second element (float) is the DIN 45681 tonality uncertainty, in dB.
156159
157-
Third element (float) is the DIN 45681 tonal adjustment Kt, in dB.
160+
- Third element (float) is the DIN 45681 tonal adjustment Kt, in dB.
158161
159-
Fourth element (Field) is the DIN 45681 tonality over time
160-
(decisive difference DLj), in dB.
162+
- Fourth element (Field) is the DIN 45681 tonality over time
163+
(decisive difference DLj), in dB.
161164
162-
Fifth element (Field) is the DIN 45681 tonality uncertainty over time, in dB.
165+
- Fifth element (Field) is the DIN 45681 tonality uncertainty over time, in dB.
163166
164-
Sixth element (Field) is the DIN 45681 decisive frequency over time, in Hz.
167+
- Sixth element (Field) is the DIN 45681 decisive frequency over time, in Hz.
165168
166-
Seventh element (Field) is the DIN 45681 tonal adjustment Kt over time, in dB.
169+
- Seventh element (Field) is the DIN 45681 tonal adjustment Kt over time, in dB.
167170
168-
Eighth element (GenericDataContainer) is the DIN 45681 tonality details (individual
169-
tone data for each spectrum).
171+
- Eighth element (GenericDataContainer) is the DIN 45681 tonality details (individual
172+
tone data for each spectrum).
170173
"""
171174
if self._output == None:
172175
warnings.warn(
173176
PyAnsysSoundWarning(
174177
f"Output is not processed yet. "
175-
f"Use the ``{__class__.__name__}.process()`` method."
178+
f"Use the `{__class__.__name__}.process()` method."
176179
)
177180
)
178181

@@ -184,21 +187,21 @@ def get_output_as_nparray(self) -> tuple[np.ndarray]:
184187
Returns
185188
-------
186189
tuple[numpy.ndarray]
187-
First element is the DIN 45681 tonality (mean difference DL), in dB.
190+
- First element is the DIN 45681 tonality (mean difference DL), in dB.
188191
189-
Second element is the DIN 45681 tonality uncertainty, in dB.
192+
- Second element is the DIN 45681 tonality uncertainty, in dB.
190193
191-
Third element is the DIN 45681 tonal adjustment Kt, in dB.
194+
- Third element is the DIN 45681 tonal adjustment Kt, in dB.
192195
193-
Fourth element is the DIN 45681 tonality over time (decisive difference DLj), in dB.
196+
- Fourth element is the DIN 45681 tonality over time (decisive difference DLj), in dB.
194197
195-
Fifth element is the DIN 45681 tonality uncertainty over time, in dB.
198+
- Fifth element is the DIN 45681 tonality uncertainty over time, in dB.
196199
197-
Sixth element is the DIN 45681 decisive frequency over time, in Hz.
200+
- Sixth element is the DIN 45681 decisive frequency over time, in Hz.
198201
199-
Seventh element is the DIN 45681 tonal adjustment Kt over time, in dB.
202+
- Seventh element is the DIN 45681 tonal adjustment Kt over time, in dB.
200203
201-
Eighth element is the time scale, in s.
204+
- Eighth element is the time scale, in s.
202205
"""
203206
output = self.get_output()
204207

@@ -318,25 +321,25 @@ def get_spectrum_number(self) -> int:
318321
"""
319322
return len(self.get_output()[3])
320323

321-
def get_spectrum_details(self, spectrum_index: int = 0) -> tuple[float, float, float]:
324+
def get_spectrum_details(self, spectrum_index: int) -> tuple[float]:
322325
"""Get the spectrum data for a specific spectrum.
323326
324327
Returns the data (decisive difference, uncertainty, and decisive frequency) corresponding
325328
to a specific spectrum (time step).
326329
327330
Parameters
328331
----------
329-
spectrum_index: int, default: 0
330-
Index of the spectrum to get.
332+
spectrum_index: int
333+
Index of the spectrum. The index is 0-based.
331334
332335
Returns
333336
-------
334-
tuple[float,float,float]
335-
Decisive difference DLj in dB.
337+
tuple[float]
338+
- First element is the decisive difference DLj in dB.
336339
337-
Uncertainty in dB.
340+
- Second element is the uncertainty in dB.
338341
339-
Decisive frequency in Hz.
342+
- Third element is the decisive frequency in Hz.
340343
"""
341344
# Check validity of the input spectrum index.
342345
self.__check_spectrum_index(spectrum_index)
@@ -347,11 +350,16 @@ def get_spectrum_details(self, spectrum_index: int = 0) -> tuple[float, float, f
347350
self.get_output_as_nparray()[5][spectrum_index],
348351
)
349352

350-
def get_tone_number(self, spectrum_index: int = 0) -> int:
353+
def get_tone_number(self, spectrum_index: int) -> int:
351354
"""Get the number of tones for a specific spectrum.
352355
353356
Returns the number of tones detected in a specific spectrum (time step).
354357
358+
Parameters
359+
----------
360+
spectrum_index: int
361+
Index of the spectrum where the tone was detected. The index is 0-based.
362+
355363
Returns
356364
-------
357365
int
@@ -367,43 +375,42 @@ def get_tone_number(self, spectrum_index: int = 0) -> int:
367375

368376
return len(spectrum.get_property("differences"))
369377

370-
def get_tone_details(
371-
self, spectrum_index: int = 0, tone_index: int = 0
372-
) -> tuple[float, float, float, str, float, float, float, float, float, float]:
378+
def get_tone_details(self, spectrum_index: int, tone_index: int) -> tuple:
373379
"""Get the tone data, for a specific spectrum.
374380
375381
Returns all data associated with a specific detected tone, in a specific spectrum (time
376382
step).
377383
378384
Parameters
379385
----------
380-
spectrum_index: int, default: 0
381-
Index of the spectrum where the tone was detected.
382-
tone_index: int, default: 0
383-
Index of the tone whose details are requested.
386+
spectrum_index: int
387+
Index of the spectrum where the tone was detected. The index is 0-based.
388+
tone_index: int
389+
Index of the tone whose details are requested. The index is 0-based.
384390
385391
Returns
386392
-------
387-
tuple[float,float,float,str,float,float,float,float,float,float]
388-
Decisive difference DLj in dB.
393+
tuple
394+
- First element (float) is the decisive difference DLj in dB.
389395
390-
Uncertainty, in dB.
396+
- Second element (float) is the uncertainty, in dB.
391397
392-
Decisive frequency, in Hz.
398+
- Third element (float) is the decisive frequency, in Hz.
393399
394-
Tone type ('' for individual tones, or 'FG' for groups of tones).
400+
- Fourth element (str) is the tone type ('' for individual tones, or 'FG' for groups
401+
of tones).
395402
396-
Critical band lower limit, in Hz.
403+
- Fifth element (float) is the critical band lower limit, in Hz.
397404
398-
Critical band upper limit, in Hz.
405+
- Sixth element (float) is the critical band upper limit, in Hz.
399406
400-
Mean narrow-band masking noise level Ls, in dBA.
407+
- Seventh element (float) is the mean narrow-band masking noise level Ls, in dBA.
401408
402-
Tone level Lt, in dBA.
409+
- Eighth element (float) is the tone level Lt, in dBA.
403410
404-
Masking noise level Lg, in dBA.
411+
- Ninth element (float) is the masking noise level Lg, in dBA.
405412
406-
Masking index av, in dB.
413+
- Tenth element (float) is the masking index av, in dB.
407414
"""
408415
# Check validities of input indexes.
409416
self.__check_spectrum_index(spectrum_index)
@@ -440,7 +447,7 @@ def plot(self):
440447
"""
441448
if self._output == None:
442449
raise PyAnsysSoundException(
443-
f"Output is not processed yet. Use the ``{__class__.__name__}.process()`` method."
450+
f"Output is not processed yet. Use the `{__class__.__name__}.process()` method."
444451
)
445452

446453
# Get data to plot

0 commit comments

Comments
 (0)