{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Exercise 1: SLR Pulse Design\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Welcome! This first exercise will cover the design of SLR pulses for MRI using Python. \n", "\n", "Documentation for all pulse design tools can be found [here](https://sigpy.readthedocs.io/en/latest/mri_rf.html).\n", "\n", "Prior to beginning this exercise (and at the beginning of all additional exercise notebooks) we will need to import the packages we will use:\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%matplotlib notebook\n", "\n", "# typical sigpy and numpy imports\n", "import numpy as np\n", "import sigpy.mri.rf as rf # import for our RF pulse design tools \n", "import sigpy.plot as pl" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Problem 1a: design an inversion pulse" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Large-tip inversion pulses cannot be effectively designed by the small-tip-angle approximation alone, and should instead be designed by iterative methods or the SLR method, which we will use here.\n", "\n", "In SigPy, basic SLR pulses are designed using the [*sigpy.mri.rf.slr.dzrf*](https://sigpy.readthedocs.io/en/latest/generated/sigpy.mri.rf.slr.dzrf.html#sigpy.mri.rf.slr.dzrf) function, modeled after John Pauly's SLR design tools.\n", "\n", "For this example, we want to design an inversion pulse with a sharp edge to invert magnetization(flip the sign of Mz).\n", "\n", "* Using dzrf(), design an inversion pulse with a duration of 128 samples.\n", "* To start, give your pulse 8 zero crossings. \n", "* Use a filter type that concentrates the pulse energy at the end of the pulse.\n", "* Design the pulse to have at maximum 1% ripple in both the passband and the stopband.\n", "* Plot the pulse using pl.LinePlot()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "N = 128 \n", "tb = 4\n", "d1 = 0.01\n", "d2 = 0.01\n", "ptype = 'inv'\n", "ftype = 'ls'" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pulse = rf.slr.dzrf(N, tb, ptype, ftype, d1, d2)\n", "pl.LinePlot(pulse, mode='r', title = 'Real Component')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Problem 1b: simulate the inversion pulse's profile" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Simulate and plot the Mz profile created by this pulse.\n", "\n", "This is done in 2 steps: \n", "* First, find get the a and b Cayley-Klein coefficients that correspond to the RF pulse using [*rf.sim.abrm()*](https://sigpy.readthedocs.io/en/latest/generated/sigpy.mri.rf.sim.abrm.html#sigpy.mri.rf.sim.abrm). You'll want to use spatial locations ranging from -2TB to 2TB. \n", "* Second, you need to make a conversion from the Cayley-Klein parameters to the magnetization response. For an inversion pulse (assuming M<sub>0</sub> is initially oriented entirely along M<sub>Z</sub>), the relationship for M<sub>Z</sub>'s final state is:\n", "\n", "<center>M<sub>Z</sub> = M<sub>0,Z</sub>(1 - 2|$\\beta$|<sup>2</sup>)</center>\n", "\n", "For this example you can just take M<sub>0</sub> = [0,0,1]." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "[a, b] = rf.sim.abrm(pulse, np.arange(-2*tb, 2*tb, 0.01), True)\n", "Mz = 1-2*np.abs(b)**2" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pl.LinePlot(Mz, mode='r')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If done correctly, you should see a profile of mainly 1's (uninverted magnetization) with a segment in the middle with a value of -1 (successfully inverted magnetization)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Problem 1c: alter the time-bandwidth product" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Now, go back and rerun the code above, but change the time-bandwidth product to 4. Note the change in the sharpness of the inversion profile!\n", "* While keeping the time-bandwidth product at four, change the design filter to a least-squares filter *'ls'* and re-plot the magnetization profile.\n", "* Increase the allowable stopband ripple level to 25% while keeping the previous settings, and re-plot the magnetization profile." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Problem 1d: root-flip the inversion pulse" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For the final problem of exercise 1, we will explore the rf.mri.slr.dzrf() source code, and design a root-flipped SLR inversion pulse using what we find there. We can compare this to the standard SLR inversion pulse designed in 1a. *The slides from the educational session discussing the inside workings of dzrf() will be a helpful guide.*\n", "\n", "Root flipping can be performed using the [*rf.slr.root_flip()*](https://sigpy.readthedocs.io/en/latest/generated/sigpy.mri.rf.slr.root_flip.html#sigpy.mri.rf.slr.root_flip) function. This function is used in the following fashion:\n", "\n", "[pulse, bRootFlipped] = rf.slr.root_flip(b, d1, flip, tb)\n", "\n", "To design the root flipped pulse, we will need b (the SLR b polynomial), d1 (the passband ripple level), flip (the flip angle of our pulse in radians) and tb (our time bandwidth product). All of these are knowns, aside from b.\n", "\n", "**Your assignment is to write code to design b by extracting 4 lines of code from the [rf.slr.dzrf() source code](https://sigpy.readthedocs.io/en/latest/_modules/sigpy/mri/rf/slr.html#dzrf). Once this is done, root flip the pulse using root_flip().**\n", "\n", "Step #1: You will want 1 line of code from dzrf() that calculates new filter ripples from the desired magnetization d1 and d2\n", "\n", "Step #2: You will want 2 lines of code from dzrf() that design a minphase b.\n", "\n", "Step #3: You will want to end with a 4th line of code from dzrf() that multiplies bsf by b.\n", "\n", "Step #4: Once you have written these 4 lines of code to design b, use the root_flip() function to root flip the pulse. Plot its magnetization profile using the same code that you used in problem 1b!\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# parameters of the pulse are provided\n", "flip = np.pi # 180 degree inversion\n", "d1 = 0.01 # our 1% ripples in pass and stop bands\n", "d2 = 0.01\n", "tb = 8 # time-bandwidth product of 8" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# code extracted from dzrf():\n", "[bsf, d1, d2] = rf.slr.calc_ripples(ptype, d1, d2)\n", "b = rf.slr.dzmp(N, tb, d1, d2)\n", "b = b[::-1]\n", "b = bsf*b\n", "\n", "# root flipping the pulse, using the b polynomial\n", "[pulse, bRootFlipped] = rf.slr.root_flip(b, d1, flip, tb)\n", "pl.LinePlot(pulse)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "[a, b] = rf.sim.abrm(pulse, np.arange(-2*tb, 2*tb, 0.01), True)\n", "Mz = 1-2*np.abs(b)**2" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "pl.LinePlot(Mz, mode='r')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.3" } }, "nbformat": 4, "nbformat_minor": 2 }