Skip to content

Feature: time-slicing function for pyfar.Signal objects#849

Merged
mberz merged 6 commits intodevelopfrom
feature/time_slicing_for_signals
Dec 12, 2025
Merged

Feature: time-slicing function for pyfar.Signal objects#849
mberz merged 6 commits intodevelopfrom
feature/time_slicing_for_signals

Conversation

@h-chmeruk
Copy link
Copy Markdown
Contributor

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

Closes #751

This is my implementation of the pyfar.dsp.time_crop function, which can be used to crop a signal in the time domain. I have also written some test functions, most of which are similar to the existing test functions for pyfar.dsp.time_window.

@h-chmeruk h-chmeruk added feature For requesting new features dsp labels Oct 8, 2025
Copy link
Copy Markdown
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.

nice, thank you. a few minor comments on the doc and testing

Copy link
Copy Markdown
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.

see previous review

Copy link
Copy Markdown
Contributor

@jf-som jf-som 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 implementing this feature!

Adding to what @ahms5 already mentioned, I just have some coding style hints :)

@h-chmeruk
Copy link
Copy Markdown
Contributor Author

I added TimeData as a data type for the parameter signal, so the time_crop function has had some changes, and there are also some significant changes in test_dsp.py . Therefore, I could use a deeper review again. Thanks in advance :)

@h-chmeruk h-chmeruk requested review from ahms5 and jf-som October 30, 2025 17:53
Copy link
Copy Markdown
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 hanna, Looks fine, just one main point about the error handling, see below.

Copy link
Copy Markdown
Contributor

@jf-som jf-som 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 implementing these changes. I found a small corrention and an unusual empty line, but otherwise all looks good to me

Copy link
Copy Markdown
Member

@sikersten sikersten 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! Already looks quite good. Some minor comments and one more important on the function's behavior if interval is out of the boundaries.

Copy link
Copy Markdown
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.

Thanks for the implementation.
Apart from the interval checking issue missing for samples already mentioned by Simon I have only minor comments. Functionality wise I think this is good to go.

Additionally I found a couple of indenting issue which do not comply with PEP8. You can have a look at the guidelines for PEP8 here:
https://peps.python.org/pep-0008/#indentation

pyfar/dsp/dsp.py Outdated
np.ndarray],
unit: Literal["samples", "s"]='samples'):
"""This function can be used to crop a pf.Signal or pf.TimeData object.
"""Crop a pf.Signal or pf.TimeData object in time.
Copy link
Copy Markdown
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 add a sentence on the definition of the crop interval used by the function, i.e. that the function crops to the inside of the interval.

@github-project-automation github-project-automation bot moved this to Require review in Weekly Planning Nov 20, 2025
@ahms5 ahms5 moved this from Require review to Implementation in progress in Weekly Planning Nov 20, 2025
@h-chmeruk h-chmeruk moved this from Implementation in progress to Require review in Weekly Planning Nov 21, 2025
@jf-som
Copy link
Copy Markdown
Contributor

jf-som commented Nov 21, 2025

Thanks for implementing the changes. In terms of the actual code, this looks ready to me.

I have two general design thoughts though:

  1. Intuitively, I would expect this function to behave like slicing in numpy or python in general, where the interval [3, 6] gives the indexes 3, 4 and 5 (excluding 6). So
    cropped = pf.Signal(signal.time[:, 3:6], signal.sampling_rate) should be the same as
    cropped = pf.dsp.time_crop(signal, [3, 6]).
    As is it is implemented now, the interval end is inclusive, which is unusual for 0-indexed programming languages. So I would argue to replace indices <= interval[1] by indices < interval[1].
    I'm aware that time_window also has an inclusive range. But since time_crop has a different goal that is closer to array slicing, I would argue that the inlusive start, exclusive end interval is more appropriate here.

I see you added TimeData as a an alternative input to Signal. In my opinion, it's unusual to allow different types of inputs and return types, when the behavior of the function is different depending on the type. In this case, cropping TimeData seems to keep timestamps while Signal changes them to start at 0, as you show in the examples.
Since the return type is always the same as the first argument, it might make more sense to make two instance methods out of this with different comments, i.e.

croppedTimeData = someTimeData.time_crop(interval, unit)
croppedSignal = someSignal.time_crop(interval, unit)

This version would be similar to the filter.impulse_response() functions, which also do slightly different things depending on the type of filter.
Doing so would also help with type hints in vscode etc, since then the IDE could infer the output type from the object it was used on.

Perhaps we can discuss this in the weekly meeting in 7 days.

@h-chmeruk
Copy link
Copy Markdown
Contributor Author

Thanks for implementing the changes. In terms of the actual code, this looks ready to me.

I have two general design thoughts though:

1. Intuitively, I would expect this function to behave like slicing in numpy or python in general, where the interval [3, 6] gives the indexes 3, 4 and 5 (excluding 6). So
   `cropped = pf.Signal(signal.time[:, 3:6], signal.sampling_rate)` should be the same as
   `cropped = pf.dsp.time_crop(signal, [3, 6])`.
   As is it is implemented now, the interval end is inclusive, which is unusual for 0-indexed programming languages. So I would argue to replace `indices <= interval[1]` by `indices < interval[1]`.
   I'm aware that `time_window` also has an inclusive range. But since time_crop has a different goal that is closer to array slicing, I would argue that the inlusive start, exclusive end interval is more appropriate here.

I see you added TimeData as a an alternative input to Signal. In my opinion, it's unusual to allow different types of inputs and return types, when the behavior of the function is different depending on the type. In this case, cropping TimeData seems to keep timestamps while Signal changes them to start at 0, as you show in the examples. Since the return type is always the same as the first argument, it might make more sense to make two instance methods out of this with different comments, i.e.

croppedTimeData = someTimeData.time_crop(interval, unit)
croppedSignal = someSignal.time_crop(interval, unit)

This version would be similar to the filter.impulse_response() functions, which also do slightly different things depending on the type of filter. Doing so would also help with type hints in vscode etc, since then the IDE could infer the output type from the object it was used on.

Perhaps we can discuss this in the weekly meeting in 7 days.

Thank you very much for such a comprehensive review! I appreciate your opinion.

Regarding the first point: I don't use pyfar myself, so it's always difficult for me to evaluate the context in which the implemented functions will be used. If the majority agrees that the end of the interval should not be included in the new signal, I will of course apply these changes.

Regarding the second point: I would like to note that the idea of adding TimeData to this function as alternative data type for the parameter signal has been around since one of the very first comments on this PR. Speaking spontaneously, I have no problem with turning this function into an instance method. However, next time I would appreciate knowing in advance if there are any opinions against combining two different data types in one function.
But, as with the interval end, if the majority agrees that the function should be turned into an instance method, I will certainly do so.

And I agree that this is a topic for discussion at the weekly meeting :)

@jf-som
Copy link
Copy Markdown
Contributor

jf-som commented Nov 21, 2025

Your are right in that it's pretty late for structure changes like this, though the thought only came to me now that I saw the different examples in practice... Sorry!

For now I just think it's something worth discussing. If we decide to make it instance methods instead, I don't think it will be too much work. But I'm also open to implement that change myself if it comes to it, I'm not trying to offload extra work onto you ^^

@h-chmeruk
Copy link
Copy Markdown
Contributor Author

Your are right in that it's pretty late for structure changes like this, though the thought only came to me now that I saw the different examples in practice... Sorry!

For now I just think it's something worth discussing. If we decide to make it instance methods instead, I don't think it will be too much work. But I'm also open to implement that change myself if it comes to it, I'm not trying to offload extra work onto you ^^

It's fine, don't worry, I also think that implementing this change won't take long. And it's certainly better to mention possible improvements belatedly than not to mention them at all.
So thank you again ^-^

Copy link
Copy Markdown
Contributor

@jf-som jf-som left a comment

Choose a reason for hiding this comment

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

As discussed in the weekly, I consider this ready for merge. 🙌

As a last minor edit, it would be nice if you could add a short hint to the different signal.times behavior between Signal and TimeData input types before the merge, like we discussed in the weekly.

Thanks for implementation!

Copy link
Copy Markdown
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.

approved, execpt hint about the interval, feel free to ajust my recommendation.
Thank you Hanna.

@h-chmeruk h-chmeruk requested review from ahms5 and jf-som December 1, 2025 11:21
@ahms5 ahms5 modified the milestone: v0.8.0 Dec 3, 2025
@mberz mberz added this to the v0.8.0 milestone Dec 12, 2025
@mberz mberz merged commit 0f6586e into develop Dec 12, 2025
11 of 12 checks passed
@github-project-automation github-project-automation bot moved this from Require review to Done in Weekly Planning Dec 12, 2025
@mberz mberz deleted the feature/time_slicing_for_signals branch December 12, 2025 13:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dsp feature For requesting new features

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants