Skip to content
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

Add support for segmentation with continuous trigger #474

Open
me-pic opened this issue Dec 11, 2024 · 6 comments
Open

Add support for segmentation with continuous trigger #474

me-pic opened this issue Dec 11, 2024 · 6 comments
Assignees
Labels
Enhancement New feature or request

Comments

@me-pic
Copy link

me-pic commented Dec 11, 2024

Detailed Description

It would be nice to be able to segment runs that are defined by a continuous trigger (see last channel in the figure below). It that case, when the run starts, the value of that channel changes from 0 to 5, and when it ends, it changes from 5 to 0. It would thus be useful if, to be able to segment the physiological signals from when the value of the trigger channel initial change to the point where it change again to 0.

physio_eeg

Context / Motivation

Currently there is no support (?) for segmenting runs from recordings containing continuous trigger (ex. physio recordings not acquired with fMRI).

Possible Implementation

If value of tr argument is False, compute the gradient on the trigger channel to find the start/end of the runs. The number of expected timepoints could be based on the expected duration (number of expected timepoints = expected duration * sampling rate) of the run instead of the number of expected triggers. The function check_trigger_amount in physio_obj.py could be changed accordingly. That function will have to be called in slice4phys.py if tr is False.

@me-pic me-pic added the Enhancement New feature or request label Dec 11, 2024
@me-pic
Copy link
Author

me-pic commented Dec 12, 2024

I would be curious to hear some feedback on that. I've taken a closer look to the code, and I think it would be fairly straightforward to change the check_trigger_amount function. Maybe we can do something like checking if the number of segments in the recording match the length of the list of expected timepoints. In the case of a continuous trigger, that would already be given by that line : num_timepoints_found = np.count_nonzero(np.ediff1d(timepoints.astype(np.int8)) > 0).

So maybe something like:

if len(num_timepoints_found) > len(num_timepoints_expected):
    # We can initially consider the extra runs at the end of the recording
    LGR.warning(f"Found {len(num_timepoints_found)-len(num_timepoints_expected)} more than expected. Will proceed by considering that we have {len(num_timepoints_found)-len(num_timepoints_expected)} extra runs at the end of the recording")
    # Then adjust which runs to consider accordingly
    new_timepoints_to_consider = num_timepoints_found[:np.where(np.ediff1d(timepoints.astype(np.int8))>0)[-(len(num_timepoints_found)-len(num_timepoints_expected))]]
   
    # proceed to verification on the expected duration (total number of timepoints). 
    # i.e for each different segments: new_num_timepoints_found == num_expected_timpoints

    # If that does not match, we can restart considering that the extra runs are at the beginning.
    new_timepoints_to_consider = num_timepoints_found[np.where(np.ediff1d(timepoints.astype(np.int8))>0)[-(len(num_timepoints_found)-len(num_timepoints_expected))]:]
else:
   # In the case that we have missing runs in the recording (ex. the physio recording stopped before the end of the experiment)
    LGR.warning(f"Found {len(num_timepoints_expected)-len(num_timepoints_found)} less than expected. Will proceed by considering that we have {len(num_timepoints_expected)-len(num_timepoints_found)} missing runs at the end of the recording")
    
    # Proceed in a similar way as above

Would that work ? Not sure if everything should go in the check_trigger_amount function or create a new function for that specific case, even if there will be some redundancy with check_trigger_amount.

@smoia
Copy link
Member

smoia commented Dec 12, 2024

@tsalo didn't you try to implement something similar back in the days?

@smoia
Copy link
Member

smoia commented Dec 12, 2024

(It is trick-able in the sense that you can have a train of 1-trigger runs with TR equivalent to the full span of the trigger, but it's true that we do not have a way to deal with continuous triggers)

@me-pic
Copy link
Author

me-pic commented Dec 12, 2024

Just to make sure, @smoia do you think it would work to segment runs with continuous trigger by given to the tr parameters a list containing the duration (in seconds) of the runs, and for the number of expected timepoints to be 1 for each run ?

@smoia
Copy link
Member

smoia commented Dec 12, 2024

Absolutely yes - we've been doing that. However, I do see the appeal to capture automatically when the trigger ends so that the program can guess the run duration.

Incidentally, the same code could even detect a group of triggers and decide how to divide runs based on adjacent trigger distances

@tsalo
Copy link
Member

tsalo commented Dec 12, 2024

@tsalo didn't you try to implement something similar back in the days?

I did have something to work with this kind of trigger, but in my case it was exacerbated by the fact that the trigger sometimes wasn't disabled at the end of a run or enabled at the start of a run, so I had to align times of runs from the BOLD DICOMs against the timing of the starts of trigger blocks that were present. While I did have a working branch that implemented it (and it's what I used for the physio data in this dataset), I doubt that it's worth incorporating into phys2bids proper.

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

No branches or pull requests

3 participants