Skip to content

Conversation

@tluebeck
Copy link

@tluebeck tluebeck commented Jul 6, 2025

Which issue(s) are closed by this pull request?

Closes #165

Changes proposed in this pull request:

  • introduce SphericalHarmonicsAudio base class which holds all SH related properties
  • introduce SphericalHarmonicsTimeData and FrequencyData

@tluebeck tluebeck changed the base branch from main to develop July 6, 2025 13:36
@tluebeck tluebeck self-assigned this Jul 6, 2025
@tluebeck tluebeck added the enhancement New feature or request label Jul 6, 2025
@tluebeck tluebeck marked this pull request as draft July 6, 2025 13:37
@mberz mberz moved this from Backlog to Drafting Phase in Weekly Planning Jul 8, 2025
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.

Thanks for the effort. It generally looks good to me! I suggested one structural change and adding the docs but otherwise its fine to me. I think the testing should be fine. complete functionality is tested for SH signal, initialization tested for each class separately.

Comment on lines 208 to 218
# check dimensions
if len(data.shape) < 3:
raise ValueError("Invalid number of dimensions. Data should have "
"at least 3 dimensions.")

# set n_max
n_max = np.sqrt(data.shape[-2])-1
if n_max - int(n_max) != 0:
raise ValueError("Invalid number of SH channels: "
f"{data.shape[-2]}. It must match (n_max + 1)^2.")
self._n_max = int(n_max)
Copy link
Member

Choose a reason for hiding this comment

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

It seems a little redundant to me to have this in all three classes. Would the following work:

  • First call the init of the Audio class (FrequencyData in this case)
  • Second call the init of the SHAudio class and move this code there

Copy link
Author

Choose a reason for hiding this comment

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

Good point, yes that works.



class SphericalHarmonicTimeData(SphericalHarmonicsAudio, TimeData):
"""_summary_
Copy link
Member

Choose a reason for hiding this comment

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

Missing docs - probably intended to get a review before the effort.



class SphericalHarmonicFrequencyData(SphericalHarmonicsAudio, FrequencyData):
"""_summary_
Copy link
Member

Choose a reason for hiding this comment

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

Missing docs - probably intended to get a review before the effort.

@github-project-automation github-project-automation bot moved this from Drafting Phase to Require review in Weekly Planning Jul 10, 2025
tluebeck added 2 commits July 11, 2025 07:24
add docstrings
move n_max and dimensions check to base class
@tluebeck tluebeck requested a review from f-brinkmann July 18, 2025 11:14
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.

Looks good to me. I would suggest to wait with the merge until we finalized discussions on the SH conventions that we want to support. This might cause changes here as well.

comment : str
A comment related to `data`. The default is ``None``.
"""
def __init__(self, data, frequencies, basis_type, normalization,
Copy link
Member

Choose a reason for hiding this comment

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

Do we want to have default values for the SH parameters as in the SH class, or are there not defaults by intention to make sure people think about this when inputting data from sources other than our internal SHT functions?

@github-project-automation github-project-automation bot moved this from Require review to Reviewer Approved in Weekly Planning Jul 24, 2025
@f-brinkmann f-brinkmann moved this from Reviewer Approved to Require review in Weekly Planning Jul 24, 2025
@ahms5 ahms5 added this to the v1.0.0 milestone Jul 25, 2025
Copy link
Member

@ahms5 ahms5 left a comment

Choose a reason for hiding this comment

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

Thank you for taking care!
just minor comments

class SphericalHarmonicSignal(Signal):
"""Create audio object with spherical harmonics coefficients in time or
frequency domain.
class SphericalHarmonicAudio(_Audio):
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
class SphericalHarmonicAudio(_Audio):
class _SphericalHarmonicAudio(_Audio):

shouldnt this be private, too?

comment=comment, is_complex=is_complex)
SphericalHarmonicAudio.__init__(
self, basis_type, normalization, channel_convention,
condon_shortley, domain="time", comment=comment)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
condon_shortley, domain="time", comment=comment)
condon_shortley, domain=domain, comment=comment)

domain="time"would overwrite the given domain. But i think we can remove it here anyway

Comment on lines 52 to 54
def __init__(self, basis_type, normalization, channel_convention,
condon_shortley, domain, comment=""):
_Audio.__init__(self, domain=domain, comment=comment)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
def __init__(self, basis_type, normalization, channel_convention,
condon_shortley, domain, comment=""):
_Audio.__init__(self, domain=domain, comment=comment)
def __init__(self, basis_type, normalization, channel_convention,
condon_shortley):

i wounder if we really need it here, because it would be set twice, by the audio class and then overwritten by this class. I think the _Audio.init is not setting anything else then this to entries, so i guess we can remove it.

Comment on lines 233 to 235
SphericalHarmonicAudio.__init__(
self, basis_type, normalization, channel_convention,
condon_shortley, domain="time", comment=comment)
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
SphericalHarmonicAudio.__init__(
self, basis_type, normalization, channel_convention,
condon_shortley, domain="time", comment=comment)
SphericalHarmonicAudio.__init__(
self, basis_type, normalization, channel_convention,
condon_shortley)

@sikersten
Copy link
Member

Thanks for implementing! I think I am missing something fundamental here. Why is it not possible that _SphericalHarmonicAudio inherits from the SphericalHarmonics class?

@mberz
Copy link
Member

mberz commented Aug 22, 2025

Thanks for implementing! I think I am missing something fundamental here. Why is it not possible that _SphericalHarmonicAudio inherits from the SphericalHarmonics class?

Because the SphericalHarmonics class contains a number of properties which are not meaningful in the SphericalHarmonicSignal class. They however share a set of properties/methods which would make a shared base class usefull, see #173

@ahms5 ahms5 modified the milestones: v1.0.0, v1.1.0 Sep 12, 2025
@f-brinkmann f-brinkmann moved this from Require review to Implementation in progress in Weekly Planning Sep 27, 2025
@tluebeck tluebeck marked this pull request as ready for review October 19, 2025 01:43
@f-brinkmann f-brinkmann self-requested a review October 20, 2025 11:56
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.

The import of SH TimeData and FrequencyData is missing in spharpy/__init__.py

Comment on lines +20 to +22
well as the normalizations N3D, SN3D, or MaxN, see [#]_. The definition of
the spherical harmonics basis functions is based on the scipy convention
which includes the Condon-Shortley phase, [#]_, [#]_.
Copy link
Member

Choose a reason for hiding this comment

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

I would suggest to keep this plain and without references. We will have a large general documentation for SHs for this:

Suggested change
well as the normalizations N3D, SN3D, or MaxN, see [#]_. The definition of
the spherical harmonics basis functions is based on the scipy convention
which includes the Condon-Shortley phase, [#]_, [#]_.
well as the normalizations N3D, NM, SN3D, SNM, or MaxN.

Copy link
Member

Choose a reason for hiding this comment

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

This re-appears in the SphericalHarmonicSignal class. But I can't comment there because the lines were not changed in this pull.

Comment on lines +47 to +52
.. [#] F. Zotter, M. Frank, "Ambisonics A Practical 3D Audio Theory
for Recording, Studio Production, Sound Reinforcement, and
Virtual Reality", (2019), Springer-Verlag
.. [#] B. Rafely, "Fundamentals of Spherical Array Processing", (2015),
Springer-Verlag
.. [#] E.G. Williams, "Fourier Acoustics", (1999), Academic Press
Copy link
Member

Choose a reason for hiding this comment

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

See above. But maybe wait if anyone disagrees.

Suggested change
.. [#] F. Zotter, M. Frank, "Ambisonics A Practical 3D Audio Theory
for Recording, Studio Production, Sound Reinforcement, and
Virtual Reality", (2019), Springer-Verlag
.. [#] B. Rafely, "Fundamentals of Spherical Array Processing", (2015),
Springer-Verlag
.. [#] E.G. Williams, "Fourier Acoustics", (1999), Academic Press

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.

Can you please merge develop into this again to make sure we have capitalized channel conventions 'ACN' and 'FuMa'?

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.

Thanks for the effort. The inheritance generally looks good, but I found two things that I think must be considered:

  1. I think we must overwrite the setters for n_max, basis_type, and condon_shortley to raise an error when the user attempts to set these attributes. Otherwise these parameters can be changed but the change won't be refelcted in the data. We could allow for such things, but I would not consider it in this pull request:
td = SphericalHarmonicTimeData([[[1, 2, 3]]], [1, 2, 3], 'real', 'SN3D', 'acn', 'auto')
td.n_max = 1  # this changes the order, but the data stays the same.
  1. We need to handle setting the data and getting n_max. The following changes the data, without changing n_max. I assume we want to be able to set new data and updating the order accordingly, e.g., whan upmixing to a higher SH order:
td = sy.classes.SphericalHarmonicTimeData([[[1, 2, 3]]], [1, 2, 3], 'real', 'SN3D', 'acn', 'auto')
td.time = np.random.rand(1, 4, 100) 

"""
def __init__(self, basis_type, normalization, channel_convention,
condon_shortley, domain, comment=""):
Copy link
Member

Choose a reason for hiding this comment

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

domain and time are not accessed here, I assume because they are set in the audio classes from this inherits.

Suggested change
condon_shortley, domain, comment=""):
condon_shortley):

harmonic coefficients and times.
Objects of this class contain time data which is not directly convertible
to frequency domain, i.e., non-equidistant samples.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
to frequency domain, i.e., non-equidistant samples.
to the frequency domain, i.e., non-equidistant samples.

``'maxN'``, ``'SN3D'`` or ``'SNM'``. (maxN is only supported up
to 3rd order)
channel_convention : str
Channel ordering convention, either ``'acn'`` or ``'fuma'``.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
Channel ordering convention, either ``'acn'`` or ``'fuma'``.
Channel ordering convention, either ``'ACN'`` or ``'FuMa'``.

Flag to indicate if the Condon-Shortley phase term is included
(``True``) or not (``False``).
comment : str
A comment related to `data`. The default is ``None``.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
A comment related to `data`. The default is ``None``.
A comment related to `data`. The default is ``""``.

Comment on lines 121 to 122
coefficients with 1024 samples each. The data can be ``int`` or
``float`` and is converted to ``float`` in any case.
Copy link
Member

Choose a reason for hiding this comment

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

To be consistent with FrequencyData

Suggested change
coefficients with 1024 samples each. The data can be ``int`` or
``float`` and is converted to ``float`` in any case.
coefficients with 1024 samples each. The data can be ``int``,
``float`` or ``complex``. Data of type ``int`` is converted to
``float``.

``'maxN'``, ``'SN3D'`` or ``'SNM'``. (maxN is only supported up
to 3rd order)
channel_convention : str
Channel ordering convention, either ``'acn'`` or ``'fuma'``.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
Channel ordering convention, either ``'acn'`` or ``'fuma'``.
Channel ordering convention, either ``'ACN'`` or ``'FuMa'``.

self._channel_convention = value
_SphericalHarmonicAudio.__init__(
self, basis_type, normalization, channel_convention,
condon_shortley, domain=domain, comment=comment)
Copy link
Member

Choose a reason for hiding this comment

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

see comment above:

Suggested change
condon_shortley, domain=domain, comment=comment)
condon_shortley)

data, times, basis_type='real', normalization='SN3D',
channel_convention="acn", condon_shortley=False,
comment="")
assert isinstance(sh_time_data, SphericalHarmonicTimeData)
Copy link
Member

Choose a reason for hiding this comment

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

This would be more strict

Suggested change
assert isinstance(sh_time_data, SphericalHarmonicTimeData)
assert type(sh_time_data) == SphericalHarmonicTimeData

(maybe needs is instead of ==)

data, frequencies, basis_type='real', normalization='SN3D',
channel_convention="acn", condon_shortley=False,
comment="")
assert isinstance(sh_freq_data, SphericalHarmonicFrequencyData) No newline at end of file
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
assert isinstance(sh_freq_data, SphericalHarmonicFrequencyData)
assert type(sh_freq_data) == SphericalHarmonicFrequencyData

Comment on lines 188 to 189
match="Invalid channel convention, currently only 'acn' "
"and 'fuma' are supported"):
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
match="Invalid channel convention, currently only 'acn' "
"and 'fuma' are supported"):
match="Invalid channel convention, currently only 'ACN' "
"and 'FuMa' are supported"):

Should also be changed below after merging develop into this.

@github-project-automation github-project-automation bot moved this from Implementation in progress to Require review in Weekly Planning Oct 20, 2025
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.

Sorry, forgot one thing. I would suggest to rename audio.py to sh_audio.py.

@mberz
Copy link
Member

mberz commented Oct 22, 2025

Sorry, forgot one thing. I would suggest to rename audio.py to sh_audio.py.

Please rename files in this pr. this will cause conflicts with other branches.

@mberz
Copy link
Member

mberz commented Oct 23, 2025

Sorry, forgot one thing. I would suggest to rename audio.py to sh_audio.py.

Please rename files in this pr. this will cause conflicts with other branches.

I'm very sorry, I meant to write don't rename in this branch, since the file is already part of develop.
Could you please revert dfd4d54 ?

Copy link
Member

@mberz mberz left a comment

Choose a reason for hiding this comment

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

I'm just commenting on this now, as I feel we need to make some adjustments to the SphericalHarmonicDefinition class before continuing with this PR.

  1. I think it makes sense to move the functionality of saving the old properties to the parent class, as it could come in handy in other classes.
  2. I now remember why I first had the SphericalHarmonicDefintion in mind without the n_max property defined. I'll add an abstract base class for that which could serve as parent for the SphericalHarmonicAudio classes.

Sorry to postpone this PR once again.

Comment on lines +12 to +14
three sub-classes :py:func:`SphericalHarmonicsTimeData`,
:py:func:`SphericalHarmonicsFrequencyData`, and
:py:func:`SphericalHarmonicsSignal`.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
three sub-classes :py:func:`SphericalHarmonicsTimeData`,
:py:func:`SphericalHarmonicsFrequencyData`, and
:py:func:`SphericalHarmonicsSignal`.
three sub-classes :py:func:`SphericalHarmonicTimeData`,
:py:func:`SphericalHarmonicFrequencyData`, and
:py:func:`SphericalHarmonicSignal`.

Copy link
Author

Choose a reason for hiding this comment

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

Sure, reverted. I kind of had the feeling it was a typo cause it did't made sense to me :D ...
I agree that it makes sense to move the saving of the old parameters to the SHDefinitions class. However, I think it could be an option to do that in a separate PR. The functionality from outside would not change, and we could move on with other stuff, like SHtrafo etc.

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

Status: Require review

Development

Successfully merging this pull request may close these issues.

SH Time and FrequencyData

5 participants