Ejemplo n.º 1
0
    def load_from_file(self, filename=None):
        if filename:
            # Get data from file:
            data = np.transpose(
                nib.load(filename[0]).get_data(),
                [1, 2, 3, 4, 5, 0]).squeeze()

            # Use the water unsuppressed data to combine over coils:
            w_data, w_supp_data = ana.coil_combine(data.squeeze())
            self.timeseries = w_supp_data
Ejemplo n.º 2
0
    def __init__(self,
                 in_file,
                 line_broadening=5,
                 zerofill=100,
                 filt_method=None,
                 min_ppm=-0.7,
                 max_ppm=4.3):
        """
        Parameters
        ----------

        in_file : str
            Path to a nifti file with SV-PROBE MRS data.

        line_broadening : float
           How much to broaden the spectral line-widths (Hz)
           
        zerofill : int
           How many zeros to add to the spectrum for additional spectral
           resolution

        min_ppm, max_ppm : float
           The limits of the spectra that are represented

        fit_lb, fit_ub : float
           The limits for the part of the spectrum for which we fit the
           creatine and GABA peaks. 
        
        """
        self.raw_data = np.transpose(
            nib.load(in_file).get_data(), [1, 2, 3, 4, 5, 0]).squeeze()

        w_data, w_supp_data = ana.coil_combine(self.raw_data,
                                               w_idx=range(8),
                                               coil_dim=1)
        # We keep these around for reference, as private attrs
        self._water_data = w_data
        self._w_supp_data = w_supp_data
        # This is the time-domain signal of interest, combined over coils:
        self.data = ana.subtract_water(w_data, w_supp_data)

        f_hz, spectra = ana.get_spectra(self.data,
                                        line_broadening=line_broadening,
                                        zerofill=zerofill,
                                        filt_method=filt_method)

        self.f_hz = f_hz
        # Convert from Hz to ppm and extract the part you are interested in.
        f_ppm = ut.freq_to_ppm(self.f_hz)
        idx0 = np.argmin(np.abs(f_ppm - min_ppm))
        idx1 = np.argmin(np.abs(f_ppm - max_ppm))
        self.idx = slice(idx1, idx0)
        self.f_ppm = f_ppm
        self.spectra = spectra[:, self.idx]
Ejemplo n.º 3
0
def test_coil_combine():
    """
    Test combining of information from different coils
    """
    data = np.transpose(nib.load(file_name).get_data(), [1,2,3,4,5,0]).squeeze()
    w_data, w_supp_data = ana.coil_combine(data)
    # Make sure that the time-dimension is still correct: 
    npt.assert_equal(w_data.shape[-1], data.shape[-1])
    npt.assert_equal(w_supp_data.shape[-1], data.shape[-1])

    # Check that the phase for the first data point is approximately the
    # same and approximately 0 for all the water-channels:
    npt.assert_array_almost_equal(np.angle(w_data)[:,:,0],
                                  np.zeros_like(w_data[:,:,0]),
                                  decimal=1)  # We're not being awfully strict
Ejemplo n.º 4
0
    def __init__(self, in_file, line_broadening=5, zerofill=100,
                 filt_method=None, min_ppm=-0.7, max_ppm=4.3):
        """
        Parameters
        ----------

        in_file : str
            Path to a nifti file with SV-PROBE MRS data.

        line_broadening : float
           How much to broaden the spectral line-widths (Hz)
           
        zerofill : int
           How many zeros to add to the spectrum for additional spectral
           resolution

        min_ppm, max_ppm : float
           The limits of the spectra that are represented

        fit_lb, fit_ub : float
           The limits for the part of the spectrum for which we fit the
           creatine and GABA peaks. 
        
        """
        self.raw_data = np.transpose(nib.load(in_file).get_data(),
                                     [1,2,3,4,5,0]).squeeze()

        w_data, w_supp_data = ana.coil_combine(self.raw_data, w_idx = range(8),
                                               coil_dim=1)
        # We keep these around for reference, as private attrs
        self._water_data = w_data
        self._w_supp_data = w_supp_data
        # This is the time-domain signal of interest, combined over coils:
        self.data = ana.subtract_water(w_data, w_supp_data)

        f_hz, spectra = ana.get_spectra(self.data,
                                        line_broadening=line_broadening,
                                        zerofill=zerofill,
                                        filt_method=filt_method)
                                           
        self.f_hz = f_hz
        # Convert from Hz to ppm and extract the part you are interested in.
        f_ppm = ut.freq_to_ppm(self.f_hz)
        idx0 = np.argmin(np.abs(f_ppm - min_ppm))
        idx1 = np.argmin(np.abs(f_ppm - max_ppm))
        self.idx = slice(idx1, idx0)
        self.f_ppm = f_ppm
        self.spectra = spectra[:,self.idx]
Ejemplo n.º 5
0
def test_get_spectra():
    """
    Test the function that does the spectral analysis
    """
    data = np.transpose(nib.load(file_name).get_data(), [1,2,3,4,5,0]).squeeze()
    w_data, w_supp_data = ana.coil_combine(data)

    # XXX Just basic smoke-testing for now:
    f_nonw, nonw_sig1 = ana.get_spectra(nt.TimeSeries(w_supp_data,
                                       sampling_rate=5000))

    f_nonw, nonw_sig2 = ana.get_spectra(nt.TimeSeries(w_supp_data,
                                       sampling_rate=5000),
                                       line_broadening=5)

    f_nonw, nonw_sig3 = ana.get_spectra(nt.TimeSeries(w_supp_data,
                                       sampling_rate=5000),
                                       line_broadening=5,
                                       zerofill=1000)
Ejemplo n.º 6
0
    def __init__(self,
                 in_data,
                 line_broadening=5,
                 zerofill=100,
                 filt_method=None,
                 min_ppm=-0.7,
                 max_ppm=4.3):
        """
        Parameters
        ----------

        in_data : str
            Path to a nifti file containing MRS data.

        line_broadening : float
           How much to broaden the spectral line-widths (Hz)
           
        zerofill : int
           How many zeros to add to the spectrum for additional spectral
           resolution

        min_ppm, max_ppm : float
           The limits of the spectra that are represented

        fit_lb, fit_ub : float
           The limits for the part of the spectrum for which we fit the
           creatine and GABA peaks. 
        
        """
        if isinstance(in_data, str):
            # The nifti files follow the strange nifti convention, but we want
            # to use our own logic, which is transients on dim 0 and time on
            # dim -1:
            self.raw_data = np.transpose(
                nib.load(in_data).get_data(), [1, 2, 3, 4, 5, 0]).squeeze()
        elif isinstance(in_data, np.ndarray):
            self.raw_data = in_data

        w_data, w_supp_data = ana.coil_combine(self.raw_data)
        f_hz, w_supp_spectra = ana.get_spectra(w_supp_data,
                                               line_broadening=line_broadening,
                                               zerofill=zerofill,
                                               filt_method=filt_method)

        self.w_supp_spectra = w_supp_spectra

        # Often, there will be some small offset from the on-resonance
        # frequency, which we can correct for. We fit a Lorentzian to each of
        # the spectra from the water-suppressed data, so that we can get a
        # phase-corrected estimate of the frequency shift, instead of just
        # relying on the frequency of the maximum:
        self.w_supp_lorentz = np.zeros(w_supp_spectra.shape[:-1] + (6, ))
        for ii in range(self.w_supp_lorentz.shape[0]):
            for jj in range(self.w_supp_lorentz.shape[1]):
                self.w_supp_lorentz[ii,jj]=\
                    ana._do_lorentzian_fit(f_hz, w_supp_spectra[ii,jj])

        # We store the frequency offset for each transient/echo:
        self.freq_offset = self.w_supp_lorentz[..., 0]

        # But for now, we average over all the transients/echos for the
        # correction:
        mean_freq_offset = np.mean(self.w_supp_lorentz[..., 0])
        f_hz = f_hz - mean_freq_offset

        self.water_fid = w_data
        self.w_supp_fid = w_supp_data
        # This is the time-domain signal of interest, combined over coils:
        self.data = ana.subtract_water(w_data, w_supp_data)

        _, spectra = ana.get_spectra(self.data,
                                     line_broadening=line_broadening,
                                     zerofill=zerofill,
                                     filt_method=filt_method)

        self.f_hz = f_hz
        # Convert from Hz to ppm and extract the part you are interested in.
        f_ppm = ut.freq_to_ppm(self.f_hz)
        idx0 = np.argmin(np.abs(f_ppm - min_ppm))
        idx1 = np.argmin(np.abs(f_ppm - max_ppm))
        self.idx = slice(idx1, idx0)
        self.f_ppm = f_ppm

        self.echo_off = spectra[:, 1]
        self.echo_on = spectra[:, 0]

        # Calculate sum and difference:
        self.diff_spectra = self.echo_on - self.echo_off
        self.sum_spectra = self.echo_off + self.echo_on
Ejemplo n.º 7
0
    def __init__(self,
                 in_data,
                 w_idx=[1,2,3],
                 line_broadening=5,
                 zerofill=100,
                 filt_method=None,
                 spect_method=dict(NFFT=1024, n_overlap=1023, BW=2),
                 min_ppm=-0.7,
                 max_ppm=4.3,
                 sampling_rate=5000.):
        """
        Parameters
        ----------

        in_data : str
            Path to a nifti file containing MRS data.

        w_idx : list (optional)
            The indices to the non-water-suppressed transients. Per default we
            take the 2nd-4th transients. We dump the first one, because it
            seems to be quite different than the rest of them. 

        line_broadening : float (optional)
           How much to broaden the spectral line-widths (Hz). Default: 5
           
        zerofill : int (optional)
           How many zeros to add to the spectrum for additional spectral
           resolution. Default: 100

        filt_method : dict (optional)
            How/whether to filter the data. Default: None (#nofilter)

        spect_method: dict (optional)
            How to derive spectra. Per default, a simple Fourier transform will
            be derived from apodized time-series, but other methods can also be
            used (see `nitime` documentation for details)
            
        min_ppm, max_ppm : float
           The limits of the spectra that are represented

        sampling_rate : float
           The sampling rate in Hz.
        
        """
        if isinstance(in_data, str):
            # The nifti files follow the strange nifti convention, but we want
            # to use our own logic, which is transients on dim 0 and time on
            # dim -1:
            self.raw_data = np.transpose(nib.load(in_data).get_data(),
                                         [1,2,3,4,5,0]).squeeze()
        elif isinstance(in_data, np.ndarray):
            self.raw_data = in_data

        w_data, w_supp_data = ana.coil_combine(self.raw_data, w_idx=w_idx,
                                               sampling_rate=sampling_rate)
        f_hz, w_supp_spectra = ana.get_spectra(w_supp_data,
                                           line_broadening=line_broadening,
                                           zerofill=zerofill,
                                           filt_method=filt_method,
                                           spect_method=spect_method)

        self.w_supp_spectra = w_supp_spectra

        # Often, there will be some small offset from the on-resonance
        # frequency, which we can correct for. We fit a Lorentzian to each of
        # the spectra from the water-suppressed data, so that we can get a
        # phase-corrected estimate of the frequency shift, instead of just
        # relying on the frequency of the maximum:
        self.w_supp_lorentz = np.zeros(w_supp_spectra.shape[:-1] + (6,))
        for ii in range(self.w_supp_lorentz.shape[0]):
            for jj in range(self.w_supp_lorentz.shape[1]):
                self.w_supp_lorentz[ii,jj]=\
                    ana._do_lorentzian_fit(f_hz, w_supp_spectra[ii,jj])

        # We store the frequency offset for each transient/echo:
        self.freq_offset = self.w_supp_lorentz[..., 0]

        # But for now, we average over all the transients/echos for the
        # correction: 
        mean_freq_offset = np.mean(self.w_supp_lorentz[..., 0])
        f_hz = f_hz - mean_freq_offset
    
        self.water_fid = w_data
        self.w_supp_fid = w_supp_data
        # This is the time-domain signal of interest, combined over coils:
        self.data = ana.subtract_water(w_data, w_supp_data)

        _, spectra = ana.get_spectra(self.data,
                                     line_broadening=line_broadening,
                                     zerofill=zerofill,
                                     filt_method=filt_method)

        self.f_hz = f_hz
        # Convert from Hz to ppm and extract the part you are interested in.
        f_ppm = ut.freq_to_ppm(self.f_hz)
        idx0 = np.argmin(np.abs(f_ppm - min_ppm))
        idx1 = np.argmin(np.abs(f_ppm - max_ppm))
        self.idx = slice(idx1, idx0)
        self.f_ppm = f_ppm
    
        self.echo_off = spectra[:, 1]
        self.echo_on = spectra[:, 0]

        # Calculate sum and difference:
        self.diff_spectra = self.echo_on - self.echo_off
        self.sum_spectra = self.echo_off + self.echo_on
Ejemplo n.º 8
0
    def __init__(self,
                 in_data,
                 w_idx=[1,2,3],
                 line_broadening=5,
                 zerofill=100,
                 filt_method=None,
                 spect_method=dict(NFFT=1024, n_overlap=1023, BW=2),
                 min_ppm=-0.7,
                 max_ppm=4.3,
                 sampling_rate=5000.):
        """
        Parameters
        ----------

        in_data : str
            Path to a nifti file containing MRS data.

        w_idx : list (optional)
            The indices to the non-water-suppressed transients. Per default we
            take the 2nd-4th transients. We dump the first one, because it
            seems to be quite different than the rest of them. 

        line_broadening : float (optional)
           How much to broaden the spectral line-widths (Hz). Default: 5
           
        zerofill : int (optional)
           How many zeros to add to the spectrum for additional spectral
           resolution. Default: 100

        filt_method : dict (optional)
            How/whether to filter the data. Default: None (#nofilter)

        spect_method: dict (optional)
            How to derive spectra. Per default, a simple Fourier transform will
            be derived from apodized time-series, but other methods can also be
            used (see `nitime` documentation for details)
            
        min_ppm, max_ppm : float
           The limits of the spectra that are represented

        sampling_rate : float
           The sampling rate in Hz.
        
        """
        if isinstance(in_data, str):
            # The nifti files follow the strange nifti convention, but we want
            # to use our own logic, which is transients on dim 0 and time on
            # dim -1:
            self.raw_data = np.transpose(nib.load(in_data).get_data(),
                                         [1,2,3,4,5,0]).squeeze()
        elif isinstance(in_data, np.ndarray):
            self.raw_data = in_data

        w_data, w_supp_data = ana.coil_combine(self.raw_data, w_idx=w_idx,
                                               sampling_rate=sampling_rate)
        f_hz, w_supp_spectra = ana.get_spectra(w_supp_data,
                                           line_broadening=line_broadening,
                                           zerofill=zerofill,
                                           filt_method=filt_method,
                                           spect_method=spect_method)

        self.w_supp_spectra = w_supp_spectra

        # Often, there will be some small offset from the on-resonance
        # frequency, which we can correct for. We fit a Lorentzian to each of
        # the spectra from the water-suppressed data, so that we can get a
        # phase-corrected estimate of the frequency shift, instead of just
        # relying on the frequency of the maximum:
        self.w_supp_lorentz = np.zeros(w_supp_spectra.shape[:-1] + (6,))
        for ii in range(self.w_supp_lorentz.shape[0]):
            for jj in range(self.w_supp_lorentz.shape[1]):
                self.w_supp_lorentz[ii,jj]=\
                    ana._do_lorentzian_fit(f_hz, w_supp_spectra[ii,jj])

        # We store the frequency offset for each transient/echo:
        self.freq_offset = self.w_supp_lorentz[..., 0]

        # But for now, we average over all the transients/echos for the
        # correction: 
        mean_freq_offset = np.mean(self.w_supp_lorentz[..., 0])
        f_hz = f_hz - mean_freq_offset
    
        self.water_fid = w_data
        self.w_supp_fid = w_supp_data
        # This is the time-domain signal of interest, combined over coils:
        self.data = ana.subtract_water(w_data, w_supp_data)

        _, spectra = ana.get_spectra(self.data,
                                     line_broadening=line_broadening,
                                     zerofill=zerofill,
                                     filt_method=filt_method)

        self.f_hz = f_hz
        # Convert from Hz to ppm and extract the part you are interested in.
        f_ppm = ut.freq_to_ppm(self.f_hz)
        idx0 = np.argmin(np.abs(f_ppm - min_ppm))
        idx1 = np.argmin(np.abs(f_ppm - max_ppm))
        self.idx = slice(idx1, idx0)
        self.f_ppm = f_ppm
    
        self.echo_off = spectra[:, 1]
        self.echo_on = spectra[:, 0]

        # Calculate sum and difference:
        self.diff_spectra = self.echo_on - self.echo_off
        self.sum_spectra = self.echo_off + self.echo_on
