-
Notifications
You must be signed in to change notification settings - Fork 2
Feature: correlation method after mommertz #31
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the feature. It generally looks good to me. I had mostly minor comments.
imkar/scattering/freefield.py
Outdated
| - :math:`w` represents the area weights of the sampling, and | ||
| :math:`\vartheta` and :math:`\varphi` are the ``colatitude`` | ||
| and ``azimuth`` angles from the | ||
| :py:class:`~pyfar.classes.coordinates.Coordinates` object. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rather link here than to the coordinates object for explaining the angles: https://pyfar.readthedocs.io/en/stable/classes/pyfar.coordinates.html#coordinate-systems. And I think it would help to mention that they denote the incidence direction
imkar/scattering/freefield.py
Outdated
| Returns | ||
| ------- | ||
| scattering_coefficients : :py:class:`~pyfar.classes.audio.FrequencyData` | ||
| The scattering coefficient for each incident direction as a function |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe mention here and also above, that the channels up to the last channel dimension of sample_pressure, reference_pressure and scattering_coefficients represent the incident direction. It might help to get an example as 'cshape = (45, 25) denotes a measurement with 45 incidenet directions and recorded at 25 microphone positions.'
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually it is just relevant what the last cdim is, because this is the receiver grid, from which we are averaging. what ever is before that (typically incident direction) will come out. it can also be just one incident direction. I tired to make it more clear in th docstring
imkar/scattering/freefield.py
Outdated
| and ``azimuth`` angles from the | ||
| :py:class:`~pyfar.classes.coordinates.Coordinates` object. | ||
|
|
||
| The test sample is assumed to lie in the x-y-plane. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this relevant for the computation? Otherwise this information could be omitted.
imkar/scattering/freefield.py
Outdated
| if not isinstance(sample_pressure, pf.FrequencyData): | ||
| raise TypeError("sample_pressure must be of type pyfar.FrequencyData") | ||
| if not isinstance(reference_pressure, pf.FrequencyData): | ||
| raise TypeError( | ||
| "reference_pressure must be of type pyfar.FrequencyData") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This will pass also for signals. You have to use type(sample_pressure) == pf.FrequencyData
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes it can also be an impulse response, where we just use freq data. I made it more clear in docs and checks
imkar/scattering/freefield.py
Outdated
| if sample_pressure.cshape[:-1] != reference_pressure.cshape[:-1]: | ||
| raise ValueError( | ||
| "The cshape of sample_pressure and reference_pressure must be " | ||
| "broadcastable except for the last dimension") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this error can not be reached and should be deleted. One of the two if-cases above would already if sample_pressure.cshape[:-1] != reference_pressure.cshape[:-1]
| from imkar.scattering import freefield as sff | ||
|
|
||
|
|
||
| def plane_wave(amplitude, direction, sampling): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a minimal docstring to ease maintainance
|
|
||
|
|
||
| def test_correlation_method_0(): | ||
| sampling = pf.samplings.sph_equal_area(5000) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better already use samplings from spharpy?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll shift it to the todo, after the spharpy release
tests/test_scattering_freefield.py
Outdated
|
|
||
| @pytest.mark.parametrize("s_scatter", [0.1, 0.5, 0.9]) | ||
| @pytest.mark.parametrize("Phi_scatter_deg", [30, 60, 90, 120, 150, 42]) | ||
| def test_correlation_method_with_plane_waves(s_scatter, Phi_scatter_deg): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would take a little while to understand. Can you add some comments for guidance?
tests/test_scattering_freefield.py
Outdated
| ) | ||
|
|
||
|
|
||
| def test_correlation_method_0(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this be integrated into test_correlation_method_with_plane_waves?
tests/test_scattering_freefield.py
Outdated
| npt.assert_almost_equal(sd_scatter_0.freq, 0, 1) | ||
|
|
||
|
|
||
| def test_correlation_method(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In how far is this different from test_correlation_method_0 above?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces a new correlation method for calculating scattering coefficients from free-field measurements based on the Mommertz correlation method. The implementation allows users to compute scattering coefficients by analyzing reflection patterns from samples compared to reference measurements.
Key changes:
- Implements the Mommertz correlation method for scattering coefficient calculation
- Adds comprehensive test coverage for various scattering scenarios
- Updates module structure and documentation to include the new freefield scattering functionality
Reviewed Changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| imkar/scattering/freefield.py | Core implementation of the correlation_method function with mathematical formulation and input validation |
| tests/test_scattering_freefield.py | Comprehensive test suite covering edge cases, parametric testing, and input validation |
| imkar/scattering/init.py | New module initialization file exposing freefield submodule |
| imkar/init.py | Updated package initialization to include scattering module |
| docs/modules/imkar.scattering.freefield.rst | Documentation file for the new freefield module |
| docs/modules/imkar.rst | Removed original imkar module documentation |
| docs/api_reference.rst | Updated API reference to point to new freefield module |
Comments suppressed due to low confidence (2)
tests/test_scattering_freefield.py:130
- The error message in the test doesn't match the actual error message from the function. The function accepts both FrequencyData and Signal types, but the test expects an error message mentioning only FrequencyData.
TypeError, match="sample_pressure must be of type "
tests/test_scattering_freefield.py:140
- The error message in the test doesn't match the actual error message from the function. The function accepts both FrequencyData and Signal types, but the test expects an error message mentioning only FrequencyData.
TypeError, match="reference_pressure must be of type "
Co-authored-by: Copilot <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, only minor things. I'm not sure if I understood the testing in detail though...
| cshape of ``reference_pressure``. The frequency vectors of both | ||
| ``sample_pressure`` and ``reference_pressure`` must match. | ||
| reference_pressure : pyfar.FrequencyData, pyfar.Signal | ||
| Reflected sound pressure or directivity of the reference sample. Its |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is meant with the "or"? Do reflected sound pressure and directivity mean the same thing or can both be used as input for the function?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
both can be used, because it is proportional
imkar/scattering/freefield.py
Outdated
| "broadcastable except for the last dimension") | ||
| # Test whether the objects are able to perform arithmetic operations. | ||
| # e.g. does the frequency vectors match | ||
| _ = sample_pressure + reference_pressure |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is checking the frequencies the only purpose? If yes, +1 for an explicit solution
| p_sample_sum = np.sum(microphone_weights * np.abs(p_sample)**2, axis=-2) | ||
| p_ref_sum = np.sum(microphone_weights * np.abs(p_reference)**2, axis=-2) | ||
| p_cross_sum = np.sum( | ||
| p_sample * np.conj(p_reference) * microphone_weights, axis=-2) | ||
|
|
||
| data_scattering_coefficient = 1 - np.abs(p_cross_sum)**2/( | ||
| p_sample_sum*p_ref_sum) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be cool to have pyfar functions sum, abs, conj in the future, wouldn't it? pyfar/pyfar#830
| npt.assert_almost_equal(sd_scatter_0.freq, 0, 1) | ||
|
|
||
|
|
||
| def test_correlation_one_scattering(): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Short docstrings would be helpful :)
Co-authored-by: sikersten <[email protected]>
Which issue(s) are closed by this pull request?
Closes #12
Changes proposed in this pull request:
requires #32