Beispiel #1
0
 def __init__(self, system=Opts()):
     self.system = system
     # EventLibrary.data is a dict
     self.shape_library = EventLibrary()
     self.rf_library = EventLibrary()
     self.grad_library = EventLibrary()
     self.adc_library = EventLibrary()
     self.delay_library = EventLibrary()
     self.block_events = {}
     self.rf_raster_time = self.system.rf_raster_time
     self.grad_raster_time = self.system.grad_raster_time
Beispiel #2
0
    def compute(self):
        if 'ComputeEvents' in self.widgetEvents(
        ) or 'input' in self.portEvents():
            out_dict = {}
            max_grad = self.getVal('Maximum Gradient')
            max_grad_unit = self.getVal('Maximum Gradient Unit')
            max_slew = self.getVal('Maximum Slew Rate')
            max_slew_unit = self.getVal('Maximum Slew Rate Unit')
            tr = self.getVal('Repetition Time (s)')
            te = self.getVal('Echo Time (s)')
            fov = self.getVal('Field of View')
            Nx = self.getVal('Nx')
            Ny = self.getVal('Ny')
            rise_time = self.getVal('Rise Time (s)')
            rf_dead_time = self.getVal('RF Dead Time (s)')
            adc_dead_time = self.getVal('ADC Dead Time (s)')
            rf_raster_time = self.getVal('RF Raster Time (s)')
            rf_raster_time = rf_raster_time if rf_raster_time != '' else 1e-6
            grad_raster_time = self.getVal('Gradient Raster Time (s)')
            grad_raster_time = grad_raster_time if grad_raster_time != '' else 10e-6

            kwargs_for_opts = {
                'grad_unit': max_grad_unit,
                'slew_unit': max_slew_unit
            }
            keys_for_opts = [
                'max_grad', 'max_slew', 'tr', 'te', 'fov', 'Nx', 'Ny',
                'rise_tme', 'rf_dead_time', 'adc_dead_time', 'rf_raster_time',
                'grad_raster_time'
            ]
            values_for_opts = [
                max_grad, max_slew, tr, te, fov, Nx, Ny, rise_time,
                rf_dead_time, adc_dead_time, rf_raster_time, grad_raster_time
            ]
            for i in range(len(values_for_opts)):
                kwargs_for_opts[keys_for_opts[i]] = float(values_for_opts[i])

            system = Opts(kwargs_for_opts)
            out_dict['system'] = system

            self.setData('output', out_dict)

            # To display the computed info in the TextBox
            self.setAttr('System limits', val=str(system))

            return 0
Beispiel #3
0
def makeadc(kwargs):
    """
    Makes a Holder object for an ADC Event.

    Parameters
    ----------
    kwargs : dict
        Key value mappings of ADC Event parameters_params and values.

    Returns
    -------
    adc : Holder
        ADC Event.
    """

    num_samples = kwargs.get("num_samples", 0)
    system = kwargs.get("system", Opts())
    dwell = kwargs.get("dwell", 0)
    duration = kwargs.get("duration", 0)
    delay = kwargs.get("delay", 0)
    freq_offset = kwargs.get("freq_offset", 0)
    phase_offset = kwargs.get("phase_offset", 0)

    adc = Holder()
    adc.type = 'adc'
    adc.num_samples = num_samples
    adc.dwell = dwell
    adc.delay = delay
    adc.freq_offset = freq_offset
    adc.phase_offset = phase_offset
    adc.dead_time = system.adc_dead_time

    if (dwell == 0 and duration == 0) or (dwell > 0 and duration > 0):
        raise ValueError("Either dwell or duration must be defined, not both")

    if duration > 0:
        # getcontext().prec = 4
        adc.dwell = float(Decimal(duration) / Decimal(num_samples))
    adc.duration = dwell * num_samples if dwell > 0 else 0
    return adc
Beispiel #4
0
def makearbitrarygrad(kwargs):
    """
    Makes a Holder object for an arbitrary gradient Event.

    Parameters
    ----------
    kwargs : dict
        Key value mappings of RF Event parameters_params and values.

    Returns
    -------
    grad : Holder
        Trapezoidal gradient Event configured based on supplied kwargs.
    """

    channel = kwargs.get("channel", "z")
    system = kwargs.get("system", Opts())
    waveform = kwargs.get("waveform")
    max_grad_result = kwargs.get("max_grad", 0)
    max_slew_result = kwargs.get("max_slew", 0)

    max_grad = max_grad_result if max_grad_result > 0 else system.max_grad
    max_slew = max_slew_result if max_slew_result > 0 else system.max_slew

    g = waveform
    slew = (g[0][1:] - g[0][0:-1]) / system.grad_raster_time
    if max(abs(slew)) > max_slew:
        raise ValueError('Slew rate violation {:f}'.format(
            max(abs(slew)) / max_slew * 100))
    if max(abs(g[0])) > max_grad:
        raise ValueError('Gradient amplitude violation {:f}'.format(
            max(abs(g)) / max_grad * 100))
    grad = Holder()
    grad.type = 'grad'
    grad.channel = channel
    grad.waveform = g
    grad.t = np.array([[x * system.grad_raster_time
                        for x in range(len(g[0]))]])
    return grad
from mr_gpi.makeadc import makeadc
from mr_gpi.makeblock import makeblockpulse
from mr_gpi.makedelay import makedelay
from mr_gpi.makesinc import makesincpulse
from mr_gpi.maketrap import maketrapezoid
from mr_gpi.opts import Opts

kwargs_for_opts = {
    "max_grad": 33,
    "grad_unit": "mT/m",
    "max_slew": 110,
    "slew_unit": "T/m/s",
    "rf_dead_time": 10e-6,
    "adc_dead_time": 10e-6
}
system = Opts(kwargs_for_opts)
seq = Sequence(system)

TE, TR = 70e-3, 200e-3
fov = 220e-3
Nx = 64
Ny = 64
slice_thickness = 3e-3
dt_GE = 4e-6

flip = 90 * pi / 180
kwargs_for_sinc = {
    "flip_angle": flip,
    "system": system,
    "duration": 2.5e-3,
    "slice_thickness": slice_thickness,
Beispiel #6
0
    def make_se_epi(self):
        kwargs_for_opts = {"max_grad": self.max_grad, "grad_unit": "mT/m", "max_slew": self.max_slew,
                           "slew_unit": "T/m/s", "rf_dead_time": 10e-6, "adc_dead_time": 10e-6}
        system = Opts(kwargs_for_opts)
        seq = Sequence(system)

        slice_thickness = 3e-3

        flip = 90 * pi / 180
        kwargs_for_sinc = {"flip_angle": flip, "system": system, "duration": 3e-3, "slice_thickness": slice_thickness,
                           "apodization": 0.5, "time_bw_product": 4}
        rf, gz = makesincpulse(kwargs_for_sinc, 2)
        # plt.plot(rf.t[0], rf.signal[0])
        # plt.show()

        delta_k = 1 / self.fov
        k_width = self.Nx * delta_k
        readout_time = 3.2e-4
        kwargs_for_gx = {"channel": 'x', "system": system, "flat_area": k_width, "flat_time": readout_time}
        gx = maketrapezoid(kwargs_for_gx)
        kwargs_for_adc = {"num_samples": self.Nx, "system": system, "duration": gx.flat_time, "delay": gx.rise_time}
        adc = makeadc(kwargs_for_adc)

        pre_time = 8e-4
        kwargs_for_gxpre = {"channel": 'x', "system": system, "area": -gx.area / 2, "duration": pre_time}
        gx_pre = maketrapezoid(kwargs_for_gxpre)
        kwargs_for_gz_reph = {"channel": 'z', "system": system, "area": -gz.area / 2, "duration": pre_time}
        gz_reph = maketrapezoid(kwargs_for_gz_reph)
        kwargs_for_gy_pre = {"channel": 'y', "system": system, "area": -self.Ny / 2 * delta_k, "duration": pre_time}
        gy_pre = maketrapezoid(kwargs_for_gy_pre)

        dur = ceil(2 * sqrt(delta_k / system.max_slew) / 10e-6) * 10e-6
        kwargs_for_gy = {"channel": 'y', "system": system, "area": delta_k, "duration": dur}
        gy = maketrapezoid(kwargs_for_gy)

        flip = 180 * pi / 180
        kwargs_for_sinc = {"flip_angle": flip, "system": system, "duration": 500e-6}
        rf180 = makeblockpulse(kwargs_for_sinc)
        kwargs_for_gz_spoil = {"channel": 'z', "system": system, "area": gz.area * 2, "duration": 3 * pre_time}
        gz_spoil = maketrapezoid(kwargs_for_gz_spoil)

        TE = self.te
        duration_to_center = (self.Nx / 2 + 0.5) * calcduration(gx) + self.Ny / 2 * calcduration(gy)
        delayTE1 = TE / 2 - calcduration(gz) / 2 - pre_time - calcduration(gz_spoil) - calcduration(rf180) / 2
        delayTE2 = TE / 2 - calcduration(rf180) / 2 - calcduration(gz_spoil) - duration_to_center
        delay1 = makedelay(delayTE1)
        delay2 = makedelay(delayTE2)

        seq.add_block(rf, gz)
        seq.add_block(gx_pre, gy_pre, gz_reph)
        seq.add_block(delay1)
        seq.add_block(gz_spoil)
        seq.add_block(rf180)
        seq.add_block(gz_spoil)
        seq.add_block(delay2)
        for i in range(self.Ny):
            seq.add_block(gx, adc)
            seq.add_block(gy)
            gx.amplitude = -gx.amplitude
        seq.add_block(makedelay(1))

        return seq
Beispiel #7
0
def makeblockpulse(kwargs, nargout=1):
    """
    Makes a Holder object for an RF pulse Event.

    Parameters
    ----------
    kwargs : dict
        Key value mappings of RF Event parameters_params and values.
    nargout: int
        Number of output arguments to be returned. Default is 1, only RF Event is returned. Passing any number greater
        than 1 will return the Gz Event along with the RF Event.

    Returns
    -------
    Tuple consisting of:
    rf : Holder
        RF Event configured based on supplied kwargs.
    gz : Holder
        Slice select trapezoidal gradient Event.
    """

    flip_angle = kwargs.get("flip_angle")
    system = kwargs.get("system", Opts())
    duration = kwargs.get("duration", 0)
    freq_offset = kwargs.get("freq_offset", 0)
    phase_offset = kwargs.get("phase_offset", 0)
    time_bw_product = kwargs.get("time_bw_product", 4)
    bandwidth = kwargs.get("bandwidth", 0)
    max_grad = kwargs.get("max_grad", 0)
    max_slew = kwargs.get("max_slew", 0)
    slice_thickness = kwargs.get("slice_thickness", 0)

    if duration == 0:
        if time_bw_product > 0:
            duration = time_bw_product / bandwidth
        elif bandwidth > 0:
            duration = 1 / (4 * bandwidth)
        else:
            raise ValueError('Either bandwidth or duration must be defined')

    BW = 1 / (4 * duration)
    N = round(duration / 1e-6)
    t = [x * system.rf_raster_time for x in range(N)]
    signal = flip_angle / (2 * np.pi) / duration * np.ones(len(t))

    rf = Holder()
    rf.type = 'rf'
    rf.signal = signal
    rf.t = t
    rf.freq_offset = freq_offset
    rf.phase_offset = phase_offset
    rf.dead_time = system.rf_dead_time

    fill_time = 0
    if nargout > 1:
        if slice_thickness < 0:
            raise ValueError('Slice thickness must be provided')

        if max_grad > 0:
            system.max_grad = max_grad
        if max_slew > 0:
            system.max_slew = max_slew

        amplitude = BW / slice_thickness
        area = amplitude * duration
        kwargs_for_trap = {'channel': 'z', 'system': system, 'flat_time': duration, 'flat_area': area}
        gz = maketrapezoid(kwargs_for_trap)

        fill_time = gz.rise_time
        t_fill = np.array([x * 1e-6 for x in range(int(round(fill_time / 1e-6)))])
        rf.t = np.array([t_fill, rf.t + t_fill[-1], t_fill + rf.t[-1] + t_fill[-1]])
        rf.signal = np.array([np.zeros(t_fill.size), rf.signal, np.zeros(t_fill.size)])

    if fill_time < rf.dead_time:
        fill_time = rf.dead_time - fill_time
        t_fill = np.array([x * 1e-6 for x in range(int(round(fill_time / 1e-6)))])
        rf.t = np.insert(rf.t, 0, t_fill) + t_fill[-1]
        rf.t = np.reshape(rf.t, (1, len(rf.t)))
        rf.signal = np.insert(rf.signal, 0, np.zeros(t_fill.size))
        rf.signal = np.reshape(rf.signal, (1, len(rf.signal)))

    if nargout > 1:
        return rf, gz
    else:
        return rf
Beispiel #8
0
def makearbitraryrf(kwargs, nargout=1):
    """
    Makes a Holder object for an arbitrary RF pulse Event.

    Parameters
    ----------
    kwargs : dict
        Key value mappings of RF Event parameters_params and values.
    nargout: int
        Number of output arguments to be returned. Default is 1, only RF Event is returned. Passing any number greater
        than 1 will return the Gz Event along with the RF Event.

    Returns
    -------
    rf : Holder
        RF Event configured based on supplied kwargs.
    gz : Holder
        Slice select trapezoidal gradient Event.
    """

    flip_angle = kwargs.get("flip_angle")
    system = kwargs.get("system", Opts())
    signal = kwargs.get("signal", 0)
    freq_offset = kwargs.get("freq_offset", 0)
    phase_offset = kwargs.get("phase_offset", 0)
    time_bw_product = kwargs.get("time_bw_product", 0)
    bandwidth = kwargs.get("bandwidth", 0)
    max_grad = kwargs.get("max_grad", 0)
    max_slew = kwargs.get("max_slew", 0)
    slice_thickness = kwargs.get("slice_thickness", 0)

    signal = signal / sum(
        signal * system.rf_raster_time) * flip_angle / (2 * pi)
    N = len(signal)
    duration = N * system.rf_raster_time
    t = [x * system.rfRasterTime for x in range(0, N)]

    rf = Holder()
    rf.type = 'rf'
    rf.signal = signal
    rf.t = t
    rf.freq_offset = freq_offset
    rf.phase_offset = phase_offset
    rf.rf_dead_time = system.rf_dead_time

    if nargout > 1:
        if slice_thickness <= 0:
            raise ValueError('Slice thickness must be provided')
        if bandwidth <= 0:
            raise ValueError('Bandwdith of pulse must be provided')

        system.maxgrad = max_grad if max_grad > 0 else system.maxgrad
        system.max_slew = max_slew if max_slew > 0 else system.max_slew

        BW = bandwidth
        if time_bw_product > 0:
            BW = time_bw_product / duration

        amplitude = BW / slice_thickness
        area = amplitude * duration
        kwargs_for_trap = {
            "channel": 'z',
            "system": system,
            "flat_time": duration,
            "flat_area": area
        }
        gz = maketrapezoid(**kwargs_for_trap)

        t_fill = [x * 1e-6 for x in range(1, round(gz.riseTime / 1e-6))]
        rf.t = [t_fill, rf.t + t_fill[-1], t_fill + rf.t[-1] + t_fill[-1]]
        rf.signal = [np.zeros(len(t_fill)), rf.signal, np.zeros(len(t_fill))]

    return rf, gz
Beispiel #9
0
def makesincpulse(kwargs, nargout=1):
    """
    Makes a Holder object for an RF pulse Event.

    Parameters
    ----------
    kwargs : dict
        Key value mappings of RF Event parameters_params and values.
    nargout: int
        Number of output arguments to be returned. Default is 1, only RF Event is returned. Passing any number greater
        than 1 will return the Gz Event along with the RF Event.

    Returns
    -------
    Tuple consisting of:
    rf : Holder
        RF Event configured based on supplied kwargs.
    gz : Holder
        Slice select trapezoidal gradient Event.
    """

    flip_angle = kwargs.get("flip_angle")
    system = kwargs.get("system", Opts())
    duration = kwargs.get("duration", 0)
    freq_offset = kwargs.get("freq_offset", 0)
    phase_offset = kwargs.get("phase_offset", 0)
    time_bw_product = kwargs.get("time_bw_product", 4)
    apodization = kwargs.get("apodization", 0)
    max_grad = kwargs.get("max_grad", 0)
    max_slew = kwargs.get("max_slew", 0)
    slice_thickness = kwargs.get("slice_thickness", 0)

    BW = time_bw_product / duration
    alpha = apodization
    N = int(round(duration / 1e-6))
    t = np.zeros((1, N))
    for x in range(1, N + 1):
        t[0][x - 1] = x * system.rf_raster_time
    tt = t - (duration / 2)
    window = np.zeros((1, tt.shape[1]))
    for x in range(0, tt.shape[1]):
        window[0][x] = 1.0 - alpha + alpha * np.cos(
            2 * np.pi * tt[0][x] / duration)
    signal = np.multiply(window, np.sinc(BW * tt))
    flip = np.sum(signal) * system.rf_raster_time * 2 * np.pi
    signal = signal * flip_angle / flip

    rf = Holder()
    rf.type = 'rf'
    rf.signal = signal
    rf.t = t
    rf.freq_offset = freq_offset
    rf.phase_offset = phase_offset
    rf.dead_time = system.rf_dead_time

    fill_time = 0
    if nargout > 1:
        if slice_thickness == 0:
            raise ValueError('Slice thickness must be provided')

        system.max_grad = max_grad if max_grad > 0 else system.max_grad
        system.max_slew = max_slew if max_slew > 0 else system.max_slew

        amplitude = BW / slice_thickness
        area = amplitude * duration
        kwargs_for_trap = {
            "channel": 'z',
            "system": system,
            "flat_time": duration,
            "flat_area": area
        }
        gz = maketrapezoid(kwargs_for_trap)

        fill_time = gz.rise_time
        nfill_time = int(round(fill_time / 1e-6))
        t_fill = np.zeros((1, nfill_time))
        for x in range(1, nfill_time + 1):
            t_fill[0][x - 1] = x * 1e-6
        temp = np.concatenate((t_fill[0], rf.t[0] + t_fill[0][-1]))
        temp = temp.reshape((1, len(temp)))
        rf.t = np.resize(rf.t, temp.shape)
        rf.t[0] = temp
        z = np.zeros((1, t_fill.shape[1]))
        temp2 = np.concatenate((z[0], rf.signal[0]))
        temp2 = temp2.reshape((1, len(temp2)))
        rf.signal = np.resize(rf.signal, temp2.shape)
        rf.signal[0] = temp2

    if fill_time < rf.dead_time:
        fill_time = rf.dead_time - fill_time
        t_fill = np.array(
            [x * 1e-6 for x in range(int(round(fill_time / 1e-6)))])
        rf.t = np.insert(rf.t, 0, t_fill) + t_fill[-1]
        rf.t = np.reshape(rf.t, (1, len(rf.t)))
        rf.signal = np.insert(rf.signal, 0, (np.zeros(t_fill.size)))
        rf.signal = np.reshape(rf.signal, (1, len(rf.signal)))

    # Following 2 lines of code are workarounds for numpy returning 3.14... for np.angle(-0.00...)
    negative_zero_indices = np.where(rf.signal == -0.0)
    rf.signal[negative_zero_indices] = 0

    if nargout > 1:
        return rf, gz
    else:
        return rf
Beispiel #10
0
def maketrapezoid(kwargs):
    """
    Makes a Holder object for an trapezoidal gradient Event.

    Parameters
    ----------
    kwargs : dict
        Key value mappings of trapezoidal gradient Event parameters_params and values.

    Returns
    -------
    grad : Holder
        Trapezoidal gradient Event configured based on supplied kwargs.
    """

    channel = kwargs.get("channel", "z")
    system = kwargs.get("system", Opts())
    duration = kwargs.get("duration", 0)
    area_result = kwargs.get("area", -1)
    flat_time_result = kwargs.get("flat_time", 0)
    flat_area_result = kwargs.get("flat_area", -1)
    amplitude_result = kwargs.get("amplitude", -1)
    max_grad = kwargs.get("max_grad", 0)
    max_slew = kwargs.get("max_slew", 0)
    rise_time = kwargs.get("rise_time", 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
    rise_time = rise_time if rise_time > 0 else system.rise_time

    if area_result == -1 and flat_area_result == -1 and amplitude_result == -1:
        raise ValueError('Must supply either '
                         'area'
                         ', '
                         'flat_area'
                         ' or '
                         'amplitude'
                         '')

    if flat_time_result > 0:
        amplitude = amplitude_result if (amplitude_result != -1) else (
            flat_area_result / flat_time_result)
        if rise_time == 0:
            rise_time = abs(amplitude) / max_slew
            rise_time = ceil(
                rise_time / system.grad_raster_time) * system.grad_raster_time
        fall_time, flat_time = rise_time, flat_time_result
    elif duration > 0:
        if amplitude_result != -1:
            amplitude = amplitude_result
        else:
            if rise_time == 0:
                dC = 1 / abs(2 * max_slew) + 1 / abs(2 * max_slew)
                amplitude = (duration - sqrt(
                    pow(duration, 2) - 4 * abs(area_result) * dC)) / (2 * dC)
            else:
                amplitude = area_result / (duration - rise_time)

        if rise_time == 0:
            rise_time = ceil(amplitude / max_slew /
                             system.grad_raster_time) * system.grad_raster_time

        fall_time = rise_time
        flat_time = (duration - rise_time - fall_time)

        amplitude = area_result / (rise_time / 2 + fall_time / 2 + flat_time
                                   ) if amplitude_result == -1 else amplitude
    else:
        raise ValueError('Must supply a duration')

    if abs(amplitude) > max_grad:
        raise ValueError("Amplitude violation")

    grad = Holder()
    grad.type = "trap"
    grad.channel = channel
    grad.amplitude = amplitude
    grad.rise_time = rise_time
    grad.flat_time = flat_time
    grad.fall_time = fall_time
    grad.area = amplitude * (flat_time + rise_time / 2 + fall_time / 2)
    grad.flat_area = amplitude * flat_time

    return grad
Beispiel #11
0
 def compute(self):
     if 'File location' in self.widgetEvents():
         file_location = self.getVal('File location')
         seq = Sequence(Opts())
         seq.read(file_location)
         self.setData('output', {"seq": seq})