#!/usr/bin/env python
# coding: utf-8
# # Exercise 1: SLR Pulse Design
#
# Welcome! This first exercise will cover the design of SLR pulses for MRI using Python.
#
# Documentation for all pulse design tools can be found [here](https://sigpy.readthedocs.io/en/latest/mri_rf.html).
#
# Prior to beginning this exercise (and at the beginning of all additional exercise notebooks) we will need to import the packages we will use:
#
# In[ ]:
get_ipython().run_line_magic('matplotlib', 'notebook')
# typical sigpy and numpy imports
import numpy as np
import sigpy.mri.rf as rf # import for our RF pulse design tools
import sigpy.plot as pl
# ## Problem 1a: design an inversion pulse
# 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.
#
# 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.
#
# For this example, we want to design an inversion pulse with a sharp edge to invert magnetization(flip the sign of Mz).
#
# * Using dzrf(), design an inversion pulse with a duration of 128 samples.
# * To start, give your pulse 8 zero crossings.
# * Use a filter type that concentrates the pulse energy at the end of the pulse.
# * Design the pulse to have at maximum 1% ripple in both the passband and the stopband.
# * Plot the pulse using pl.LinePlot()
# In[ ]:
N = 128
tb = 4
d1 = 0.01
d2 = 0.01
ptype = 'inv'
ftype = 'ls'
# In[ ]:
pulse = rf.slr.dzrf(N, tb, ptype, ftype, d1, d2)
pl.LinePlot(pulse, mode='r', title = 'Real Component')
# ## Problem 1b: simulate the inversion pulse's profile
# * Simulate and plot the Mz profile created by this pulse.
#
# This is done in 2 steps:
# * 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.
# * Second, you need to make a conversion from the Cayley-Klein parameters to the magnetization response. For an inversion pulse (assuming M0 is initially oriented entirely along MZ), the relationship for MZ's final state is:
#
#
MZ = M0,Z(1 - 2|$\beta$|2)
#
# For this example you can just take M0 = [0,0,1].
# In[ ]:
[a, b] = rf.sim.abrm(pulse, np.arange(-2*tb, 2*tb, 0.01), True)
Mz = 1-2*np.abs(b)**2
# In[ ]:
pl.LinePlot(Mz, mode='r')
# 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).
# # Problem 1c: alter the time-bandwidth product
# * 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!
# * While keeping the time-bandwidth product at four, change the design filter to a least-squares filter *'ls'* and re-plot the magnetization profile.
# * Increase the allowable stopband ripple level to 25% while keeping the previous settings, and re-plot the magnetization profile.
# # Problem 1d: root-flip the inversion pulse
# 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.*
#
# 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:
#
# [pulse, bRootFlipped] = rf.slr.root_flip(b, d1, flip, tb)
#
# 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.
#
# **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().**
#
# Step #1: You will want 1 line of code from dzrf() that calculates new filter ripples from the desired magnetization d1 and d2
#
# Step #2: You will want 2 lines of code from dzrf() that design a minphase b.
#
# Step #3: You will want to end with a 4th line of code from dzrf() that multiplies bsf by b.
#
# 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!
#
# In[ ]:
# parameters of the pulse are provided
flip = np.pi # 180 degree inversion
d1 = 0.01 # our 1% ripples in pass and stop bands
d2 = 0.01
tb = 8 # time-bandwidth product of 8
# In[ ]:
# code extracted from dzrf():
[bsf, d1, d2] = rf.slr.calc_ripples(ptype, d1, d2)
b = rf.slr.dzmp(N, tb, d1, d2)
b = b[::-1]
b = bsf*b
# root flipping the pulse, using the b polynomial
[pulse, bRootFlipped] = rf.slr.root_flip(b, d1, flip, tb)
pl.LinePlot(pulse)
# In[ ]:
[a, b] = rf.sim.abrm(pulse, np.arange(-2*tb, 2*tb, 0.01), True)
Mz = 1-2*np.abs(b)**2
# In[ ]:
pl.LinePlot(Mz, mode='r')
# In[ ]: