Skip to content

Conversation

@SimonBuechner
Copy link

Changes proposed in this pull request:

  • implements a channel-loop based version of STI calculations and according tests
  • STI calculation is split into three functions: speech_transmission_index, modulation_transfer_function and a small function handling final STI computations.

@SimonBuechner SimonBuechner added this to the v1.0.0 milestone Jan 16, 2026
@SimonBuechner SimonBuechner requested a review from a team January 16, 2026 10:36
@SimonBuechner SimonBuechner added the enhancement New feature or request label Jan 16, 2026
@SimonBuechner SimonBuechner changed the title Feature/sti channel loop STI channel-loop based Jan 16, 2026
Copy link
Member

@f-brinkmann f-brinkmann left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally looks good to me. I made a first round of review without already looking at the tests.

Comment on lines 205 to 208

def _energy_ratio(limits, energy_decay_curve1, energy_decay_curve2):
r"""
Calculate the energy ratio for the time limits from two energy
decay curves (EDC).

A variety of room-acoustic parameters are defined by energy ratios derived
from one or two time-domain Energy Decay Curves (EDCs). These parameters
distinguish between time regions using the four provided limits, and some,
such as Strength (:math:`G`), Early lateral sound (:math:`J_\mathrm{LF}`),
and Late lateral sound (:math:`L_J`), require EDCs obtained from different
impulse-response measurements [#iso]_.

Energy-Ratio is calculated as:
.. math::
ER = \frac{
\displaystyle \int_{lim3}^{lim4} p_2^2(t) \, dt
}{
\displaystyle \int_{lim1}^{lim2} p_1^2(t) \, dt
}
where :math:`[lim1, ..., lim4]` are the time limits and :math:`p(t)` is the
pressure of a room impulse response. Here, the energy ratio is
efficiently computed from the EDC :math:`e(t)` directly by:
.. math::
ER = \frac{
\displaystyle e_2(lim3) - e_2(lim4)
}{
\displaystyle e_1(lim1) - e_1(lim2)
}.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be two blank lines before a function only

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do suggest code changes on unrelated changes in reviews. Unrelated changes should not be included or discussed in PRs

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It not unrealted - but the diff above makes it look like. Theres too many blank lines before the start of a newly added function.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, alright. My bad then!

Comment on lines +282 to +284
snr = np.asarray(snr).flatten()
# Check if SNR has the correct number of components
if np.squeeze(snr.flatten().shape)/7 != (np.squeeze(data.cshape)):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are flattening and reshaping twice. Would this work as well

Suggested change
snr = np.asarray(snr).flatten()
# Check if SNR has the correct number of components
if np.squeeze(snr.flatten().shape)/7 != (np.squeeze(data.cshape)):
snr = np.atleast_2d(snr)
# Check if SNR has the correct number of components
if snr.shape[:-1] != cshape:
# error about wrong number of channesl
elif snr.shape[-1] != 7:
# raise error about wrong number of octave values
# check snr as is already done
# only one reshape
snr = np.reshape(snr, (-1, 7))

if np.any(snr < 20):
warnings.warn(
"SNR should be at least 20 dB for every octave band.",
stacklevel=2,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be stacklevel 1 or 2? If this is the main function, it should probably be 1.

Parameters
----------
data : pyfar.Signal
Single-channel room impulse response with shape ``(n_samples,)``.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If single channel is important it should be checked and an error sould be raised if it is violated.

data : pyfar.Signal
Single-channel room impulse response with shape ``(n_samples,)``.
data_type : {'electrical', 'acoustical'}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please add checks for data_type, level, snr,and amb similar to the way they are checked in the sti function?

data, num_fractions=1, freq_range=(125, 8000),
)

f_m = np.array(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a comment that these are the modulation frequencies and ideally link to the equation, section that defines them in the standard?

f_m = np.tile(f_m, (data_oct.cshape[0], 1))
energy = data_oct.time ** 2

term_exp = np.exp(-2j * np.pi * f_m[:, :, None] * data_oct.times)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The below is hard to understand. Can you please reference equations from the standard that are computed?

sti : np.ndarray
Speech Transmission Index.
"""
with np.errstate(divide="ignore"):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you here add references to equations/sections in the standard as well. Makes it way easier to review and maintain.

SimonBuechner and others added 4 commits January 20, 2026 10:33
dcostring spellling

Co-authored-by: Fabian Brinkmann <fabian.brinkmann@mailbox.org>
Error message adjusted to include reference to reason

Co-authored-by: Fabian Brinkmann <fabian.brinkmann@mailbox.org>
Co-authored-by: Fabian Brinkmann <fabian.brinkmann@mailbox.org>
Co-authored-by: Fabian Brinkmann <fabian.brinkmann@mailbox.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants