Esempio n. 1
0
    def gradient_waveforms(self):
        duration, num_blocks, _ = self.duration()

        wave_length = math.ceil(duration / self.grad_raster_time)
        grad_channels = 3
        grad_waveforms = np.zeros((grad_channels, wave_length))
        grad_channels = ['gx', 'gy', 'gz']

        t0 = 0
        t0_n = 0
        for i in range(num_blocks):
            block = self.get_block(i + 1)
            for j in range(len(grad_channels)):
                if hasattr(block, grad_channels[j]):
                    grad = getattr(block, grad_channels[j])
                    if grad.type == 'grad':
                        nt_start = round(
                            (grad.delay + grad.t[0]) / self.grad_raster_time)
                        waveform = grad.waveform
                    else:
                        nt_start = round(grad.delay / self.grad_raster_time)
                        if abs(grad.flat_time) > np.finfo(float).eps:
                            t = np.cumsum([
                                0, grad.rise_time, grad.flat_time,
                                grad.fall_time
                            ])
                            trap_form = np.multiply([0, 1, 1, 0],
                                                    grad.amplitude)
                        else:
                            t = np.cumsum([0, grad.rise_time, grad.fall_time])
                            trap_form = np.multiply([0, 1, 0], grad.amplitude)

                        tn = math.floor(t[-1] / self.grad_raster_time)
                        t = np.append(t, t[-1] + self.grad_raster_time)
                        trap_form = np.append(trap_form, 0)

                        if abs(grad.amplitude) > np.finfo(float).eps:
                            waveform = points_to_waveform(
                                t, trap_form, self.grad_raster_time)
                        else:
                            waveform = np.zeros(tn + 1)

                    if waveform.size != np.sum(np.isfinite(waveform)):
                        raise Warning(
                            'Not all elements of the generated waveform are finite'
                        )

                    grad_waveforms[
                        j,
                        int(t0_n +
                            nt_start):int(t0_n + nt_start +
                                          max(waveform.shape))] = waveform

            t0 += calc_duration(block)
            t0_n = round(t0 / self.grad_raster_time)

        return grad_waveforms
def make_extended_trapezoid(channel: str, times: np.ndarray = np.zeros(1), amplitudes: np.ndarray = np.zeros(1),
                            system: Opts = Opts(), max_grad: float = 0, max_slew: float = 0, skip_check: bool = False):
    """
    Creates an extend trapezoidal gradient event by defined by amplitude values in `amplitudes` at time indices in
    `times`.

    Parameters
    ----------
    channel : str
        Orientation of extended trapezoidal gradient event. Must be one of x, y or z.
    times : numpy.ndarray, optional
        Time points at which `amplitudes` defines amplitude values. Default is 0.
    amplitudes : numpy.ndarray, optional
        Values defined at `times` time indices. Default is 0.
    system : Opts, optional
        System limits. Default is a system limits object initialised to default values.
    max_grad : float, optional
        Maximum gradient strength. Default is 0.
    max_slew : float, optional
        Maximum slew rate. Default is 0.
    skip_check : bool, optional
        Perform check. Default is false.

    Returns
    -------
    grad : SimpleNamespace
        Extended trapezoid gradient event.
    """
    if channel not in ['x', 'y', 'z']:
        raise ValueError()

    if not np.any(times):
        raise ValueError('At least one of the given times must be non-zero')

    if np.any(np.diff(times) <= 0):
        raise ValueError('Times must be in ascending order and all times must be distinct')

    if not np.any(amplitudes):
        raise ValueError('At least one of the given amplitudes must be non-zero')

    if skip_check is False and times[0] > 0 and amplitudes[0] != 0:
        raise ValueError('If first amplitude of a gradient is non-zero, it must connect to previous block')

    if max_grad <= 0:
        max_grad = system.max_grad

    if max_slew <= 0:
        max_slew = system.max_slew

    waveform = points_to_waveform(times=times, amplitudes=amplitudes, grad_raster_time=system.grad_raster_time)
    grad = make_arbitrary_grad(channel=channel, waveform=waveform, system=system, max_grad=max_grad, max_slew=max_slew,
                               delay=times[0])
    grad.first = amplitudes[0]
    grad.last = amplitudes[-1]

    return grad
def make_extended_trapezoid(channel,
                            times=0,
                            amplitudes=0,
                            system=Opts(),
                            max_grad=0,
                            max_slew=0,
                            skip_check=False):
    if channel not in ['x', 'y', 'z']:
        raise ValueError()

    if not np.any(times):
        raise ValueError('At least one of the given times must be non-zero')

    if np.any(np.diff(times) <= 0):
        raise ValueError(
            'Times must be in ascending order and all times mut be distinct')

    if not np.any(amplitudes):
        raise ValueError(
            'At least one of the given amplitudes must be non-zero')

    if skip_check is False and times[0] > 0 and amplitudes[0] != 0:
        raise ValueError(
            'If first amplitude of a gradient is non-zero, it must connect to previous block'
        )

    if max_grad <= 0:
        max_grad = system.max_grad

    if max_slew <= 0:
        max_slew = system.max_slew

    waveform = points_to_waveform(times=times,
                                  amplitudes=amplitudes,
                                  grad_raster_time=system.grad_raster_time)
    grad = make_arbitrary_grad(channel=channel,
                               waveform=waveform,
                               system=system,
                               max_grad=max_grad,
                               max_slew=max_slew,
                               delay=times[0])
    grad.first = amplitudes[0]
    grad.last = amplitudes[-1]

    return grad
Esempio n. 4
0
    def gradient_waveforms(self) -> np.ndarray:
        """
        Decompress the entire gradient waveform. Returns an array of shape `gradient_axesxtimepoints`.
        `gradient_axes` is typically 3.

        Returns
        -------
        grad_waveforms : numpy.ndarray
            Decompressed gradient waveform.
        """
        duration, num_blocks, _ = self.duration()

        wave_length = math.ceil(duration / self.grad_raster_time)
        grad_channels = 3
        grad_waveforms = np.zeros((grad_channels, wave_length))
        grad_channels = ['gx', 'gy', 'gz']

        t0 = 0
        t0_n = 0
        for i in range(num_blocks):
            block = self.get_block(i + 1)
            for j in range(len(grad_channels)):
                if hasattr(block, grad_channels[j]):
                    grad = getattr(block, grad_channels[j])
                    if grad.type == 'grad':
                        nt_start = round(
                            (grad.delay + grad.t[0]) / self.grad_raster_time)
                        waveform = grad.waveform
                    else:
                        nt_start = round(grad.delay / self.grad_raster_time)
                        if abs(grad.flat_time) > np.finfo(float).eps:
                            t = np.cumsum([
                                0, grad.rise_time, grad.flat_time,
                                grad.fall_time
                            ])
                            trap_form = np.multiply([0, 1, 1, 0],
                                                    grad.amplitude)
                        else:
                            t = np.cumsum([0, grad.rise_time, grad.fall_time])
                            trap_form = np.multiply([0, 1, 0], grad.amplitude)

                        tn = math.floor(t[-1] / self.grad_raster_time)
                        t = np.append(t, t[-1] + self.grad_raster_time)
                        trap_form = np.append(trap_form, 0)

                        if abs(grad.amplitude) > np.finfo(float).eps:
                            waveform = points_to_waveform(
                                t, trap_form, self.grad_raster_time)
                        else:
                            waveform = np.zeros(tn + 1)

                    if waveform.size != np.sum(np.isfinite(waveform)):
                        raise Warning(
                            'Not all elements of the generated waveform are finite'
                        )
                    """
                    Matlab dynamically resizes arrays during slice assignment operation if assignment is out of bounds
                    Numpy does not
                    Following lines are a workaround
                    """
                    l1, l2 = int(t0_n + nt_start), int(t0_n + nt_start +
                                                       max(waveform.shape))
                    if l2 > grad_waveforms.shape[1]:
                        grad_waveforms.resize((len(grad_channels), l2))
                    grad_waveforms[j, l1:l2] = waveform

            t0 += calc_duration(block)
            t0_n = round(t0 / self.grad_raster_time)

        return grad_waveforms
Esempio n. 5
0
def add_gradients(grads: Union[list, tuple],
                  system=Opts(),
                  max_grad: int = 0,
                  max_slew: int = 0) -> SimpleNamespace:
    """
    Superpose several gradient events.

    Parameters
    ----------
    grads : list or tuple
        List or tuple of 'SimpleNamespace' gradient events.
    system : Opts, optional, default=Opts()
        System limits.
    max_grad : float, optional, default=0
        Maximum gradient amplitude.
    max_slew : float, optional, default=0
        Maximum slew rate.

    Returns
    -------
    grad : SimpleNamespace
        Superimposition of gradient events from `grads`.
    """
    max_grad = max_grad if max_grad > 0 else system.max_grad
    max_slew = max_slew if max_slew > 0 else system.max_slew

    if len(grads) < 2:
        raise Exception()

    # First gradient defines channel
    channel = grads[0].channel

    # Find out the general delay of all gradients and other statistics
    delays, firsts, lasts, durs = [], [], [], []
    for ii in range(len(grads)):
        delays.append(grads[ii].delay)
        firsts.append(grads[ii].first)
        lasts.append(grads[ii].last)
        durs.append(calc_duration(grads[ii]))

    # Convert to numpy.ndarray for fancy-indexing later on
    firsts, lasts = np.array(firsts), np.array(lasts)

    common_delay = min(delays)
    total_duration = max(durs)

    waveforms = dict()
    max_length = 0
    for ii in range(len(grads)):
        g = grads[ii]
        if g.type == 'grad':
            waveforms[ii] = g.waveform
        elif g.type == 'trap':
            if g.flat_time > 0:  # Triangle or trapezoid
                times = [
                    g.delay - common_delay,
                    g.delay - common_delay + g.rise_time,
                    g.delay - common_delay + g.rise_time + g.flat_time,
                    g.delay - common_delay + g.rise_time + g.flat_time +
                    g.fall_time
                ]
                amplitudes = [0, g.amplitude, g.amplitude, 0]
            else:
                times = [
                    g.delay - common_delay,
                    g.delay - common_delay + g.rise_time,
                    g.delay - common_delay + g.rise_time + g.flat_time
                ]
                amplitudes = [0, g.amplitude, 0]
            waveforms[ii] = points_to_waveform(
                times=times,
                amplitudes=amplitudes,
                grad_raster_time=system.grad_raster_time)
        else:
            raise ValueError('Unknown gradient type')

        if g.delay - common_delay > 0:
            # Stop for numpy.arange is not g.delay - common_delay - system.grad_raster_time like in Matlab
            # so as to include the endpoint
            t_delay = np.arange(0,
                                g.delay - common_delay,
                                step=system.grad_raster_time)
            waveforms[ii] = np.insert(waveforms[ii], 0, t_delay)

        num_points = len(waveforms[ii])
        max_length = num_points if num_points > max_length else max_length

    w = np.zeros(max_length)
    for ii in range(len(grads)):
        wt = np.zeros(max_length)
        wt[0:len(waveforms[ii])] = waveforms[ii]
        w += wt

    grad = make_arbitrary_grad(channel,
                               w,
                               system,
                               max_slew=max_slew,
                               max_grad=max_grad,
                               delay=common_delay)
    grad.first = np.sum(firsts[np.array(delays) == common_delay])
    grad.last = np.sum(lasts[np.where(durs == total_duration)])

    return grad
Esempio n. 6
0
def add_gradients(grads, system=Opts(), max_grad=0, max_slew=0):
    max_grad = max_grad if max_grad > 0 else system.max_grad
    max_slew = max_slew if max_slew > 0 else system.max_slew

    if len(grads) < 2:
        raise Exception()

    # First gradient defines channel
    channel = grads[0].channel

    # Find out the general delay of all gradients and other statistics
    delays, firsts, lasts, durs = [], [], [], []
    for ii in range(len(grads)):
        delays.append(grads[ii].delay)
        firsts.append(grads[ii].first)
        lasts.append(grads[ii].last)
        durs.append(calc_duration(grads[ii]))

    common_delay = min(delays)
    total_duration = max(durs)

    waveforms = dict()
    max_length = 0
    for ii in range(len(grads)):
        g = grads[ii]
        if g.type == 'grad':
            waveforms[ii] = g.waveform
        elif g.type == 'trap':
            if g.flat_time > 0:  # Triangle or trapezoid
                times = [
                    g.delay - common_delay,
                    g.delay - common_delay + g.rise_time,
                    g.delay - common_delay + g.rise_time + g.flat_time,
                    g.delay - common_delay + g.rise_time + g.flat_time +
                    g.fall_time
                ]
                amplitudes = [0, g.amplitude, g.amplitude, 0]
            else:
                times = [
                    g.delay - common_delay,
                    g.delay - common_delay + g.rise_time,
                    g.delay - common_delay + g.rise_time + g.flat_time
                ]
                amplitudes = [0, g.amplitude, 0]
            waveforms[ii] = points_to_waveform(
                times=times,
                amplitudes=amplitudes,
                grad_raster_time=system.grad_raster_time)
        else:
            raise ValueError('Unknown gradient type')

        if g.delay - common_delay > 0:
            t_delay = list(
                range(0, g.delay - common_delay - system.grad_raster_time,
                      system.grad_raster_time))
            waveforms[ii] = waveforms[ii].insert(0, t_delay)

        num_points = len(waveforms[ii])
        max_length = num_points if num_points > max_length else max_length

    w = np.zeros((max_length, 1))
    for ii in range(len(grads)):
        wt = np.zeros((max_length, 1))
        wt[0:len(waveforms[ii])] = waveforms[ii]
        w += wt

    grad = make_arbitrary_grad(channel,
                               w,
                               system,
                               max_slew=max_slew,
                               max_grad=max_grad,
                               delay=common_delay)
    grad.first = np.sum(firsts[np.where(delays == common_delay)])
    grad.last = np.sum(lasts[np.where(durs == total_duration)])

    return grad
def make_extended_trapezoid(channel: str, amplitudes: Iterable = np.zeros(1), max_grad: float = 0,
                            max_slew: float = 0, system: Opts = Opts(), skip_check: bool = False,
                            times: Iterable = np.zeros(1)) -> SimpleNamespace:
    """
    Creates an extend trapezoidal gradient event by defined by amplitude values in `amplitudes` at time indices in
    `times`.

    Parameters
    ----------
    channel : str
        Orientation of extended trapezoidal gradient event. Must be one of 'x', 'y' or 'z'.
    amplitudes : numpy.ndarray, optional, default=09
        Values defined at `times` time indices.
    max_grad : float, optional, default=0
        Maximum gradient strength.
    max_slew : float, optional, default=0
        Maximum slew rate.
    system : Opts, optional, default=Opts()
        System limits.
    skip_check : bool, optional, default=False
        Perform check.
    times : numpy.ndarray, optional, default=np.zeros(1)
        Time points at which `amplitudes` defines amplitude values.

    Returns
    -------
    grad : SimpleNamespace
        Extended trapezoid gradient event.

    Raises
    ------
    ValueError
        If invalid `channel` is passed. Must be one of 'x', 'y' or 'z'.
        If all elements in `times` are zero.
        If elements in `times` are not in ascending order or not distinct.
        If all elements in `amplitudes` are zero.
        If first amplitude of a gradient is non-ero and does not connect to a previous block.
    """
    if channel not in ['x', 'y', 'z']:
        raise ValueError(f"Invalid channel. Must be one of 'x', 'y' or 'z'. Passed: {channel}")

    if not np.any(times):
        raise ValueError('At least one of the given times must be non-zero')

    if np.any(np.diff(times) <= 0):
        raise ValueError('Times must be in ascending order and all times must be distinct')

    if not np.any(amplitudes):
        raise ValueError('At least one of the given amplitudes must be non-zero')

    if skip_check is False and times[0] > 0 and amplitudes[0] != 0:
        raise ValueError('If first amplitude of a gradient is non-zero, it must connect to previous block')

    if max_grad <= 0:
        max_grad = system.max_grad

    if max_slew <= 0:
        max_slew = system.max_slew

    waveform = points_to_waveform(times=times, amplitudes=amplitudes, grad_raster_time=system.grad_raster_time)
    grad = make_arbitrary_grad(channel=channel, waveform=waveform, system=system, max_grad=max_grad, max_slew=max_slew,
                               delay=times[0])
    grad.first = amplitudes[0]
    grad.last = amplitudes[-1]

    return grad