@@ -346,89 +346,3 @@ def heart_beat_interval(
346346 )
347347
348348 return data , hbi
349-
350-
351- @return_physio_or_metric ()
352- @physio .make_operation ()
353- def cardiac_phase (data , slice_timings , n_scans , t_r , peaks = None , fs = None , ** kwargs ):
354- """Calculate cardiac phase from cardiac peaks.
355-
356- Assumes that timing of cardiac events are given in same units
357- as slice timings, for example seconds.
358-
359- Parameters
360- ----------
361- data : physutils.Physio, np.ndarray, or array-like object
362- Object containing the timeseries of the recorded cardiac signal
363- slice_timings : 1D array_like
364- Slice times, in seconds.
365- n_scans : int
366- Number of volumes in the imaging run.
367- t_r : float
368- Sampling rate of the imaging run, in seconds.
369- fs : float, optional if data is a physutils.Physio
370- Sampling rate of `data` in Hz
371- peaks : :obj:`numpy.ndarray`, optional if data is a physutils.Physio
372- Indices of peaks in `data`
373-
374- Returns
375- -------
376- phase_card : array_like
377- Cardiac phase signal, of shape (n_scans,)
378- """
379- if isinstance (data , physio .Physio ):
380- # Initialize physio object
381- data = physio .check_physio (data , ensure_fs = True , copy = True )
382- elif fs is not None and peaks is not None :
383- data = io .load_physio (data , fs = fs )
384- data ._metadata ["peaks" ] = peaks
385- else :
386- raise ValueError (
387- """
388- To use this function you should either provide a Physio object
389- with existing peaks metadata (e.g. using the peakdet module), or
390- by providing the physiological data timeseries, the sampling frequency,
391- and the peak indices separately.
392- """
393- )
394- if data .peaks .size == 0 :
395- raise ValueError (
396- """
397- Peaks must be a non-empty list.
398- Make sure to run peak detection on your physiological data first,
399- using the peakdet module, or other software of your choice.
400- """
401- )
402-
403- assert slice_timings .ndim == 1 , "Slice times must be a 1D array"
404- n_slices = np .size (slice_timings )
405- phase_card = np .zeros ((n_scans , n_slices ))
406-
407- card_peaks_sec = data .peaks / data .fs
408- for i_slice in range (n_slices ):
409- # generate slice acquisition timings across all scans
410- times_crSlice = t_r * np .arange (n_scans ) + slice_timings [i_slice ]
411- phase_card_crSlice = np .zeros (n_scans )
412- for j_scan in range (n_scans ):
413- previous_card_peaks = np .asarray (
414- np .nonzero (card_peaks_sec < times_crSlice [j_scan ])
415- )
416- if np .size (previous_card_peaks ) == 0 :
417- t1 = 0
418- else :
419- last_peak = previous_card_peaks [0 ][- 1 ]
420- t1 = card_peaks_sec [last_peak ]
421- next_card_peaks = np .asarray (
422- np .nonzero (card_peaks_sec > times_crSlice [j_scan ])
423- )
424- if np .size (next_card_peaks ) == 0 :
425- t2 = n_scans * t_r
426- else :
427- next_peak = next_card_peaks [0 ][0 ]
428- t2 = card_peaks_sec [next_peak ]
429- phase_card_crSlice [j_scan ] = (
430- 2 * np .math .pi * (times_crSlice [j_scan ] - t1 )
431- ) / (t2 - t1 )
432- phase_card [:, i_slice ] = phase_card_crSlice
433-
434- return data , phase_card
0 commit comments