{
 "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
}