Ejemplo n.º 9
0
    def __init__(self, in_data, line_broadening=5, zerofill=100,
                 filt_method=None, min_ppm=-0.7, max_ppm=4.3):
        """
        Parameters
        ----------

        in_data : str
            Path to a nifti file containing MRS data.

        line_broadening : float
           How much to broaden the spectral line-widths (Hz)
           
        zerofill : int
           How many zeros to add to the spectrum for additional spectral
           resolution

        min_ppm, max_ppm : float
           The limits of the spectra that are represented

        fit_lb, fit_ub : float
           The limits for the part of the spectrum for which we fit the
           creatine and GABA peaks. 
        
        """
        if isinstance(in_data, str):
            # The nifti files follow the strange nifti convention, but we want
            # to use our own logic, which is transients on dim 0 and time on
            # dim -1:
            self.raw_data = np.transpose(nib.load(in_data).get_data(),
                                         [1,2,3,4,5,0]).squeeze()
        elif isinstance(in_data, np.ndarray):
            self.raw_data = in_data

        w_data, w_supp_data = ana.coil_combine(self.raw_data)
        f_hz, w_supp_spectra = ana.get_spectra(w_supp_data,
                                           line_broadening=line_broadening,
                                           zerofill=zerofill,
                                           filt_method=filt_method)

        self.w_supp_spectra = w_supp_spectra

        # Often, there will be some small offset from the on-resonance
        # frequency, which we can correct for. We fit a Lorentzian to each of
        # the spectra from the water-suppressed data, so that we can get a
        # phase-corrected estimate of the frequency shift, instead of just
        # relying on the frequency of the maximum:
        self.w_supp_lorentz = np.zeros(w_supp_spectra.shape[:-1] + (6,))
        for ii in range(self.w_supp_lorentz.shape[0]):
            for jj in range(self.w_supp_lorentz.shape[1]):
                self.w_supp_lorentz[ii,jj]=\
                    ana._do_lorentzian_fit(f_hz, w_supp_spectra[ii,jj])

        # We store the frequency offset for each transient/echo:
        self.freq_offset = self.w_supp_lorentz[..., 0]

        # But for now, we average over all the transients/echos for the
        # correction: 
        mean_freq_offset = np.mean(self.w_supp_lorentz[..., 0])
        f_hz = f_hz - mean_freq_offset
    
        self.water_fid = w_data
        self.w_supp_fid = w_supp_data
        # This is the time-domain signal of interest, combined over coils:
        self.data = ana.subtract_water(w_data, w_supp_data)

        _, spectra = ana.get_spectra(self.data,
                                     line_broadening=line_broadening,
                                     zerofill=zerofill,
                                     filt_method=filt_method)

        self.f_hz = f_hz
        # Convert from Hz to ppm and extract the part you are interested in.
        f_ppm = ut.freq_to_ppm(self.f_hz)
        idx0 = np.argmin(np.abs(f_ppm - min_ppm))
        idx1 = np.argmin(np.abs(f_ppm - max_ppm))
        self.idx = slice(idx1, idx0)
        self.f_ppm = f_ppm
    
        self.echo_off = spectra[:, 1]
        self.echo_on = spectra[:, 0]

        # Calculate sum and difference:
        self.diff_spectra = self.echo_on - self.echo_off
        self.sum_spectra = self.echo_off + self.echo_on