├── .gitattributes ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── docs ├── _config.yml ├── alpha.png ├── c++.png ├── c.png ├── demoicon.gif ├── down.png ├── doxysearch.php ├── fortran.png ├── hp.png ├── index.html ├── left.png ├── linux.png ├── m2html.css ├── matlabicon.gif ├── menu.html ├── mex.png ├── mrf │ ├── Dictionary_Matching │ │ ├── Function │ │ │ ├── MRF_Dict_Matching.html │ │ │ └── menu.html │ │ ├── MRF_dict_matching_demo.html │ │ └── menu.html │ ├── EPG_Dict_Sim │ │ ├── Function │ │ │ ├── EPG_custom.html │ │ │ ├── EPGsim_MRF.html │ │ │ ├── Var_TE.html │ │ │ ├── display_epg.html │ │ │ ├── findEchoes.html │ │ │ ├── menu.html │ │ │ ├── relax.html │ │ │ ├── rf_rotation.html │ │ │ └── shift_grad.html │ │ ├── dict_sim_MRF_demo.html │ │ └── menu.html │ ├── Image_Reconstruction │ │ ├── Function │ │ │ ├── Complex_Chan_Combining.html │ │ │ ├── MRF_recon.html │ │ │ ├── dat2mat_nonCart.html │ │ │ ├── mapVBVDVE.html │ │ │ ├── menu.html │ │ │ ├── read_twix_hdr.html │ │ │ ├── twix_map_obj.html │ │ │ └── twix_map_objVE.html │ │ ├── MRF_recon_demo.html │ │ └── menu.html │ ├── ROI_analysis_tool │ │ ├── Function │ │ │ ├── Circle_Analysis.html │ │ │ ├── NIST_ROI_ana.html │ │ │ ├── gen_NIST_sphere_loc.html │ │ │ ├── gen_NIST_std_par.html │ │ │ └── menu.html │ │ ├── ROI_ana_demo.html │ │ └── menu.html │ ├── Sequence_Design │ │ ├── Function │ │ │ ├── design_spiral_pulseq.html │ │ │ ├── gen_MRF_sequence_pulseq.html │ │ │ ├── gradient_lobe.html │ │ │ ├── gyrogamma.html │ │ │ ├── menu.html │ │ │ ├── vds.html │ │ │ └── voronoi_area.html │ │ ├── menu.html │ │ └── sequence_design_demo.html │ ├── demo_MRF.html │ └── menu.html ├── pcode.png ├── right.png ├── sgi.png ├── simulinkicon.gif ├── solaris.png ├── up.png └── windows.png ├── images ├── Brain_rec_all.jpg ├── MRF_FA_all.png ├── MRF_TR_all.png ├── Seq file.PNG ├── Sequence plot.png ├── Sliding window.png ├── Spiral plot.png ├── T2_map_sphere_1.png ├── T2_map_with_ROI.png ├── comparison.png ├── dict_evo.png ├── select raw data.png └── select traj data.png └── mrf ├── Dictionary_Matching ├── Data │ └── dict_example.mat ├── Function │ └── MRF_Dict_Matching.m └── MRF_dict_matching_demo.m ├── EPG_Dict_Sim ├── Data │ └── TR_TE_FA.mat ├── Function │ ├── EPG_custom.m │ ├── EPGsim_MRF.m │ ├── display_epg.m │ ├── findEchoes.m │ ├── gen_MRF_dict.m │ ├── relax.m │ ├── rf_rotation.m │ └── shift_grad.m └── gen_MRF_dict_demo.m ├── Image_Reconstruction ├── Data │ └── K_Traj4rec.mat ├── Function │ ├── Complex_Chan_Combining.m │ ├── MRF_recon.m │ ├── dat2mat_nonCart.m │ ├── mapVBVDVE.m │ ├── read_twix_hdr.m │ ├── twix_map_obj.m │ └── twix_map_objVE.m └── MRF_recon_demo.m ├── ROI_analysis_tool ├── Data │ ├── T1_map.mat │ ├── T1_map_rot45.mat │ ├── T2_map.mat │ └── T2_map_rot30.mat ├── Function │ ├── Circle_Analysis.m │ ├── NIST_ROI_ana.m │ ├── gen_NIST_sphere_loc.m │ └── gen_NIST_std_par.m └── ROI_ana_demo.m ├── Sequence_Design ├── Data │ └── method_orig.mat ├── Function │ ├── design_spiral_pulseq.m │ ├── gen_MRF_sequence_pulseq.m │ ├── gradient_lobe.m │ ├── gyrogamma.m │ ├── make_HSI.m │ ├── vds.m │ └── voronoi_area.m └── sequence_design_demo.m └── demo_MRF.m /.gitattributes: -------------------------------------------------------------------------------- 1 | *.dat filter=lfs diff=lfs merge=lfs -text 2 | *.gif filter=lfs diff=lfs merge=lfs -text 3 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at imr.framework2018@gmail.com . All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Open Source MRF Package 2 | Thank you for taking the time to contribute to the package! 3 | 4 | The following is a set of guidelines for contributing to Open Source MRF Package. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request. 5 | 6 | ## Table of contents 7 | 1. [Contributing](#contributing-to-the-software) 8 | 2. [Reporting Issues](#reporting-issues) 9 | 3. [Seeking Support](#seeking-support) 10 | 11 | ## Contributing to the Software 12 | 13 | If you would like to contribute to Open Source MRF Package, please fork and make a pull request with adequate documentation of functionality. In addition, please take a look at the Code of Conduct and documentation guide below: 14 | 15 | **Code of Conduct** 16 | 17 | This project and everyone participating in it is governed by the [Code of Conduct](https://github.com/imr-framework/mrf/blob/master/CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code. Please report unacceptable behavior to imr.framework2018@github.com. 18 | 19 | **Source code header** 20 | 21 | Insert and fill out the following header comments at the top of every script in your source code: 22 | ``` 23 | Institution : (your university/research facility) 24 | Version : 1.0.0 25 | ``` 26 | Note that "Version" refers to the Open Source MRF Package release you developed your code on. You can add more fields if needed. 27 | 28 | **Documenting source code** 29 | 30 | Please add a top-level description of code functionality in each script. In addition, document all inputs and outputs and add a line of description for each input and output. 31 | 32 | ## Reporting Issues 33 | Please report issues in Github Issues, following the given format for either "Bug Report" or "Feature Request". 34 | 35 | ## Seeking Support 36 | For support in installing and using Open Source MRF Package, please feel free to either use Github Issues. 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 |

Open Source Magnetic Resonance Fingerprinting Package (OMEGA)


5 | 6 | Open Source MRF is a Matlab based software package which enables vendor neutral, fast prototyping of magnetic resonance fingerprinting using Pulseq. It is supported by open-soure standards. 7 | 8 | Magnetic resonance fingerprinting is a framework that allows for simultaneous quantification of tissue properties and hence is a significant tool to understand multi-vendor multi-site variability. However, a vendor-neutral, open soure implementation of MRF has not been developed to the best of our knowlegde. In this work, we develop the package to enable comparisons between two sites with two vendors. 9 | 10 | Open Source MRF consists of five modules. Sequence design, image reconstruction, dictionary simulation, dictionary matching, and ROI analysis. 11 | 12 | **Please note:** You need to install Pulseq and Michigan Image Reconstruction Toolbox (MIRT) in your system for the package to run. Visit [Pulseq](http://pulseq.github.io/) and [MIRT](https://web.eecs.umich.edu/~fessler/code/) for more information. 13 | 14 | This package contains five different parts. To use the package, please pull the complete mrf repository. 15 | 16 | ## How to use the package 17 | #### Generate MRF Sequence 18 | 1. Call **Spiral_Design/Function/gen_MRF_sequence_pulseq.m**. The function returns parameters of the sequence that are used in other parts of the package 19 | 2. A MRF sequence based on Jiang's paper [1] is implemented using Pulseq framework. 20 | 3. The user should be able play the generated .seq file on a scanner with Pulseq interpreter installed. This sequence has been verified on a scanner by the author. 21 | 22 | #### Image Reconstruction 23 | 1. Call **Image_Reconstruction/Function/MRF_recon.m** 24 | 2. The script lets user select raw data file (.dat) from scanner and trajectory file (.mat) and reconstruct the image using sliding window method and complex channel combination [2]. 25 | 26 | #### EPG Dictionary Simulation 27 | 1. Call **EPG_dict_sim/Function/gen_MRF_dict.m**. 28 | 2. A dictionary is simulated based on the T1/T2 ranges using Extend Phase Graph(EPG) [3] method. 29 | 30 | #### Dictionary Matching 31 | 1. Call **Dictionary_Matching/Function/MRF_Dic_Matching.m**. 32 | 2. The script uses vector dot product to find the best matching dictionary entry and retrieves all parameters for that entry. 33 | 34 | #### ROI Analysis Tool 35 | 1. Call **ROI_analysis_tool/Function/NIST_ROI_ana.m** . 36 | 2. The function takes in the parameter maps of ISMRM/NIST phantom and return locations of spheres in correct orders. 37 | 38 | ## Demo 39 | To test the package, a demo script can be found at **mrf/demo_MRF.m**. This script generates a sequence, then read a sample data, reconstruct the data. A dictionary is generated and dictionary matching is performed. Then ROI analysis is done to provide T1 and T2 values for each spheres. 40 | 41 | In addition to the overall demo script, each module can be tested by itself. The demo script can be located under each module, which will help verify the correctness of the module. 42 | 43 | ## Reference 44 | [1] Jiang Y, Ma D, Seiberlich N, Gulani V, Griswold M. MR fingerprinting using fast imaging with steady state precession (FISP) with spiral readout. Magn Reson Med. 2015;74(6):spcone-spcone. doi:10.1002/mrm.26048 45 | 46 | [2] Roemer P, Edelstein W, Hayes C, Souza S, Mueller O. The NMR phased array. Magn Reson Med. 1990;16(2):192-225. doi:10.1002/mrm.1910160203 47 | 48 | [3] Weigel M. Extended phase graphs: Dephasing, RF pulses, and echoes - pure and simple. Journal of Magnetic Resonance Imaging. 2014;41(2):266-295. doi:10.1002/jmri.24619 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-minimal -------------------------------------------------------------------------------- /docs/alpha.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/docs/alpha.png -------------------------------------------------------------------------------- /docs/c++.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/docs/c++.png -------------------------------------------------------------------------------- /docs/c.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/docs/c.png -------------------------------------------------------------------------------- /docs/demoicon.gif: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:6822a1b747689e6a7a8cda7dafe52858bcc8e997c237a49eae581eae4d8e9a4c 3 | size 214 4 | -------------------------------------------------------------------------------- /docs/down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/docs/down.png -------------------------------------------------------------------------------- /docs/doxysearch.php: -------------------------------------------------------------------------------- 1 | $word, 70 | "match"=>$w, 71 | "index"=>$statIdx, 72 | "full"=>strlen($w)==strlen($word), 73 | "docs"=>array() 74 | ); 75 | } 76 | $w = readString($file); 77 | } 78 | $totalFreq=0; 79 | for ($count=$start;$count$idx,"freq"=>$freq,"rank"=>0.0); 91 | $totalFreq+=$freq; 92 | if ($statInfo["full"]) $totalfreq+=$freq; 93 | } 94 | // read name an url info for the doc 95 | for ($i=0;$i<$numDocs;$i++) 96 | { 97 | fseek($file,$docInfo[$i]["idx"]); 98 | $docInfo[$i]["name"]=readString($file); 99 | $docInfo[$i]["url"]=readString($file); 100 | } 101 | $statInfo["docs"]=$docInfo; 102 | } 103 | for ($count=$start;$count$key, 136 | "name"=>$di["name"], 137 | "rank"=>$rank 138 | ); 139 | } 140 | $docs[$key]["words"][] = array( 141 | "word"=>$wordInfo["word"], 142 | "match"=>$wordInfo["match"], 143 | "freq"=>$di["freq"] 144 | ); 145 | } 146 | } 147 | return $docs; 148 | } 149 | 150 | function normalize_ranking(&$docs) 151 | { 152 | $maxRank = 0.0000001; 153 | // compute maximal rank 154 | foreach ($docs as $doc) 155 | { 156 | if ($doc["rank"]>$maxRank) 157 | { 158 | $maxRank=$doc["rank"]; 159 | } 160 | } 161 | reset($docs); 162 | // normalize rankings 163 | while (list ($key, $val) = each ($docs)) 164 | { 165 | $docs[$key]["rank"]*=100/$maxRank; 166 | } 167 | } 168 | 169 | function filter_results($docs,&$requiredWords,&$forbiddenWords) 170 | { 171 | $filteredDocs=array(); 172 | while (list ($key, $val) = each ($docs)) 173 | { 174 | $words = &$docs[$key]["words"]; 175 | $copy=1; // copy entry by default 176 | if (sizeof($requiredWords)>0) 177 | { 178 | foreach ($requiredWords as $reqWord) 179 | { 180 | $found=0; 181 | foreach ($words as $wordInfo) 182 | { 183 | $found = $wordInfo["word"]==$reqWord; 184 | if ($found) break; 185 | } 186 | if (!$found) 187 | { 188 | $copy=0; // document contains none of the required words 189 | break; 190 | } 191 | } 192 | } 193 | if (sizeof($forbiddenWords)>0) 194 | { 195 | foreach ($words as $wordInfo) 196 | { 197 | if (in_array($wordInfo["word"],$forbiddenWords)) 198 | { 199 | $copy=0; // document contains a forbidden word 200 | break; 201 | } 202 | } 203 | } 204 | if ($copy) $filteredDocs[$key]=$docs[$key]; 205 | } 206 | return $filteredDocs; 207 | } 208 | 209 | function compare_rank($a,$b) 210 | { 211 | return ($a["rank"]>$b["rank"]) ? -1 : 1; 212 | } 213 | 214 | function sort_results($docs,&$sorted) 215 | { 216 | $sorted = $docs; 217 | usort($sorted,"compare_rank"); 218 | return $sorted; 219 | } 220 | 221 | function report_results(&$docs) 222 | { 223 | echo "\n"; 224 | echo " \n"; 225 | echo " \n"; 226 | echo " \n"; 227 | $numDocs = sizeof($docs); 228 | if ($numDocs==0) 229 | { 230 | echo " \n"; 231 | echo " \n"; 232 | echo " \n"; 233 | } 234 | else 235 | { 236 | echo " \n"; 237 | echo " \n"; 240 | echo " \n"; 241 | $num=1; 242 | foreach ($docs as $doc) 243 | { 244 | echo " \n"; 245 | echo " "; 246 | echo "\n"; 247 | echo " \n"; 248 | echo " \n"; 256 | echo " \n"; 257 | $num++; 258 | } 259 | } 260 | echo "

Search Results

".matches_text(0)."
".matches_text($numDocs); 238 | echo "\n"; 239 | echo "
$num.".$doc["name"]."
Matches: "; 249 | foreach ($doc["words"] as $wordInfo) 250 | { 251 | $word = $wordInfo["word"]; 252 | $matchRight = substr($wordInfo["match"],strlen($word)); 253 | echo "$word$matchRight(".$wordInfo["freq"].") "; 254 | } 255 | echo "
\n"; 261 | } 262 | 263 | function matches_text($num) 264 | { 265 | if ($num==0) 266 | { 267 | return 'Sorry, no documents matching your query.'; 268 | } 269 | else if ($num==1) 270 | { 271 | return 'Found 1 document matching your query.'; 272 | } 273 | else // $num>1 274 | { 275 | return 'Found '.$num.' documents matching your query. Showing best matches first.'; 276 | } 277 | } 278 | 279 | function main($idxfile) 280 | { 281 | if(strcmp('4.1.0', phpversion()) > 0) 282 | { 283 | die("Error: PHP version 4.1.0 or above required!"); 284 | } 285 | if (!($file=fopen($idxfile,"rb"))) 286 | { 287 | die("Error: Search index file could NOT be opened!"); 288 | } 289 | if (readHeader($file)!="DOXS") 290 | { 291 | die("Error: Header of index file is invalid!"); 292 | } 293 | $query=""; 294 | if (array_key_exists("query", $_GET)) 295 | { 296 | $query=$_GET["query"]; 297 | } 298 | $results = array(); 299 | $requiredWords = array(); 300 | $forbiddenWords = array(); 301 | $foundWords = array(); 302 | $word=strtolower(strtok($query," ")); 303 | while ($word) // for each word in the search query 304 | { 305 | if (($word{0}=='+')) { $word=substr($word,1); $requiredWords[]=$word; } 306 | if (($word{0}=='-')) { $word=substr($word,1); $forbiddenWords[]=$word; } 307 | if (!in_array($word,$foundWords)) 308 | { 309 | $foundWords[]=$word; 310 | search($file,$word,$results); 311 | } 312 | $word=strtolower(strtok(" ")); 313 | } 314 | $docs = array(); 315 | combine_results($results,$docs); 316 | // filter out documents with forbidden word or that do not contain 317 | // required words 318 | $filteredDocs = filter_results($docs,$requiredWords,$forbiddenWords); 319 | // normalize rankings so they are in the range [0-100] 320 | normalize_ranking($filteredDocs); 321 | // sort the results based on rank 322 | $sorted = array(); 323 | sort_results($filteredDocs,$sorted); 324 | // report results to the user 325 | report_results($sorted); 326 | fclose($file); 327 | } 328 | 329 | ?> 330 | -------------------------------------------------------------------------------- /docs/fortran.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/docs/fortran.png -------------------------------------------------------------------------------- /docs/hp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/docs/hp.png -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Matlab Documentation by M2HTML 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | This is a Matlab Documentation by M2HTML.
19 | Go to menu.html for the documentation of all 20 | the Matlab functions. 21 |
22 | 23 | -------------------------------------------------------------------------------- /docs/left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/docs/left.png -------------------------------------------------------------------------------- /docs/linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/docs/linux.png -------------------------------------------------------------------------------- /docs/m2html.css: -------------------------------------------------------------------------------- 1 | body { 2 | background: white; 3 | color: black; 4 | font-family: arial,sans-serif; 5 | margin: 0; 6 | padding: 1ex; 7 | } 8 | 9 | div.fragment { 10 | width: 98%; 11 | border: 1px solid #CCCCCC; 12 | background-color: #f5f5f5; 13 | padding-left: 4px; 14 | margin: 4px; 15 | } 16 | 17 | div.box { 18 | width: 98%; 19 | background-color: #f5f5f5; 20 | border: 1px solid #CCCCCC; 21 | color: black; 22 | padding: 4px; 23 | } 24 | 25 | .comment { 26 | color: #228B22; 27 | } 28 | .string { 29 | color: #B20000; 30 | } 31 | .keyword { 32 | color: #0000FF; 33 | } 34 | 35 | .keywordtype { color: #604020; } 36 | .keywordflow { color: #e08000; } 37 | .preprocessor { color: #806020; } 38 | .stringliteral { color: #002080; } 39 | .charliteral { color: #008080; } 40 | 41 | a { 42 | text-decoration: none; 43 | } 44 | 45 | a:hover { 46 | background-color: #006699; 47 | color:#FFFFFF; 48 | } 49 | 50 | a.code { 51 | font-weight: normal; 52 | color: #A020F0; 53 | } 54 | 55 | a.code:hover { 56 | background-color: #FF0000; 57 | color: #FFFFFF; 58 | } 59 | 60 | h1 { 61 | background: transparent; 62 | color: #006699; 63 | font-size: x-large; 64 | text-align: center; 65 | } 66 | 67 | h2 { 68 | background: transparent; 69 | color: #006699; 70 | font-size: large; 71 | } 72 | 73 | address { 74 | font-size:small; 75 | } 76 | 77 | form.search { 78 | margin-bottom: 0px; 79 | margin-top: 0px; 80 | } 81 | input.search { 82 | font-size: 75%; 83 | color: #000080; 84 | font-weight: normal; 85 | background-color: #eeeeff; 86 | } 87 | 88 | li { 89 | padding-left:5px; 90 | } -------------------------------------------------------------------------------- /docs/matlabicon.gif: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:5c56108ee7bc642fe192e6622dc25721e13b1df13693027f9243e8690243d15b 3 | size 574 4 | -------------------------------------------------------------------------------- /docs/menu.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Matlab Index 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |

Matlab Index

16 |

Matlab Directories

17 | 19 | 20 | 21 |
Generated by m2html © 2005
22 | 23 | -------------------------------------------------------------------------------- /docs/mex.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/docs/mex.png -------------------------------------------------------------------------------- /docs/mrf/Dictionary_Matching/Function/MRF_Dict_Matching.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Description of MRF_Dict_Matching 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 |

MRF_Dict_Matching 20 |

21 | 22 |

PURPOSE ^

23 |
% This function is a re-implementation based on P. Gomez's code
24 | 25 |

SYNOPSIS ^

26 |
function out = MRF_Dict_Matching(dict, data)
27 | 28 |

DESCRIPTION ^

29 |
% This function is a re-implementation based on P. Gomez's code
 30 | This script uses vector dot product to find the most similar entry inside
 31 | a dictionary and retrieve the parameters from that dictionary.
 32 |  INPUT
 33 |   dict  Dictionary file
 34 |   data  Reconstructed data file
 35 |  
 36 |  OUTPUT
 37 |    out  An output structure that contains T1 and T2 maps 
 38 | 
 39 |  7/2019 Enlin Qian
 40 |  # Copyright of the Board of Trustees of Columbia University in the City of New York
 41 | % Reshape data
42 | 43 | 44 |

CROSS-REFERENCE INFORMATION ^

45 | This function calls: 46 | 48 | This function is called by: 49 | 51 | 52 | 53 | 54 | 55 |

SOURCE CODE ^

56 |
0001 function out = MRF_Dict_Matching(dict, data)
 57 | 0002 %% This function is a re-implementation based on P. Gomez's code
 58 | 0003 %This script uses vector dot product to find the most similar entry inside
 59 | 0004 %a dictionary and retrieve the parameters from that dictionary.
 60 | 0005 % INPUT
 61 | 0006 %  dict  Dictionary file
 62 | 0007 %  data  Reconstructed data file
 63 | 0008 %
 64 | 0009 % OUTPUT
 65 | 0010 %   out  An output structure that contains T1 and T2 maps
 66 | 0011 %
 67 | 0012 % 7/2019 Enlin Qian
 68 | 0013 % # Copyright of the Board of Trustees of Columbia University in the City of New York
 69 | 0014 %% Reshape data
 70 | 0015 iz = 1;
 71 | 0016 [ix,iy,T] = size(data);
 72 | 0017 datadims = [ix,iy,T];
 73 | 0018 N = ix*iy*iz;
 74 | 0019 x = reshape(data,[N,T]);
 75 | 0020 mask = ones(datadims(1:end-1)) > 0;
 76 | 0021 x = single(x(mask>0,:));
 77 | 0022 
 78 | 0023 %% Reading in dictionary and checking fields in dictionary
 79 | 0024 D = dict.D;
 80 | 0025 if isfield(dict,'normD'); normD = dict.normD; end
 81 | 0026 if ~isfield(dict,'lut')
 82 | 0027     error('dict.lut required for parameter estimation');
 83 | 0028 end
 84 | 0029 if ~exist('normD','var')
 85 | 0030     warning('normD not found, normalizing dictionary \n');
 86 | 0031     normD = zeros(1,size(D,1));
 87 | 0032     for l = 1:size(D,1)
 88 | 0033         normD(l)=norm(D(l,:));
 89 | 0034         D(l,:)=D(l,:)/normD(l);
 90 | 0035     end
 91 | 0036     D(isnan(D))=0;
 92 | 0037 end
 93 | 0038 
 94 | 0039 for n1 = 1:size(D,1)
 95 | 0040     temp1 = D(n1,:);
 96 | 0041     temp2 = x(n1,:);
 97 | 0042     temp1 = temp1./max(temp1(:));
 98 | 0043     temp2 = temp2./max(temp2(:));
 99 | 0044     D(n1,:) = temp1;
100 | 0045     x(n1,:) = temp2;
101 | 0046 end
102 | 0047 
103 | 0048 %% Setting up parameters for dic matching
104 | 0049 S = whos('x');
105 | 0050 dataBytes = S.bytes;
106 | 0051 mem = memory;
107 | 0052 percentageOfUse = 0.6;
108 | 0053 memPercentage = mem.MemAvailableAllArrays * percentageOfUse;
109 | 0054 blockSize = memPercentage/dataBytes;
110 | 0055 
111 | 0056 %% Dictionary Matching
112 | 0057 blockSize = min(max(floor(blockSize/size(D,1)),1),size(x,1));
113 | 0058 iter = ceil(size(x,1)/blockSize);
114 | 0059 mt = zeros(size(x,1),1);
115 | 0060 dm = zeros(size(x,1),1);
116 | 0061 pd = zeros(size(x,1),1);
117 | 0062 X = zeros(size(x));
118 | 0063 fprintf('Matching data \n');
119 | 0064 maxDict =  max(dict.D,[],2);
120 | 0065 dtemp = abs(dict.D./maxDict);
121 | 0066 for i = 1: iter
122 | 0067     if(mod(i,1000) ==0)
123 | 0068         disp(i)
124 | 0069     end
125 | 0070     if i<iter
126 | 0071         cind = (i-1)*blockSize+1:i*blockSize;
127 | 0072     else
128 | 0073         cind = (i-1)*blockSize+1:size(x,1);
129 | 0074     end
130 | 0075     xtemp = x(cind,:)./max(abs(x(cind,:)));
131 | 0076     ip = zeros(1,size(D,1));
132 | 0077     for m = 1:size(D,1)
133 | 0078         ip(m) = sum(abs(dtemp(m, :).^2 - xtemp.^2));
134 | 0079     end
135 | 0080     [mt(cind),dm(cind)] = min(abs(ip.'),[],1);
136 | 0081     if(mod(i, 100)==0)
137 | 0082         disp(i);
138 | 0083         disp(dm(cind));
139 | 0084     end
140 | 0085 end
141 | 0086 clear match;
142 | 0087 clear dictentry;
143 | 0088 
144 | 0089 %% Generate output
145 | 0090 Q=6;
146 | 0091 dm(dm==0) =1;
147 | 0092 dict.lut(1,:) =0;
148 | 0093 
149 | 0094 qmap = zeros(N,Q,'single');
150 | 0095 qmap(mask>0,:) = dict.lut(dm,:);
151 | 0096 qmap(isnan(qmap)) = 0; %remove possible NaN from infeasible search window
152 | 0097 out.qmap = reshape(qmap,[datadims(1:end-1),Q]);
153 | 0098 out.mask = mask;
154 | 0099 figure; imagesc(abs(squeeze(out.qmap(:,:,1)))); axis equal tight; colormap hot; title('T1 map');
155 | 0100 figure; imagesc(abs(squeeze(out.qmap(:,:,2)))); axis equal tight; colormap hot; title('T2 map');
156 | 0101 end
157 |
Generated on Mon 26-Aug-2019 16:44:22 by m2html © 2005
158 | 159 | -------------------------------------------------------------------------------- /docs/mrf/Dictionary_Matching/Function/menu.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Index for Directory mrf\Dictionary_Matching\Function 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
^ Master index ^
16 | 17 |

Index for mrf\Dictionary_Matching\Function

18 | 19 |

Matlab files in this directory:

20 | 22 | 23 | 24 | 25 | 26 | 27 |
Generated by m2html © 2005
28 | 29 | -------------------------------------------------------------------------------- /docs/mrf/Dictionary_Matching/MRF_dict_matching_demo.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Description of MRF_dict_matching_demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 |

MRF_dict_matching_demo 20 |

21 | 22 |

PURPOSE ^

23 |
This script is used as a demo for MRF_Dict_Matching.m. The function takes in a
24 | 25 |

SYNOPSIS ^

26 |
This is a script file.
27 | 28 |

DESCRIPTION ^

29 |
 This script is used as a demo for MRF_Dict_Matching.m. The function takes in a
30 |  .mat dictionary file and .mat recontructed image file and using vector dot
31 |  product to find the most similar dictionary entry. 
32 |  The .mat dictionary file can be located in Dictionary_Matching/Data, while
33 |  the reconstructed image data file is too large to be included in a Github
34 |  repository. They can be found in Google drive. Shareable link are below.
35 |  T1 Array slice: https://drive.google.com/open?id=1G4hsc00CS5ycbnQ6KQa8YDlkis_Yc-5f
36 |  G2 Array slice: https://drive.google.com/open?id=199m40D-eiPWnAMtcNZj6gIM0aDZ-VZoB
37 | 
38 |  8/2019 Enlin Qian
39 |  # Copyright of the Board of Trustees of Columbia University in the City of New York
40 | 41 | 42 |

CROSS-REFERENCE INFORMATION ^

43 | This function calls: 44 | 46 | This function is called by: 47 | 49 | 50 | 51 | 52 | 53 |

SOURCE CODE ^

54 |
0001 % This script is used as a demo for MRF_Dict_Matching.m. The function takes in a
55 | 0002 % .mat dictionary file and .mat recontructed image file and using vector dot
56 | 0003 % product to find the most similar dictionary entry.
57 | 0004 % The .mat dictionary file can be located in Dictionary_Matching/Data, while
58 | 0005 % the reconstructed image data file is too large to be included in a Github
59 | 0006 % repository. They can be found in Google drive. Shareable link are below.
60 | 0007 % T1 Array slice: https://drive.google.com/open?id=1G4hsc00CS5ycbnQ6KQa8YDlkis_Yc-5f
61 | 0008 % G2 Array slice: https://drive.google.com/open?id=199m40D-eiPWnAMtcNZj6gIM0aDZ-VZoB
62 | 0009 %
63 | 0010 % 8/2019 Enlin Qian
64 | 0011 % # Copyright of the Board of Trustees of Columbia University in the City of New York
65 | 0012 
66 | 0013 %% Image Reconstruction
67 | 0014 addpath(genpath('.'));
68 | 0015 data = image_data_final_Complex;
69 | 0016 clear image_data_final_Complex;
70 | 0017 out = MRF_Dict_Matching(dict, data);
71 |
Generated on Mon 26-Aug-2019 16:44:22 by m2html © 2005
72 | 73 | -------------------------------------------------------------------------------- /docs/mrf/Dictionary_Matching/menu.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Index for Directory mrf\Dictionary_Matching 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
^ Master index ^
16 | 17 |

Index for mrf\Dictionary_Matching

18 | 19 |

Matlab files in this directory:

20 | 22 | 23 | 24 |

Subsequent directories:

25 | 27 | 28 | 29 |
Generated by m2html © 2005
30 | 31 | -------------------------------------------------------------------------------- /docs/mrf/EPG_Dict_Sim/Function/EPG_custom.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Description of EPG_custom 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 |

EPG_custom 20 |

21 | 22 |

PURPOSE ^

23 |
[om_store,echoes] = EPG_custom(seq)
24 | 25 |

SYNOPSIS ^

26 |
function [om_store,echoes] = EPG_custom(seq)
27 | 28 |

DESCRIPTION ^

29 |
[om_store,echoes] = EPG_custom(seq)
 30 |  Performs EPG simulation of a general pulse sequence
 31 |  INPUTS 
 32 |      seq: sequence struct with the required fields
 33 |          seq.rf - 2 x P matrix with each column = [phi,alpha]'
 34 |          seq.grad - vector of k-shifts (must be integers)
 35 |          seq.events - cell of strings: 'rf','grad', or 'relax'
 36 |          seq.time - vector of timing for each event in seq.events
 37 |          seq.T1, seq.T2 : T1 and T2 values for relaxation 
 38 |                          (set both to 0 for no relaxation)
 39 |  OUTPUTS
 40 | 
 41 |       om_store - 1 x Q cell array of matrices with size (3 x K).
 42 |       Each matrix is a record of configuration states (F+(k),F-(k),Z(k)
 43 |       at all k's generated up to that point. Each matrix corresponds to
 44 |       the elements in seq.events and seq.timing at the same index.
 45 | 
 46 |       echoes - output of echo information using findEchoes
47 | 48 | 49 |

CROSS-REFERENCE INFORMATION ^

50 | This function calls: 51 | 53 | This function is called by: 54 | 56 | 57 | 58 | 59 | 60 |

SOURCE CODE ^

61 |
0001 function [om_store,echoes] = EPG_custom(seq)
 62 | 0002 %[om_store,echoes] = EPG_custom(seq)
 63 | 0003 % Performs EPG simulation of a general pulse sequence
 64 | 0004 % INPUTS
 65 | 0005 %     seq: sequence struct with the required fields
 66 | 0006 %         seq.rf - 2 x P matrix with each column = [phi,alpha]'
 67 | 0007 %         seq.grad - vector of k-shifts (must be integers)
 68 | 0008 %         seq.events - cell of strings: 'rf','grad', or 'relax'
 69 | 0009 %         seq.time - vector of timing for each event in seq.events
 70 | 0010 %         seq.T1, seq.T2 : T1 and T2 values for relaxation
 71 | 0011 %                         (set both to 0 for no relaxation)
 72 | 0012 % OUTPUTS
 73 | 0013 %
 74 | 0014 %      om_store - 1 x Q cell array of matrices with size (3 x K).
 75 | 0015 %      Each matrix is a record of configuration states (F+(k),F-(k),Z(k)
 76 | 0016 %      at all k's generated up to that point. Each matrix corresponds to
 77 | 0017 %      the elements in seq.events and seq.timing at the same index.
 78 | 0018 %
 79 | 0019 %      echoes - output of echo information using findEchoes
 80 | 0020 
 81 | 0021 %%  Inputs
 82 | 0022 rf = seq.rf;
 83 | 0023 grad = seq.grad;
 84 | 0024 timing = seq.time; % in ms
 85 | 0025 uniqtimes = unique(timing);
 86 | 0026 events = seq.events; % 3 types of events: 'rf','grad', and 'relax'
 87 | 0027 N = length(events);
 88 | 0028 T1 = seq.T1; % must be populated - set to 0 for no relaxation
 89 | 0029 T2 = seq.T2; % must be populated - set to 0 for no relaxation
 90 | 0030 %% Initialize
 91 | 0031 omega = [0 0 1].'; % initial magnetization is always at equilibrium (+z)
 92 | 0032 %delk=1; %Unit dephasing
 93 | 0033 rf_index = 1;
 94 | 0034 om_index = 1;
 95 | 0035 grad_index = 1;
 96 | 0036 %% Describe pulse sequence in steps
 97 | 0037 om_store = cell(1,N);
 98 | 0038 for n = 1:N
 99 | 0039    switch events{n}
100 | 0040        case 'rf'
101 | 0041            omega = rf_rotation(rf(1,rf_index),rf(2,rf_index))*omega;
102 | 0042            rf_index = rf_index + 1;
103 | 0043        case 'grad'
104 | 0044            omega = shift_grad(grad(grad_index),omega);     
105 | 0045            grad_index = grad_index + 1;
106 | 0046        case 'relax'
107 | 0047            q = find(uniqtimes==timing(n));
108 | 0048            tau = uniqtimes(q) - uniqtimes(q-1);
109 | 0049            omega = relax(tau,T1,T2,omega);
110 | 0050    end
111 | 0051    om_store{om_index} = omega;
112 | 0052    om_index = om_index + 1;
113 | 0053 end
114 | 0054 % Find and store echos
115 | 0055 echoes = findEchoes(seq,om_store);
116 | 0056 
117 | 0057 end
118 | 0058
119 |
Generated on Mon 26-Aug-2019 16:44:22 by m2html © 2005
120 | 121 | -------------------------------------------------------------------------------- /docs/mrf/EPG_Dict_Sim/Function/EPGsim_MRF.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Description of EPGsim_MRF 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 |

EPGsim_MRF 20 |

21 | 22 |

PURPOSE ^

23 |
[om_store, echoes, seq] = EPGsim_MRF(phis,alphas,TRs,rlx)
24 | 25 |

SYNOPSIS ^

26 |
function [om_store,echoes,seq] = EPGsim_MRF(phis,alphas,TRs,rlx)
27 | 28 |

DESCRIPTION ^

29 |
 [om_store, echoes, seq] = EPGsim_MRF(phis,alphas,TRs,rlx)
30 |  Simulates variable flip angle & variable timing EPG
31 |  Author: Gehua Tong 
32 |  Date: Feb 25, 2019
33 | 34 | 35 |

CROSS-REFERENCE INFORMATION ^

36 | This function calls: 37 | 39 | This function is called by: 40 | 42 | 43 | 44 | 45 | 46 |

SOURCE CODE ^

47 |
0001 function [om_store,echoes,seq] = EPGsim_MRF(phis,alphas,TRs,rlx)
48 | 0002 % [om_store, echoes, seq] = EPGsim_MRF(phis,alphas,TRs,rlx)
49 | 0003 % Simulates variable flip angle & variable timing EPG
50 | 0004 % Author: Gehua Tong
51 | 0005 % Date: Feb 25, 2019
52 | 0006 
53 | 0007 % Note:
54 | 0008 %    (1) phis and alphas must have the same size & be in degrees
55 | 0009 %    (2) TRs are in milliseconds; TRs must be the same size as phis &
56 | 0010 %    alphas
57 | 0011 %    (3) rlx = [T1 T2] in milliseconds(set both to zero for no relaxation)
58 | 0012 % Important: all gradients = 0, so we are always at coherence order 0
59 | 0013 %            (i.e. only RF flipping and relaxation happen)
60 | 0014 
61 | 0015 N = length(TRs);
62 | 0016 seq.name = 'Variable FA & TR for MRF';
63 | 0017 seq.rf = [phis(:)';alphas(:)'];
64 | 0018 diffTime = [zeros(1,N);repmat(TRs,2,1)];
65 | 0019 seq.time = repelem(cumsum([0 TRs(1:end-1)]),1,3) + diffTime(:)';
66 | 0020 seq.events = repmat({'rf','grad','relax'},1,length(TRs));
67 | 0021 seq.grad = zeros(1,length(TRs));
68 | 0022 seq.T1 = rlx(1); seq.T2 = rlx(2); 
69 | 0023 
70 | 0024 [om_store,echoes] = EPG_custom(seq);
71 | 0025 
72 | 0026 
73 | 0027 end
74 |
Generated on Mon 26-Aug-2019 16:44:22 by m2html © 2005
75 | 76 | -------------------------------------------------------------------------------- /docs/mrf/EPG_Dict_Sim/Function/Var_TE.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Description of Var_TE 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 |

Var_TE 20 |

21 | 22 |

PURPOSE ^

23 |
24 | 25 |

SYNOPSIS ^

26 |
function Echo_Final = Var_TE(om_store, TE_all, T2)
27 | 28 |

DESCRIPTION ^

29 |
30 | 31 | 32 |

CROSS-REFERENCE INFORMATION ^

33 | This function calls: 34 | 36 | This function is called by: 37 | 39 | 40 | 41 | 42 | 43 |

SOURCE CODE ^

44 |
0001 function Echo_Final = Var_TE(om_store, TE_all, T2)
45 | 0002 F_plus = cellfun(@(v)v(1),om_store);
46 | 0003 F_plus = F_plus(1:3:end);
47 | 0004 F_plus = abs(F_plus);
48 | 0005 F_plus = F_plus(2:1001);
49 | 0006 Echo_Final = F_plus.*exp(-TE_all'/T2);
50 | 0007 end
51 |
Generated on Mon 26-Aug-2019 16:44:22 by m2html © 2005
52 | 53 | -------------------------------------------------------------------------------- /docs/mrf/EPG_Dict_Sim/Function/findEchoes.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Description of findEchoes 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 |

findEchoes 20 |

21 | 22 |

PURPOSE ^

23 |
echoes = FINDECHOES(seq,om_store)
24 | 25 |

SYNOPSIS ^

26 |
function echoes = findEchoes(seq,om_store)
27 | 28 |

DESCRIPTION ^

29 |
echoes = FINDECHOES(seq,om_store)
30 |  Finds echo timings and intensities given sequence seq and 
31 |  om_store (the later being generated by EPG_custom.m)
32 |  
33 |  We only find the proper and unique echoes
34 |  Criteria: 
35 |  (a) The F(0) component must be non-zero (>5*eps)
36 |  (b) If there are multiple echoes satisfying (a) at the same timing,
37 |      use the last value. So for grad->relax->RF, we only get F(0) after
38 |      the RF, and for grad->relax, we only get F(0) after the relaxation.
39 |  
40 |  output: echoes is N x 2 matrix where N is the number of echoes found
41 |          1st col - timing; 2nd col - intensity (modulus of F(0))
42 | 43 | 44 |

CROSS-REFERENCE INFORMATION ^

45 | This function calls: 46 | 48 | This function is called by: 49 | 51 | 52 | 53 | 54 | 55 |

SOURCE CODE ^

56 |
0001 function echoes = findEchoes(seq,om_store)
57 | 0002 %echoes = FINDECHOES(seq,om_store)
58 | 0003 % Finds echo timings and intensities given sequence seq and
59 | 0004 % om_store (the later being generated by EPG_custom.m)
60 | 0005 %
61 | 0006 % We only find the proper and unique echoes
62 | 0007 % Criteria:
63 | 0008 % (a) The F(0) component must be non-zero (>5*eps)
64 | 0009 % (b) If there are multiple echoes satisfying (a) at the same timing,
65 | 0010 %     use the last value. So for grad->relax->RF, we only get F(0) after
66 | 0011 %     the RF, and for grad->relax, we only get F(0) after the relaxation.
67 | 0012 %
68 | 0013 % output: echoes is N x 2 matrix where N is the number of echoes found
69 | 0014 %         1st col - timing; 2nd col - intensity (modulus of F(0))
70 | 0015 
71 | 0016 echoes = [];
72 | 0017 timing = seq.time;
73 | 0018 for v = 1:length(om_store)
74 | 0019     if abs(om_store{v}(1,1)) > 5*eps %&& sum(rftimes == timing(v))==0
75 | 0020         newecho = [timing(v),abs(om_store{v}(1,1))];
76 | 0021         if ~isempty(echoes) && echoes(end,1) == timing(v)
77 | 0022             % same timing - always take the 2nd one
78 | 0023             echoes = [echoes(1:end-1,:);newecho];
79 | 0024         else 
80 | 0025             echoes = [echoes;newecho];
81 | 0026         end
82 | 0027         
83 | 0028     end
84 | 0029 end
85 | 0030 echoes = unique(echoes,'rows');
86 | 0031 end
87 | 0032
88 |
Generated on Mon 26-Aug-2019 16:44:22 by m2html © 2005
89 | 90 | -------------------------------------------------------------------------------- /docs/mrf/EPG_Dict_Sim/Function/menu.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Index for Directory mrf\EPG_Dict_Sim\Function 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
^ Master index ^
16 | 17 |

Index for mrf\EPG_Dict_Sim\Function

18 | 19 |

Matlab files in this directory:

20 | 22 | 23 | 24 | 25 | 26 | 27 |
Generated by m2html © 2005
28 | 29 | -------------------------------------------------------------------------------- /docs/mrf/EPG_Dict_Sim/Function/relax.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Description of relax 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 |

relax 20 |

21 | 22 |

PURPOSE ^

23 |
relax(tau,T1,T2,omega)
24 | 25 |

SYNOPSIS ^

26 |
function omega_new = relax(tau,T1,T2,omega)
27 | 28 |

DESCRIPTION ^

29 |
relax(tau,T1,T2,omega)
30 | relax.m: updates omega with relaxation effects
31 |  INPUTS
32 |    tau: duration of relaxation in ms
33 |    T1,T2: time constants in ms
34 |    omega: the input (3 x n) matrix of k-states
35 | 36 | 37 |

CROSS-REFERENCE INFORMATION ^

38 | This function calls: 39 | 41 | This function is called by: 42 | 44 | 45 | 46 | 47 | 48 |

SOURCE CODE ^

49 |
0001 function omega_new = relax(tau,T1,T2,omega)
50 | 0002 %relax(tau,T1,T2,omega)
51 | 0003 %relax.m: updates omega with relaxation effects
52 | 0004 % INPUTS
53 | 0005 %   tau: duration of relaxation in ms
54 | 0006 %   T1,T2: time constants in ms
55 | 0007 %   omega: the input (3 x n) matrix of k-states
56 | 0008 
57 | 0009 % Gehua Tong, Oct 7 2018
58 | 0010 
59 | 0011 if size(omega,1) ~= 3
60 | 0012     error('Size of k-state matrix incorrect. Input needs to be (3 x n)')
61 | 0013 end
62 | 0014 if T1 ~= 0 && T2 ~=0
63 | 0015     E1 = exp(-tau/T1);
64 | 0016     E2 = exp(-tau/T2);
65 | 0017     Emat = [E2  0  0;
66 | 0018              0 E2  0;
67 | 0019              0  0 E1];
68 | 0020     omega_new = Emat*omega;
69 | 0021     omega_new(:,1) = omega_new(:,1) + [0,0,1-E1]'; % M0 = 1 default
70 | 0022 else
71 | 0023     omega_new = omega;
72 | 0024 end
73 | 0025 
74 | 0026 end
75 | 0027
76 |
Generated on Mon 26-Aug-2019 16:44:22 by m2html © 2005
77 | 78 | -------------------------------------------------------------------------------- /docs/mrf/EPG_Dict_Sim/Function/rf_rotation.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Description of rf_rotation 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 |

rf_rotation 20 |

21 | 22 |

PURPOSE ^

23 |
RF_ROTATION(phi,alpha)
24 | 25 |

SYNOPSIS ^

26 |
function T_phi_alpha = rf_rotation (phi,alpha)
27 | 28 |

DESCRIPTION ^

29 |
RF_ROTATION(phi,alpha)
30 |  3 x 3 rotation matrix in complex representation for RF pulse
31 |  with phase = phi (from the x axis) and filp angle = alpha
32 |  See Weigel 2015, Eq. 15
33 | 34 | 35 |

CROSS-REFERENCE INFORMATION ^

36 | This function calls: 37 | 39 | This function is called by: 40 | 42 | 43 | 44 | 45 | 46 |

SOURCE CODE ^

47 |
0001 function T_phi_alpha = rf_rotation (phi,alpha)
48 | 0002 %RF_ROTATION(phi,alpha)
49 | 0003 % 3 x 3 rotation matrix in complex representation for RF pulse
50 | 0004 % with phase = phi (from the x axis) and filp angle = alpha
51 | 0005 % See Weigel 2015, Eq. 15
52 | 0006 
53 | 0007 phi = deg2rad(phi);
54 | 0008 alpha = deg2rad(alpha);
55 | 0009 
56 | 0010 T_phi_alpha = [cos(alpha/2).^2                     exp(2*1i*phi)*sin(alpha/2).^2       -1i*exp(1i*phi)*sin(alpha);
57 | 0011            exp(-2*1i*phi)*sin(alpha/2).^2       cos(alpha/2).^2                     1i*exp(-1i*phi)*sin(alpha);
58 | 0012            -1i*0.5.*exp(-1i*phi)* sin(alpha)    1i*0.5.*exp(1i*phi)* sin(alpha)     cos(alpha)];
59 |
Generated on Mon 26-Aug-2019 16:44:22 by m2html © 2005
60 | 61 | -------------------------------------------------------------------------------- /docs/mrf/EPG_Dict_Sim/Function/shift_grad.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Description of shift_grad 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 |

shift_grad 20 |

21 | 22 |

PURPOSE ^

23 |
SHIFT_GRAD(delk,omega)
24 | 25 |

SYNOPSIS ^

26 |
function omega_new = shift_grad(delk,omega)
27 | 28 |

DESCRIPTION ^

29 |
SHIFT_GRAD(delk,omega)
 30 |  Modified by: Gehua Tong
 31 |  Date: 15 Oct 2018
 32 |  Modified by: Sachin A B Anchan
 33 |  Date: 30 June 2014
 34 |  Shift applies to only F+ and F-* as it does not dephase in z
 35 |  check size of previous omega to determine the effect - test multiple
 36 |  times
37 | 38 | 39 |

CROSS-REFERENCE INFORMATION ^

40 | This function calls: 41 | 43 | This function is called by: 44 | 46 | 47 | 48 | 49 | 50 |

SOURCE CODE ^

51 |
0001 function omega_new = shift_grad(delk,omega)
 52 | 0002 %SHIFT_GRAD(delk,omega)
 53 | 0003 % Modified by: Gehua Tong
 54 | 0004 % Date: 15 Oct 2018
 55 | 0005 % Modified by: Sachin A B Anchan
 56 | 0006 % Date: 30 June 2014
 57 | 0007 % Shift applies to only F+ and F-* as it does not dephase in z
 58 | 0008 % check size of previous omega to determine the effect - test multiple
 59 | 0009 % times
 60 | 0010 
 61 | 0011 % delk: integer indicating discrete change in k
 62 | 0012 % omega: inputted omega matrix (with columns of [F+,F-,Z]')
 63 | 0013 
 64 | 0014 [m,n] = size(omega); %previous time point
 65 | 0015 % if(m~=3)
 66 | 0016 %     error('Still implementing equation 26, please use 3xk');
 67 | 0017 % end
 68 | 0018 if delk == 0
 69 | 0019     omega_new = omega;
 70 | 0020 else
 71 | 0021 if(n>1) % typical case: an RF pulse has happened and we have transverse components
 72 | 0022     F = [fliplr(omega(1,:)) squeeze((omega(2,2:end)))]; %arrange to make it like eq 27
 73 | 0023         % Negative shift
 74 | 0024         if(delk < 0)
 75 | 0025               F = [zeros(1,abs(delk)) F]; %negative shift moves the population downwards - 2n-1 + delk
 76 | 0026               Z = [squeeze(omega(3,:)) zeros(1,abs(delk))]; %No change in z due to grads
 77 | 0027               Fp = [fliplr(F(1:n)) zeros(1,abs(delk))]; 
 78 | 0028               Fm = F(n:end);
 79 | 0029               % Here, V(k=1) moves into V'(k=+0),
 80 | 0030               %       so V'(k=-0) is the conjugate of V'(k=+0)
 81 | 0031               Fm(1) = conj(Fm(1));
 82 | 0032         % Positive shift
 83 | 0033         else
 84 | 0034               F = [F zeros(1,delk)]; %positive shift pushes the population upwards
 85 | 0035               Z = [squeeze(omega(3,:)) zeros(1,delk)];
 86 | 0036               Fp = fliplr(F(1:n+delk)); 
 87 | 0037               Fm = [F(n+delk:end) zeros(1,delk)];
 88 | 0038               % Here, V(k=-1) moves into V'(k=-0),
 89 | 0039               %       so V'(k=+0) is the conjugate of V'(k=-0)
 90 | 0040               Fp(1) = conj(Fp(1));
 91 | 0041         end
 92 | 0042 
 93 | 0043 
 94 | 0044 else % n = 1; this happens if pulse sequence starts with nonzero transverse
 95 | 0045      %        components and no RF pulse at t = 0 - gradient happens first
 96 | 0046      % omega(1) (=F+(0)) and omega(2)(= F-(0)) must be complex conjugates!!!
 97 | 0047      % omega(3) = Z(0)
 98 | 0048      if(delk > 0)
 99 | 0049        Fp = [zeros(1,abs(delk)) omega(1)];
100 | 0050        Fm = [0  zeros(1,abs(delk))];
101 | 0051         Z = [squeeze(omega(3)) zeros(1,abs(delk))];
102 | 0052      else
103 | 0053         Fp = [0  zeros(1,abs(delk))];
104 | 0054         Fm =  [zeros(1,abs(delk)) omega(2)];
105 | 0055         Z = [squeeze(omega(3)) zeros(1,abs(delk))];
106 | 0056         
107 | 0057     end
108 | 0058 end
109 | 0059 
110 | 0060 omega_new = [Fp;Fm;Z];
111 | 0061 end
112 |
Generated on Mon 26-Aug-2019 16:44:22 by m2html © 2005
113 | 114 | -------------------------------------------------------------------------------- /docs/mrf/EPG_Dict_Sim/dict_sim_MRF_demo.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Description of dict_sim_MRF_demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 |

dict_sim_MRF_demo 20 |

21 | 22 |

PURPOSE ^

23 |
24 | 25 |

SYNOPSIS ^

26 |
This is a script file.
27 | 28 |

DESCRIPTION ^

29 |
30 | 31 | 32 |

CROSS-REFERENCE INFORMATION ^

33 | This function calls: 34 | 36 | This function is called by: 37 | 39 | 40 | 41 | 42 | 43 |

SOURCE CODE ^

44 |
0001 clc
45 | 0002 clear 
46 | 0003 
47 | 0004 %This script is used as a demo for dict_sim_MRF.m. All TR, FA, and TE are
48 | 0005 %loaded based on the sequence generated in Sequence Design part.
49 | 0006 % 7/2019 Enlin Qian
50 | 0007 % # Copyright of the Board of Trustees of Columbia University in the City of New York
51 | 0008 addpath(genpath('.'));
52 | 0009 load('TR_TE_FA.mat')
53 | 0010 %% Dictionary Simulation
54 | 0011 phis = zeros(1,1001); % the sequence starts with a 180 pulse, thus 1001 points
55 | 0012 alphas = [180, FA_all']; % all flip angles
56 | 0013 TRs = [18, TR_all'.*1000]; % all TRs, in ms
57 | 0014 T1_range=0.02:0.005:0.065;
58 | 0015 T1_range=[T1_range, 0.09:0.03:0.36];
59 | 0016 T1_range=[T1_range, 0.5:0.1:4];
60 | 0017 T2_range=0.005:0.002:0.011;
61 | 0018 T2_range=[T2_range, 0.015:0.005:0.045];
62 | 0019 T2_range=[T2_range, 0.065:0.03:0.275];
63 | 0020 T2_range=[T2_range, 0.4:0.1:2];
64 | 0021 n3 = 1;
65 | 0022 Echo_Final=zeros(length(T1_range)*length(T2_range), 1000);
66 | 0023 for n1 = 1:length(T1_range)
67 | 0024     for n2 = 1:length(T2_range)
68 | 0025         disp (n3)
69 | 0026         [om_store,echoes,seq] = EPGsim_MRF(phis,alphas,TRs,[T1_range(n1), T2_range(n2)]);
70 | 0027         Echo_Final(n3, :) = Var_TE(om_store, TE_all, T2_range(n2));
71 | 0028         n3=n3+1;
72 | 0029     end
73 | 0030 end
74 |
Generated on Mon 26-Aug-2019 16:44:22 by m2html © 2005
75 | 76 | -------------------------------------------------------------------------------- /docs/mrf/EPG_Dict_Sim/menu.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Index for Directory mrf\EPG_Dict_Sim 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
^ Master index ^
16 | 17 |

Index for mrf\EPG_Dict_Sim

18 | 19 |

Matlab files in this directory:

20 | 22 | 23 | 24 |

Subsequent directories:

25 | 27 | 28 | 29 |
Generated by m2html © 2005
30 | 31 | -------------------------------------------------------------------------------- /docs/mrf/Image_Reconstruction/Function/Complex_Chan_Combining.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Description of Complex_Chan_Combining 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 |

Complex_Chan_Combining 20 |

21 | 22 |

PURPOSE ^

23 |
This script correct phase differences in each coil using method in [1].
24 | 25 |

SYNOPSIS ^

26 |
function coil_filter = Complex_Chan_Combining(image1)
27 | 28 |

DESCRIPTION ^

29 |
 This script correct phase differences in each coil using method in [1].
30 |  IUPUT
31 |      image1  reconstructed image 
32 | 
33 |  OUTPUT
34 |  coil_filter  filter used to correct phase from each coil
35 |  
36 |  [1] Roemer P, Edelstein W, Hayes C, Souza S, Mueller O. The NMR phased
37 |  array. Magn Reson Med. 1990;16(2):192-225. doi:10.1002/mrm.1910160203
38 | 39 | 40 |

CROSS-REFERENCE INFORMATION ^

41 | This function calls: 42 | 44 | This function is called by: 45 | 47 | 48 | 49 | 50 | 51 |

SOURCE CODE ^

52 |
0001 function coil_filter = Complex_Chan_Combining(image1)
53 | 0002 % This script correct phase differences in each coil using method in [1].
54 | 0003 % IUPUT
55 | 0004 %     image1  reconstructed image
56 | 0005 %
57 | 0006 % OUTPUT
58 | 0007 % coil_filter  filter used to correct phase from each coil
59 | 0008 %
60 | 0009 % [1] Roemer P, Edelstein W, Hayes C, Souza S, Mueller O. The NMR phased
61 | 0010 % array. Magn Reson Med. 1990;16(2):192-225. doi:10.1002/mrm.1910160203
62 | 0011 image1 = permute(image1,[1 2 4 3]);
63 | 0012 [Nx, Ny, Nt, C] = size(image1);
64 | 0013 filtsize = 5;
65 | 0014 Rs = zeros(Nx, Ny, C, C);
66 | 0015 
67 | 0016 % Correlation matrix
68 | 0017 for n1 = 1:C
69 | 0018     for n2 = 1:C
70 | 0019         for n3 = 1:Nt
71 | 0020             Rs(:,:,n1,n2) = Rs(:,:,n1,n2) + filter2(ones(filtsize),...
72 | 0021                 image1(:,:,n3,n1).*conj(image1(:,:,n3,n2)),'same');
73 | 0022         end
74 | 0023     end
75 | 0024 end
76 | 0025 
77 | 0026 % Get filter
78 | 0027 Rs = permute(Rs,[3,4,1,2]);
79 | 0028 Rs = Rs(:,:,:);
80 | 0029 coil_filter = zeros(size(Rs,3),C);
81 | 0030 for n4 = 1:size(Rs,3)
82 | 0031     [U,~] = svd(squeeze(Rs(:,:,n4)));
83 | 0032     coil_filter(n4,:) = U(:,1);
84 | 0033 end
85 | 0034 
86 | 0035 coil_filter = reshape(coil_filter, Nx, Ny, C);
87 | 0036 
88 | 0037 end
89 |
Generated on Mon 26-Aug-2019 16:44:22 by m2html © 2005
90 | 91 | -------------------------------------------------------------------------------- /docs/mrf/Image_Reconstruction/Function/dat2mat_nonCart.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Description of dat2mat_nonCart 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 |

dat2mat_nonCart 20 |

21 | 22 |

PURPOSE ^

23 |
This script reads in .dat raw data and convert it to kspace data.
24 | 25 |

SYNOPSIS ^

26 |
function [kspace_data]= dat2mat_nonCart()
27 | 28 |

DESCRIPTION ^

29 |
 This script reads in .dat raw data and convert it to kspace data.
 30 |  IUPUT
 31 |       None  the user is asked to select a .dat raw data file 
 32 | 
 33 |  OUTPUT
 34 |  ksapce_data  kspace data
 35 | 
 36 |  Created 8/2013 Sairam Geethanath
 37 |  Modified 7/2019 Enlin Qian
 38 |  # Copyright of the Board of Trustees of Columbia University in the City of New York
39 | 40 | 41 |

CROSS-REFERENCE INFORMATION ^

42 | This function calls: 43 | 45 | This function is called by: 46 | 48 | 49 | 50 | 51 | 52 |

SOURCE CODE ^

53 |
0001 function [kspace_data]= dat2mat_nonCart()
 54 | 0002 % This script reads in .dat raw data and convert it to kspace data.
 55 | 0003 % IUPUT
 56 | 0004 %      None  the user is asked to select a .dat raw data file
 57 | 0005 %
 58 | 0006 % OUTPUT
 59 | 0007 % ksapce_data  kspace data
 60 | 0008 %
 61 | 0009 % Created 8/2013 Sairam Geethanath
 62 | 0010 % Modified 7/2019 Enlin Qian
 63 | 0011 % # Copyright of the Board of Trustees of Columbia University in the City of New York
 64 | 0012 
 65 | 0013 %% Obtain the file
 66 | 0014 [Filename,Pathname] = uigetfile('*.dat','Pick the raw data file');
 67 | 0015 
 68 | 0016 %% Read data using mapVBVD
 69 | 0017 twix_obj = mapVBVDVE(fullfile(Pathname,Filename));
 70 | 0018 
 71 | 0019 % image_obj = twix_obj.image; %Body coil
 72 | 0020 if(~iscell(twix_obj))
 73 | 0021 % if ( size(twix_obj.image) ==1)
 74 | 0022     image_obj = twix_obj.image;
 75 | 0023 else
 76 | 0024     image_obj = twix_obj{2}.image;
 77 | 0025 end
 78 | 0026 
 79 | 0027 sizeData = image_obj.sqzSize; %kx, nch, ky, slices, partitions
 80 | 0028 dimsData = image_obj.sqzDims;
 81 | 0029 dimsallData = image_obj.dataDims;
 82 | 0030 
 83 | 0031 %% Concatenate slices and partitions together and has a N x N acquisition set
 84 | 0032 kspace_data = zeros(sizeData);
 85 | 0033 
 86 | 0034 sl = 1;
 87 | 0035 
 88 | 0036 partitions=1;
 89 | 0037 
 90 | 0038 %% Determine k-space shift to the center
 91 | 0039 % temp = squeeze(image_obj(:,1,:,round(sizeData(4)/2),round(sizeData(5)/2)));
 92 | 0040 % [~,idx] = max(abs(temp(:)));
 93 | 0041 % [idx,idy] = ind2sub(size(temp),idx);
 94 | 0042 
 95 | 0043 %%
 96 | 0044 
 97 | 0045 
 98 | 0046 tic;
 99 | 0047 % for nch=1:size(kspace_data,2) %number of channels
100 | 0048 
101 | 0049 %        for narms=1:size(kspace_data,1) %number of arms
102 | 0050          kspace_data = squeeze(image_obj());
103 | 0051          
104 | 0052 %         temp = squeeze(image_obj(:,nch,:,sl,partitions));
105 | 0053 %         temp = circshift(temp, [round(size(temp,1)/2) - idx,round(size(temp,2)/2) - idy ]);
106 | 0054 %         trunc_part =round(0.5 .*(size(temp,1) - size(temp,2)));
107 | 0055 %         temp = squeeze(temp(trunc_part+1:end-trunc_part,:));
108 | 0056 %
109 | 0057 %         kspace_data(:,:,nslices,nch) = temp;
110 | 0058 
111 | 0059       
112 | 0060 
113 | 0061 
114 | 0062 % end
115 | 0063 toc;
116 | 0064 
117 | 0065 kspace_data = permute(kspace_data,[1  3   2   4]); %kx, ky, slices, partitions, nch
118 | 0066 kspace_data = squeeze(kspace_data);
119 | 0067 
120 | 0068 
121 | 0069 
122 | 0070 
123 | 0071 
124 | 0072 
125 | 0073 
126 | 0074 
127 | 0075 
128 | 0076 
129 | 0077
130 |
Generated on Mon 26-Aug-2019 16:44:22 by m2html © 2005
131 | 132 | -------------------------------------------------------------------------------- /docs/mrf/Image_Reconstruction/Function/menu.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Index for Directory mrf\Image_Reconstruction\Function 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
^ Master index ^
16 | 17 |

Index for mrf\Image_Reconstruction\Function

18 | 19 |

Matlab files in this directory:

20 | 22 | 23 | 24 | 25 | 26 | 27 |
Generated by m2html © 2005
28 | 29 | -------------------------------------------------------------------------------- /docs/mrf/Image_Reconstruction/MRF_recon_demo.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Description of MRF_recon_demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 |

MRF_recon_demo 20 |

21 | 22 |

PURPOSE ^

23 |
24 | 25 |

SYNOPSIS ^

26 |
This is a script file.
27 | 28 |

DESCRIPTION ^

29 |
30 | 31 | 32 |

CROSS-REFERENCE INFORMATION ^

33 | This function calls: 34 | 36 | This function is called by: 37 | 39 | 40 | 41 | 42 | 43 |

SOURCE CODE ^

44 |
0001 clc
45 | 0002 clear
46 | 0003 %This script is used as a demo for MRF_recon.m. The function takes in a
47 | 0004 %.dat raw data file and .mat trajectory file and using sliding windown
48 | 0005 %reconstruction and complex coil combination to reconstruct the image.
49 | 0006 %These two files can both be found under Image_Reconstruction/Data
50 | 0007 % 8/2019 Enlin Qian
51 | 0008 % # Copyright of the Board of Trustees of Columbia University in the City of New York
52 | 0009 
53 | 0010 %% Image Reconstruction
54 | 0011 addpath(genpath('.'));
55 | 0012 image_data_final_Complex = MRF_recon();
56 |
Generated on Mon 26-Aug-2019 16:44:22 by m2html © 2005
57 | 58 | -------------------------------------------------------------------------------- /docs/mrf/Image_Reconstruction/menu.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Index for Directory mrf\Image_Reconstruction 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
^ Master index ^
16 | 17 |

Index for mrf\Image_Reconstruction

18 | 19 |

Matlab files in this directory:

20 | 22 | 23 | 24 |

Subsequent directories:

25 | 27 | 28 | 29 |
Generated by m2html © 2005
30 | 31 | -------------------------------------------------------------------------------- /docs/mrf/ROI_analysis_tool/Function/Circle_Analysis.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Description of Circle_Analysis 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 |

Circle_Analysis 20 |

21 | 22 |

PURPOSE ^

23 |
Input center, radius, and map size and return index of pixels inside the
24 | 25 |

SYNOPSIS ^

26 |
function [CircleMap, PointsIndex] = Circle_Analysis(Center, Radius, ImXSize, ImYSize)
27 | 28 |

DESCRIPTION ^

29 |
 Input center, radius, and map size and return index of pixels inside the
30 |  circle.
31 |  INPUT
32 |      Center  Center of circle [x, y]
33 |      Radius  Radius of circle (in pixels)
34 |     ImXSize  Image size along x direction
35 |     ImYSize  Image size along y direction
36 | 
37 |  OUTPUT
38 |   CircleMap  Binary map for each circle
39 |  PointsIndex  Pixel index for all pixels inside input circle
40 | 
41 |  7/2019 Enlin Qian
42 |  # Copyright of the Board of Trustees of Columbia University in the City of New York
43 |  (x,y) = (colum, row)
44 | 45 | 46 |

CROSS-REFERENCE INFORMATION ^

47 | This function calls: 48 | 50 | This function is called by: 51 | 53 | 54 | 55 | 56 | 57 |

SOURCE CODE ^

58 |
0001 function [CircleMap, PointsIndex] = Circle_Analysis(Center, Radius, ImXSize, ImYSize)
59 | 0002 % Input center, radius, and map size and return index of pixels inside the
60 | 0003 % circle.
61 | 0004 % INPUT
62 | 0005 %     Center  Center of circle [x, y]
63 | 0006 %     Radius  Radius of circle (in pixels)
64 | 0007 %    ImXSize  Image size along x direction
65 | 0008 %    ImYSize  Image size along y direction
66 | 0009 %
67 | 0010 % OUTPUT
68 | 0011 %  CircleMap  Binary map for each circle
69 | 0012 % PointsIndex  Pixel index for all pixels inside input circle
70 | 0013 %
71 | 0014 % 7/2019 Enlin Qian
72 | 0015 % # Copyright of the Board of Trustees of Columbia University in the City of New York
73 | 0016 % (x,y) = (colum, row)
74 | 0017 [X,Y] = meshgrid(1:ImXSize,1:ImYSize);
75 | 0018 DistanceMap = sqrt((X-Center(1)).^2+(Y-Center(2)).^2);
76 | 0019 CircleMap = DistanceMap<=Radius;
77 | 0020 PointsIndex = find(CircleMap);
78 | 0021 end
79 |
Generated on Mon 26-Aug-2019 16:44:22 by m2html © 2005
80 | 81 | -------------------------------------------------------------------------------- /docs/mrf/ROI_analysis_tool/Function/gen_NIST_sphere_loc.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Description of gen_NIST_sphere_loc 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 |

gen_NIST_sphere_loc 20 |

21 | 22 |

PURPOSE ^

23 |
Input map parameters and Sphere 1 loc to generate a map that finds all
24 | 25 |

SYNOPSIS ^

26 |
function NIST_sphere_loc = gen_NIST_sphere_loc(map_type, map_size, fov, Sphere1_center)
27 | 28 |

DESCRIPTION ^

29 |
 Input map parameters and Sphere 1 loc to generate a map that finds all
 30 |  locations of other spheres.
 31 |  INPUT
 32 |    map_type  type of map (T1 or T2)
 33 |    map_size  size of map, for example, 128 means the map size is 128x128
 34 |         fov  field of view                                  [mm]
 35 |    Sphere1_loc  centers of sphere 1 (x, y)
 36 | 
 37 |  OUTPUT
 38 |    NIST_sphere_loc  sphere locations for all spheres
 39 | 
 40 |  7/2019 Enlin Qian
 41 |  # Copyright of the Board of Trustees of Columbia University in the City of New York
42 | 43 | 44 |

CROSS-REFERENCE INFORMATION ^

45 | This function calls: 46 | 48 | This function is called by: 49 | 51 | 52 | 53 | 54 | 55 |

SOURCE CODE ^

56 |
0001 function NIST_sphere_loc = gen_NIST_sphere_loc(map_type, map_size, fov, Sphere1_center)
 57 | 0002 % Input map parameters and Sphere 1 loc to generate a map that finds all
 58 | 0003 % locations of other spheres.
 59 | 0004 % INPUT
 60 | 0005 %   map_type  type of map (T1 or T2)
 61 | 0006 %   map_size  size of map, for example, 128 means the map size is 128x128
 62 | 0007 %        fov  field of view                                  [mm]
 63 | 0008 %   Sphere1_loc  centers of sphere 1 (x, y)
 64 | 0009 %
 65 | 0010 % OUTPUT
 66 | 0011 %   NIST_sphere_loc  sphere locations for all spheres
 67 | 0012 %
 68 | 0013 % 7/2019 Enlin Qian
 69 | 0014 % # Copyright of the Board of Trustees of Columbia University in the City of New York
 70 | 0015 NIST_sphere_loc.num_spheres = 14;
 71 | 0016 NIST_sphere_loc.voxel_size = fov/map_size; % unit in mm/voxel
 72 | 0017 NIST_sphere_loc.temp_rot_center = [map_size/2, map_size/2]; % unit in pixel
 73 | 0018 switch(map_type)
 74 | 0019     case 'T1'
 75 | 0020         NIST_sphere_loc.dist_map = [0, 31.324, 58.893, 81.810, 95.898, 100.317,...
 76 | 0021             95.991, 81.077, 58.860, 31.451, 35.380, 35.931, 73.124, 73.157]; % unit in mm
 77 | 0022         NIST_sphere_loc.ang_map = [0, 70.0850, 53.3538, 35.3270, 16.9426, -0.6324,...
 78 | 0023             -18.7705, -36.9326, -56.4287, -72.7011, 33.6653, -34.0284, 14.9729, -16.4091]; % unit in degree
 79 | 0024             
 80 | 0025     case 'T2'
 81 | 0026         NIST_sphere_loc.dist_map = [0, 31.547, 58.642, 80.697, 95.713, 99.812,...
 82 | 0027             96.050, 80.936, 58.824, 30.036, 36.204, 35.882, 73.002, 72.552]; % unit in mm
 83 | 0028         NIST_sphere_loc.ang_map = [0, 71.4899, 54.0302, 35.7043, 17.5603, -0.1549,...
 84 | 0029             -18.3830, -35.8010, -54.2831, -70.3638, 33.1854, -33.0284, 15.2130, -16.2861]; % unit in degree
 85 | 0030 end
 86 | 0031 
 87 | 0032 %% convert mm to voxel based on map_size and fov
 88 | 0033 NIST_sphere_loc.dist_map = NIST_sphere_loc.dist_map/NIST_sphere_loc.voxel_size; % convert to unit in voxel
 89 | 0034 
 90 | 0035 %% Use Sphere 1 loc to calculate template Sphere1 loc
 91 | 0036 dist_Sphere12center = sqrt((Sphere1_center(1)- NIST_sphere_loc.temp_rot_center(1))^2+...
 92 | 0037     (Sphere1_center(2)- NIST_sphere_loc.temp_rot_center(2))^2);
 93 | 0038 NIST_sphere_loc.template_Sphere1_loc = [map_size/2, map_size/2-dist_Sphere12center]; % pixel
 94 | 0039 
 95 | 0040 %% get coordinates for all spheres
 96 | 0041 NIST_sphere_loc.template_loc = zeros(NIST_sphere_loc.num_spheres, 2);
 97 | 0042 NIST_sphere_loc.template_loc(:, 1) = NIST_sphere_loc.template_Sphere1_loc(1, 1) +...
 98 | 0043     NIST_sphere_loc.dist_map.*sind(NIST_sphere_loc.ang_map); % x axis
 99 | 0044 NIST_sphere_loc.template_loc(:, 2) = NIST_sphere_loc.template_Sphere1_loc(1, 2) +...
100 | 0045     NIST_sphere_loc.dist_map.*cosd(NIST_sphere_loc.ang_map); % y axis
101 | 0046
102 |
Generated on Mon 26-Aug-2019 16:44:22 by m2html © 2005
103 | 104 | -------------------------------------------------------------------------------- /docs/mrf/ROI_analysis_tool/Function/gen_NIST_std_par.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Description of gen_NIST_std_par 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 |

gen_NIST_std_par 20 |

21 | 22 |

PURPOSE ^

23 |
Input map parameters and return phantom parameters based on map type, map
24 | 25 |

SYNOPSIS ^

26 |
function NIST_std_par = gen_NIST_std_par(map_type, map_size, fov)
27 | 28 |

DESCRIPTION ^

29 |
 Input map parameters and return phantom parameters based on map type, map
30 |  size and fov. 
31 |  INPUT
32 |    map_type  type of map (T1 or T2)
33 |    map_size  size of map, for example, 128 means the map size is 128x128
34 |         fov  field of view                                  [mm]
35 | 
36 |  OUTPUT
37 |    phan_std_par  standard phantom parameters.
38 | 
39 |  7/2019 Enlin Qian
40 |  # Copyright of the Board of Trustees of Columbia University in the City of New York
41 | 42 | 43 |

CROSS-REFERENCE INFORMATION ^

44 | This function calls: 45 | 47 | This function is called by: 48 | 50 | 51 | 52 | 53 | 54 |

SOURCE CODE ^

55 |
0001 function NIST_std_par = gen_NIST_std_par(map_type, map_size, fov)
56 | 0002 % Input map parameters and return phantom parameters based on map type, map
57 | 0003 % size and fov.
58 | 0004 % INPUT
59 | 0005 %   map_type  type of map (T1 or T2)
60 | 0006 %   map_size  size of map, for example, 128 means the map size is 128x128
61 | 0007 %        fov  field of view                                  [mm]
62 | 0008 %
63 | 0009 % OUTPUT
64 | 0010 %   phan_std_par  standard phantom parameters.
65 | 0011 %
66 | 0012 % 7/2019 Enlin Qian
67 | 0013 % # Copyright of the Board of Trustees of Columbia University in the City of New York
68 | 0014 NIST_std_par.num_spheres = 14;
69 | 0015 NIST_std_par.voxel_size = fov/map_size; % unit in mm/voxel
70 | 0016 NIST_std_par.sphere_radius = 8; % unit in mm
71 | 0017 NIST_std_par.temp_rot_center = [map_size/2, map_size/2]; % unit in pixel
72 | 0018 
73 | 0019 switch(map_type)
74 | 0020     case 'T1'
75 | 0021         NIST_std_par.true_value = [1.989, 1.454, 0.9841, 0.706, 0.4967,...
76 | 0022             0.3515, 0.24713, 0.1753, 0.1259, 0.089, 0.0627, 0.04453, 0.03084, 0.021719];
77 | 0023         NIST_std_par.plane_radius = 170; % mm
78 | 0024                  
79 | 0025     case 'T2'
80 | 0026         NIST_std_par.true_value = [0.5813, 0.4035, 0.2781, 0.19094, 0.13327,...
81 | 0027             0.09689, 0.06407, 0.04642, 0.03197, 0.02256, 0.015813, 0.011237, 0.007911, 0.005592];
82 | 0028         NIST_std_par.plane_radius = 195; % mm
83 | 0029 end
84 | 0030 NIST_std_par.intensity_range = [NIST_std_par.true_value(1)-0.2, NIST_std_par.true_value(1)+0.2];
85 | 0031 
86 | 0032 %% convert mm to voxel based on map_size and fov
87 | 0033 NIST_std_par.sphere_radius = NIST_std_par.sphere_radius/NIST_std_par.voxel_size; % convert to unit in voxel
88 | 0034 NIST_std_par.plane_radius = NIST_std_par.plane_radius/NIST_std_par.voxel_size; % convert to unit in voxel
89 | 0035 
90 | 0036 end
91 |
Generated on Mon 26-Aug-2019 16:44:22 by m2html © 2005
92 | 93 | -------------------------------------------------------------------------------- /docs/mrf/ROI_analysis_tool/Function/menu.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Index for Directory mrf\ROI_analysis_tool\Function 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
^ Master index ^
16 | 17 |

Index for mrf\ROI_analysis_tool\Function

18 | 19 |

Matlab files in this directory:

20 | 22 | 23 | 24 | 25 | 26 | 27 |
Generated by m2html © 2005
28 | 29 | -------------------------------------------------------------------------------- /docs/mrf/ROI_analysis_tool/ROI_ana_demo.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Description of ROI_ana_demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 |

ROI_ana_demo 20 |

21 | 22 |

PURPOSE ^

23 |
24 | 25 |

SYNOPSIS ^

26 |
This is a script file.
27 | 28 |

DESCRIPTION ^

29 |
30 | 31 | 32 |

CROSS-REFERENCE INFORMATION ^

33 | This function calls: 34 | 36 | This function is called by: 37 | 39 | 40 | 41 | 42 | 43 |

SOURCE CODE ^

44 |
0001 clc
45 | 0002 clear
46 | 0003 %This script is used as a demo for NIST_ROI_ana.m. For now, four sets of
47 | 0004 %data are used for testing.
48 | 0005 %       T1_map.mat  T1_map data
49 | 0006 % T1_map_rot45.mat  T1_map data rotated counterclockwise 45 degrees
50 | 0007 %       T2_map.mat  T2_map data
51 | 0008 % T2_map_rot30.mat  T2_map data rotated counterclockwise 30 degree
52 | 0009 %
53 | 0010 % 7/2019 Enlin Qian
54 | 0011 % # Copyright of the Board of Trustees of Columbia University in the City of New York
55 | 0012 
56 | 0013 %% Load data
57 | 0014 addpath(genpath('.'))
58 | 0015 load('T2_map_rot30.mat')
59 | 0016 sphere_par = NIST_ROI_ana(T2_map_rot, 'T2', 128, 210);
60 |
Generated on Mon 26-Aug-2019 16:44:22 by m2html © 2005
61 | 62 | -------------------------------------------------------------------------------- /docs/mrf/ROI_analysis_tool/menu.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Index for Directory mrf\ROI_analysis_tool 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
^ Master index ^
16 | 17 |

Index for mrf\ROI_analysis_tool

18 | 19 |

Matlab files in this directory:

20 | 22 | 23 | 24 |

Subsequent directories:

25 | 27 | 28 | 29 |
Generated by m2html © 2005
30 | 31 | -------------------------------------------------------------------------------- /docs/mrf/Sequence_Design/Function/menu.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Index for Directory mrf\Sequence_Design\Function 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
^ Master index ^
16 | 17 |

Index for mrf\Sequence_Design\Function

18 | 19 |

Matlab files in this directory:

20 | 22 | 23 | 24 | 25 | 26 | 27 |
Generated by m2html © 2005
28 | 29 | -------------------------------------------------------------------------------- /docs/mrf/Sequence_Design/Function/voronoi_area.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Description of voronoi_area 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 |

voronoi_area 20 |

21 | 22 |

PURPOSE ^

23 |
Calculate the area (density) of a k-space trajectory via Voronoi
24 | 25 |

SYNOPSIS ^

26 |
function dcf_out = voronoi_area(k)
27 | 28 |

DESCRIPTION ^

29 |
 Calculate the area (density) of a k-space trajectory via Voronoi
 30 |  triangulation
 31 |  INPUT
 32 |       k  k-space trajectory  ([-0.5 0.5]*res)
 33 | 
 34 |  OUTPUT
 35 | dcf_out  area assosiated with each k-space point
 36 | 
 37 |  Created Florian Wiesinger
 38 |  Modified 7/2006 Rolf Schulte
39 | 40 | 41 |

CROSS-REFERENCE INFORMATION ^

42 | This function calls: 43 | 45 | This function is called by: 46 | 48 | 49 | 50 | 51 | 52 |

SOURCE CODE ^

53 |
0001 function dcf_out = voronoi_area(k)
 54 | 0002 % Calculate the area (density) of a k-space trajectory via Voronoi
 55 | 0003 % triangulation
 56 | 0004 % INPUT
 57 | 0005 %      k  k-space trajectory  ([-0.5 0.5]*res)
 58 | 0006 %
 59 | 0007 % OUTPUT
 60 | 0008 %dcf_out  area assosiated with each k-space point
 61 | 0009 %
 62 | 0010 % Created Florian Wiesinger
 63 | 0011 % Modified 7/2006 Rolf Schulte
 64 | 0012 
 65 | 0013 if (nargin<1), help(mfilename); dcf = NaN; return; end;
 66 | 0014 if size(k,1)~=1, error('size(k,1)~=1'); end
 67 | 0015 
 68 | 0016 fufa = 0.7; % fudge factor to reduce outside areas
 69 | 0017 
 70 | 0018 tmp = version;
 71 | 0019 if str2double(tmp(1))>7
 72 | 0020     [ku,ki] = unique(k,'stable');
 73 | 0021 else
 74 | 0022     [ku,ki] = unique(k);
 75 | 0023 end
 76 | 0024 nupts = length(k)-length(ki);
 77 | 0025 nsimi = sum(abs(diff(sort(k)))<0.02);
 78 | 0026 if nsimi>nupts, 
 79 | 0027     warning('voronoi_area:nsimi',...
 80 | 0028         'Detected %g similar points -> check dcf',nsimi);
 81 | 0029 end
 82 | 0030 if nupts>0, 
 83 | 0031     fprintf('%g non-unique points excluded\n',nupts);
 84 | 0032 end
 85 | 0033 kx  = real(ku).';
 86 | 0034 ky  = imag(ku).';
 87 | 0035 kxy = [kx,ky];
 88 | 0036 [V,C] = voronoin(kxy);      % calculate voronoi vertices
 89 | 0037 dcf  = zeros(1,length(kxy));
 90 | 0038 makx  = max(abs(kx));
 91 | 0039 maky  = max(abs(ky));
 92 | 0040 makxy = min([makx maky]);
 93 | 0041 tmp1 = 0;
 94 | 0042 
 95 | 0043 for i1 = 1:length(C)%length(kxy),     % loop through all triangles
 96 | 0044     x = V(C{i1},1);
 97 | 0045     y = V(C{i1},2);
 98 | 0046     % check for points outside the sampled area
 99 | 0047     if  any(isinf(x)) || any(isinf(y)) || ...
100 | 0048             any(abs(x)>makx) || any(abs(y)>maky) || ...
101 | 0049             any(sqrt(x.^2+y.^2)>makxy), 
102 | 0050         % outside: radius -> approximate area
103 | 0051         tmp1 = tmp1+1;
104 | 0052         radii = sort(sqrt( (x-kx(i1)).^2 + (y-ky(i1)).^2 ));
105 | 0053         dcf(i1) = radii(1)*radii(2)*fufa;
106 | 0054         % dcf(i1) = mean(radii(1:2))^2;
107 | 0055         % dcf(i1) = mean(radii(1:2))^2*pi;
108 | 0056     else
109 | 0057         % inside: correct area
110 | 0058         dcf(i1) = polyarea(x,y);
111 | 0059     end
112 | 0060 end
113 | 0061 
114 | 0062 if any(isinf(dcf(:))),
115 | 0063     dcf(isinf(dcf)) = 0;
116 | 0064     warning('voronoi_area:inf','dcf contains inf -> setting to zero');
117 | 0065 end
118 | 0066 dcf_out = zeros(1,length(k));
119 | 0067 dcf_out(1,ki) = dcf;
120 | 0068 
121 | 0069 %
122 | 0070 mean_dcf_unsamp = mean(dcf_out(dcf_out>1));
123 | 0071 if mean_dcf_unsamp>1, 
124 | 0072     warning('voronoi_area:unsamp','Numerically stable?');
125 | 0073     fprintf('mean(dcf(dcf>1))=%g\n',mean_dcf_unsamp);
126 | 0074     figure,plot(dcf_out);
127 | 0075 end
128 | 0076
129 |
Generated on Mon 26-Aug-2019 16:44:22 by m2html © 2005
130 | 131 | -------------------------------------------------------------------------------- /docs/mrf/Sequence_Design/menu.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Index for Directory mrf\Sequence_Design 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
^ Master index ^
16 | 17 |

Index for mrf\Sequence_Design

18 | 19 |

Matlab files in this directory:

20 | 22 | 23 | 24 |

Subsequent directories:

25 | 27 | 28 | 29 |
Generated by m2html © 2005
30 | 31 | -------------------------------------------------------------------------------- /docs/mrf/Sequence_Design/sequence_design_demo.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Description of sequence_design_demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 |

sequence_design_demo 20 |

21 | 22 |

PURPOSE ^

23 |
24 | 25 |

SYNOPSIS ^

26 |
This is a script file.
27 | 28 |

DESCRIPTION ^

29 |
30 | 31 | 32 |

CROSS-REFERENCE INFORMATION ^

33 | This function calls: 34 | 36 | This function is called by: 37 | 39 | 40 | 41 | 42 | 43 |

SOURCE CODE ^

44 |
0001 clc
45 | 0002 clear
46 | 0003 %This script is used as a demo for gen_MRF_sequence_pulse.m. The function
47 | 0004 %uses TR, TE and FA from Spiral_Design/Data/method_orig.mat to construct a
48 | 0005 %sequence.
49 | 0006 % 8/2019 Enlin Qian
50 | 0007 % # Copyright of the Board of Trustees of Columbia University in the City of New York
51 | 0008 
52 | 0009 %% Sequence Design
53 | 0010 addpath(genpath('.'));
54 | 0011 [kshot, dcf, ind, TR_all, FA_all, TE_all] = gen_MRF_sequence_pulseq();
55 |
Generated on Mon 26-Aug-2019 16:44:22 by m2html © 2005
56 | 57 | -------------------------------------------------------------------------------- /docs/mrf/demo_MRF.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Description of demo_MRF 6 | 7 | 8 | 9 | 10 | 11 | 12 | 15 | 16 | 17 | 18 | 19 |

demo_MRF 20 |

21 | 22 |

PURPOSE ^

23 |
% This script functions as a wrapper for all components of MRF package
24 | 25 |

SYNOPSIS ^

26 |
This is a script file.
27 | 28 |

DESCRIPTION ^

29 |
% This script functions as a wrapper for all components of MRF package
30 | 31 | 32 |

CROSS-REFERENCE INFORMATION ^

33 | This function calls: 34 | 36 | This function is called by: 37 | 39 | 40 | 41 | 42 | 43 |

SOURCE CODE ^

44 |
0001 %% This script functions as a wrapper for all components of MRF package
45 | 0002 clc
46 | 0003 clear
47 | 0004 
48 | 0005 %% Sequence Design
49 | 0006 addpath(genpath('.'));
50 | 0007 [kshot, dcf, ind, TR_all, FA_all, TE_all] = gen_MRF_sequence_pulseq();
51 | 0008 
52 | 0009 %% Image Reconstruction
53 | 0010 image_data_final_Complex = MRF_recon();
54 | 0011 
55 | 0012 %% Dictionary Simulation
56 | 0013 phis = zeros(1,1001); % the sequence starts with a 180 pulse, thus 1001 points
57 | 0014 alphas = [180, FA_all']; % all flip angles
58 | 0015 TRs = [18, TR_all'.*1000]; % all TRs, in ms
59 | 0016 T1_range=20:20:2000; 
60 | 0017 T2_range=5:20:600; 
61 | 0018 n3 = 1;
62 | 0019 Echo_Final=zeros(length(T1_range)*length(T2_range), 1000);
63 | 0020 for n1 = 1:length(T1_range)
64 | 0021     for n2 = 1:length(T2_range)
65 | 0022         disp (n3)
66 | 0023         [om_store,echoes,seq] = EPGsim_MRF(phis,alphas,TRs,[T1_range(n1), T2_range(n2)]);
67 | 0024         Echo_Final(n3, :) = Var_TE(om_store, TE_all, T2_range(n2));
68 | 0025         n3=n3+1;
69 | 0026     end
70 | 0027 end
71 | 0028 %% Dictionary Matching
72 | 0029 
73 | 0030 %% ROI Analysis Tool
74 |
Generated on Mon 26-Aug-2019 16:44:22 by m2html © 2005
75 | 76 | -------------------------------------------------------------------------------- /docs/mrf/menu.html: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | Index for Directory mrf 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
^ Master index ^
16 | 17 |

Index for mrf

18 | 19 |

Matlab files in this directory:

20 | 22 | 23 | 24 |

Subsequent directories:

25 | 27 | 28 | 29 |
Generated by m2html © 2005
30 | 31 | -------------------------------------------------------------------------------- /docs/pcode.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/docs/pcode.png -------------------------------------------------------------------------------- /docs/right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/docs/right.png -------------------------------------------------------------------------------- /docs/sgi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/docs/sgi.png -------------------------------------------------------------------------------- /docs/simulinkicon.gif: -------------------------------------------------------------------------------- 1 | version https://git-lfs.github.com/spec/v1 2 | oid sha256:10f42762604ee12698159f63c7e5494632c5fb33fe8caa9f0ac6dec1c024a812 3 | size 977 4 | -------------------------------------------------------------------------------- /docs/solaris.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/docs/solaris.png -------------------------------------------------------------------------------- /docs/up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/docs/up.png -------------------------------------------------------------------------------- /docs/windows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/docs/windows.png -------------------------------------------------------------------------------- /images/Brain_rec_all.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/images/Brain_rec_all.jpg -------------------------------------------------------------------------------- /images/MRF_FA_all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/images/MRF_FA_all.png -------------------------------------------------------------------------------- /images/MRF_TR_all.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/images/MRF_TR_all.png -------------------------------------------------------------------------------- /images/Seq file.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/images/Seq file.PNG -------------------------------------------------------------------------------- /images/Sequence plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/images/Sequence plot.png -------------------------------------------------------------------------------- /images/Sliding window.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/images/Sliding window.png -------------------------------------------------------------------------------- /images/Spiral plot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/images/Spiral plot.png -------------------------------------------------------------------------------- /images/T2_map_sphere_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/images/T2_map_sphere_1.png -------------------------------------------------------------------------------- /images/T2_map_with_ROI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/images/T2_map_with_ROI.png -------------------------------------------------------------------------------- /images/comparison.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/images/comparison.png -------------------------------------------------------------------------------- /images/dict_evo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/images/dict_evo.png -------------------------------------------------------------------------------- /images/select raw data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/images/select raw data.png -------------------------------------------------------------------------------- /images/select traj data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/images/select traj data.png -------------------------------------------------------------------------------- /mrf/Dictionary_Matching/Data/dict_example.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/mrf/Dictionary_Matching/Data/dict_example.mat -------------------------------------------------------------------------------- /mrf/Dictionary_Matching/Function/MRF_Dict_Matching.m: -------------------------------------------------------------------------------- 1 | function Par_map = MRF_Dict_Matching(MRF_dict, data) 2 | 3 | % This script uses vector dot product to find the most similar entry inside 4 | % a dictionary and retrieve the parameters from that dictionary. 5 | % INPUT 6 | % MRF_dict Dictionary file 7 | % data Reconstructed data file 8 | % 9 | % OUTPUT 10 | % Par_map An output structure that contains T1 and T2 maps 11 | % 12 | % 7/2019 Enlin Qian 13 | % # Copyright of the Board of Trustees of Columbia University in the City of New York 14 | 15 | %% Flatten image data 16 | data = abs(data); 17 | image_size = size(data); 18 | num_pixel = image_size(1)*image_size(2); 19 | num_timepts = image_size(3); 20 | data_flat = reshape(data,[num_pixel,num_timepts]); 21 | mask = ones(image_size(1:end-1)) > 0; 22 | data_flat = data_flat(mask>0,:); 23 | data_size = size(data_flat); 24 | 25 | %% Reading in dictionary 26 | dict = abs(MRF_dict.dict_SW_norm); 27 | dict_size = size(dict); 28 | 29 | %% Dictionary Matching Data Preparation 30 | dict_max = max(dict,[],2); 31 | dict_temp = abs(dict./dict_max); 32 | data_max = max(data_flat,[],2); 33 | data_temp = abs(data_flat./data_max); 34 | ip = zeros(dict_size(1),1); 35 | match_point = zeros(data_size(1),1); 36 | dict_match = zeros(data_size(1),1); 37 | dict_progress = ceil((1:1:data_size(1))./data_size(1)*100); 38 | 39 | %% Dictionary Matching 40 | fprintf('Dictionary match starts \n'); 41 | for n1 = 1:data_size(1) 42 | if mod(n1, floor((data_size(1))/10))==0 43 | fprintf('%d percent has been completed. \n' ,dict_progress(n1)); 44 | end 45 | ip = sum(abs(dict_temp.^2 - data_temp(n1, :).^2), 2); 46 | [match_point(n1),dict_match(n1)] = min(abs(ip),[],1); 47 | end 48 | 49 | %% Generate Output 50 | Par_map.T1_map = reshape(MRF_dict.lut(dict_match,1), [image_size(1), image_size(2)]); 51 | Par_map.T2_map = reshape(MRF_dict.lut(dict_match,2), [image_size(1), image_size(2)]); 52 | figure; imagesc(abs(squeeze(Par_map.T1_map))); axis equal tight; colormap hot; title('T1 map'); 53 | figure; imagesc(abs(squeeze(Par_map.T2_map))); axis equal tight; colormap hot; title('T2 map'); 54 | end 55 | -------------------------------------------------------------------------------- /mrf/Dictionary_Matching/MRF_dict_matching_demo.m: -------------------------------------------------------------------------------- 1 | % This script is used as a demo for MRF_Dict_Matching.m. The function takes in a 2 | % .mat dictionary file and .mat recontructed image file and using vector dot 3 | % product to find the most similar dictionary entry. 4 | % The .mat dictionary file can be located in Dictionary_Matching/Data, while 5 | % the reconstructed image data file is too large to be included in a Github 6 | % repository. They can be found in Google drive. Shareable link are below. 7 | % T1 Array slice: https://drive.google.com/open?id=1G4hsc00CS5ycbnQ6KQa8YDlkis_Yc-5f 8 | % T2 Array slice: https://drive.google.com/open?id=199m40D-eiPWnAMtcNZj6gIM0aDZ-VZoB 9 | % 10 | % 8/2019 Enlin Qian 11 | % # Copyright of the Board of Trustees of Columbia University in the City of New York 12 | 13 | %% Image Reconstruction 14 | addpath(genpath('.')); 15 | load('MRF_dict.mat') 16 | Par_map = MRF_Dict_Matching(MRF_dict, image_data_final_Complex); 17 | 18 | %% Some testing (sphere 1) 19 | plot(mat2gray(abs(squeeze(image_data_final_Complex(124,86,:))))) 20 | hold on 21 | plot(mat2gray(abs(MRF_dict.dict_SW_norm(3096,:)))) 22 | hold off 23 | %% Some testing (sphere 2) 24 | plot(mat2gray(abs(squeeze(image_data_final_Complex(158,96,:))))) 25 | hold on 26 | plot(mat2gray(abs(MRF_dict.dict_SW_norm(2840,:)))) 27 | hold off -------------------------------------------------------------------------------- /mrf/EPG_Dict_Sim/Data/TR_TE_FA.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/mrf/EPG_Dict_Sim/Data/TR_TE_FA.mat -------------------------------------------------------------------------------- /mrf/EPG_Dict_Sim/Function/EPG_custom.m: -------------------------------------------------------------------------------- 1 | function [om_store,echoes] = EPG_custom(seq) 2 | %[om_store,echoes] = EPG_custom(seq) 3 | % Performs EPG simulation of a general pulse sequence 4 | % INPUTS 5 | % seq: sequence struct with the required fields 6 | % seq.rf - 2 x P matrix with each column = [phi,alpha]' 7 | % seq.grad - vector of k-shifts (must be integers) 8 | % seq.events - cell of strings: 'rf','grad', or 'relax' 9 | % seq.time - vector of timing for each event in seq.events 10 | % seq.T1, seq.T2 : T1 and T2 values for relaxation 11 | % (set both to 0 for no relaxation) 12 | % OUTPUTS 13 | % 14 | % om_store - 1 x Q cell array of matrices with size (3 x K). 15 | % Each matrix is a record of configuration states (F+(k),F-(k),Z(k) 16 | % at all k's generated up to that point. Each matrix corresponds to 17 | % the elements in seq.events and seq.timing at the same index. 18 | % 19 | % echoes - output of echo information using findEchoes 20 | 21 | %% Inputs 22 | rf = seq.rf; 23 | grad = seq.grad; 24 | timing = seq.time; % in ms 25 | uniqtimes = unique(timing); 26 | events = seq.events; % 3 types of events: 'rf','grad', and 'relax' 27 | N = length(events); 28 | T1 = seq.T1; % must be populated - set to 0 for no relaxation 29 | T2 = seq.T2; % must be populated - set to 0 for no relaxation 30 | %% Initialize 31 | omega = [0 0 1].'; % initial magnetization is always at equilibrium (+z) 32 | %delk=1; %Unit dephasing 33 | rf_index = 1; 34 | om_index = 1; 35 | grad_index = 1; 36 | %% Describe pulse sequence in steps 37 | om_store = cell(1,N); 38 | for n = 1:N 39 | switch events{n} 40 | case 'rf' 41 | omega = rf_rotation(rf(1,rf_index),rf(2,rf_index))*omega; 42 | rf_index = rf_index + 1; 43 | case 'grad' 44 | omega = shift_grad(grad(grad_index),omega); 45 | grad_index = grad_index + 1; 46 | case 'relax' 47 | q = find(uniqtimes==timing(n)); 48 | tau = uniqtimes(q) - uniqtimes(q-1); 49 | omega = relax(tau,T1,T2,omega); 50 | end 51 | om_store{om_index} = omega; 52 | om_index = om_index + 1; 53 | end 54 | % Find and store echos 55 | echoes = findEchoes(seq,om_store); 56 | 57 | end 58 | 59 | -------------------------------------------------------------------------------- /mrf/EPG_Dict_Sim/Function/EPGsim_MRF.m: -------------------------------------------------------------------------------- 1 | function [Echo_Final,echoes,seq] = EPGsim_MRF(phis,alphas,TRs,TEs,T1,T2,TI) 2 | % [om_store, echoes, seq] = EPGsim_MRF(phis,alphas,TRs,rlx) 3 | % Simulates variable flip angle & variable timing EPG 4 | % Author: Gehua Tong 5 | % Date: Feb 25, 2019 6 | 7 | % Note: 8 | % (1) phis and alphas must have the same size & be in degrees 9 | % (2) TRs are in milliseconds; TRs must be the same size as phis & 10 | % alphas 11 | % (3) rlx = [T1 T2] in milliseconds(set both to zero for no relaxation) 12 | % Important: all gradients = 0, so we are always at coherence order 0 13 | % (i.e. only RF flipping and relaxation happen) 14 | 15 | N = length(TRs); 16 | seq.name = 'Variable FA & TR for MRF'; 17 | seq.rf = [phis(:)';alphas(:)']; 18 | diffTime = [zeros(1,N);repmat(TRs,2,1)]; 19 | seq.time = repelem(cumsum([0 TRs(1:end-1)]),1,3) + diffTime(:)'; 20 | seq.events = repmat({'rf','grad','relax'},1,length(TRs)); 21 | seq.grad = ones(1,length(TRs)); % add gradient 22 | seq.T1 = T1; seq.T2 = T2; 23 | 24 | %% Check if 180 pulse needs to be added 25 | if TI ~= 0 % if TI is not 0, add 180 pulse to Flip angles 26 | seq.rf = ([0,180;seq.rf'])'; 27 | seq.events = [{"rf","grad","relax"}, seq.events]; 28 | seq.time = [0,TI,TI,seq.time+TI]; 29 | seq.grad = [0,seq.grad]; 30 | end 31 | 32 | 33 | [om_store,echoes] = EPG_custom(seq); 34 | % Scale with T2 relaxation 35 | F_plus = cellfun(@(v)v(1), om_store); 36 | F_plus = F_plus(1:3:end); 37 | Echo_Final = F_plus(1,2:1:end).*exp(-TEs./T2); 38 | 39 | end -------------------------------------------------------------------------------- /mrf/EPG_Dict_Sim/Function/display_epg.m: -------------------------------------------------------------------------------- 1 | function display_epg(om_store,seq,annot,ax) 2 | %DISPLAY_EPG(om_store, seq, annot, ax) 3 | % Displays extended phase graph (EPG) given configiration state values and 4 | % pulse sequence. 5 | % 6 | % om_store: cell array of config. state history, genereated by EPG_custom.m 7 | % seq: struct containing sequence information (see EPG_custom.m) 8 | % annot: 1 or 0, whether to display k-state populations 9 | % ax: axis to display on (optional); if none, it defaults to a new figure 10 | 11 | % Created by Sairam Geethanath 12 | % Modified by Gehua Tong, Nov 14 2018 13 | 14 | kmax = size(om_store{length(om_store)},2); 15 | if kmax ~= 1 16 | kstates = -kmax+1:kmax-1; 17 | else 18 | kstates = [-1,1]; 19 | end 20 | grad_cnt =1; % indexing gradient 21 | rf_cnt=1; % indexing rf pulse 22 | timing = seq.time; 23 | uniqtimes = unique(timing); 24 | grad = seq.grad; 25 | 26 | if nargin < 4 27 | ax = gca; 28 | end 29 | %% For t==0 case - must be true for all sequences 30 | % Plot horizontal axis (k=0) 31 | plot(ax,[0 seq.time(end)],[0 0],'-k','LineWidth',1.5) 32 | hold on 33 | % Plot first RF pulse 34 | t=0.*ones(1,length(kstates)); 35 | plot(ax,t,kstates,'-','Color',[0.5 0.5 0.5],'LineWidth',3); 36 | flip = seq.rf(:,rf_cnt).'; % why .'??? 37 | text(ax,t(1),kmax-1,['(',num2str(flip(1)), '^{\circ}',',',num2str(flip(2)),'^{\circ}',')'] ,'FontSize',10); 38 | rf_cnt = rf_cnt + 1; 39 | % set axis for entire graph 40 | %axis(ax,[0 timing(end) -kmax+1 kmax-1]); 41 | %% For t > 0, plot on! 42 | for seq_read = 2:length(seq.events) % for all events after the first pulse 43 | % Get data 44 | % om_current = omega{seq_read}; 45 | om_past = om_store{seq_read -1}; 46 | 47 | % Fp - states - 48 | % Fpc = squeeze(om_current(1,:)); 49 | Fpp = squeeze(om_past(1,:)); % all the +k states and k=0 50 | 51 | % Fm - states - 52 | % Fmc = squeeze(om_current(2,:)); 53 | Fmp = squeeze(om_past(2,:)); % all the -k states and k=0 54 | 55 | % Zk - states - 56 | % Zc = squeeze(om_current(3,:)); 57 | Zp = squeeze(om_past(3,:)); % all the Z states, k>=0 58 | 59 | switch (seq.events{seq_read}) 60 | % --- Event type : RF pulse --- 61 | case 'rf' %exchanges populations among three states; depict only 2 62 | % Draw vertical line spanning all k-states 63 | t = seq.time(seq_read).*ones(1,length(kstates)); 64 | plot(ax,t,kstates,'Color',[0.5 0.5 0.5],'LineWidth',3); hold on; 65 | % Get and label RF angles 66 | flip = seq.rf(:,rf_cnt).'; 67 | text(ax,t(1),max(kmax-1,1),['(',num2str(flip(1)), '^{\circ}', ... 68 | ',',num2str(flip(2)),'^{\circ}',')'] ,'FontSize',10); 69 | % Increase RF count 70 | rf_cnt = rf_cnt + 1; 71 | 72 | % --- Event type: Gradient --- 73 | case 'grad' % important: at a given time, grad always happens before rf 74 | % Increase gradient count 75 | grad_cnt = grad_cnt + 1; 76 | %(+) Fp state plot 77 | Fpp_kstates= find(abs(Fpp)> 5*eps) -1; % find nonzero states 78 | for k=1:length(Fpp_kstates) % for each +k state 79 | % vertical locations - [last_k, last_k + grad(in units of delk)] 80 | Fp_plot = [Fpp_kstates(k) Fpp_kstates(k)+grad(grad_cnt-1)]; 81 | t = [uniqtimes(grad_cnt-1) uniqtimes(grad_cnt)]; 82 | plot(ax,t,Fp_plot,'k-');hold on; 83 | %----------------------------------------------------------------- 84 | %Anotation of config. state value (a complex number for each line) 85 | if(annot==1) 86 | intensity = round(Fpp(Fpp_kstates(k)+1)*100)/100; 87 | text(ax,t(1),Fp_plot(1)+0.5,num2str(intensity),... 88 | 'Color',[0.01 0.58 0.53],'FontSize',9); 89 | end 90 | %----------------------------------------------------------------- 91 | end 92 | %(-) Fm state plot 93 | Fmp_kstates= -1*(find(abs(Fmp)> 5*eps) -1); 94 | for k=1:length(Fmp_kstates) 95 | Fp_plot = [Fmp_kstates(k) Fmp_kstates(k)+grad(grad_cnt-1)]; 96 | t = [uniqtimes(grad_cnt-1) uniqtimes(grad_cnt)]; 97 | plot(ax,t,Fp_plot,'k-');hold on; 98 | 99 | % Echos 100 | Fmp_echo = find(Fp_plot==0,1); 101 | if ~isempty(Fmp_echo) 102 | plot(ax,t(Fmp_echo), 0, '--ro','LineWidth',2,... 103 | 'MarkerEdgeColor','k',... 104 | 'MarkerFaceColor','g',... 105 | 'MarkerSize',10); 106 | end 107 | if(annot==1) 108 | intensity = round(Fmp(-Fmp_kstates(k)+1)*100)/100; 109 | text(ax,t(1),Fp_plot(1)-0.5,num2str(intensity),... 110 | 'Color',[0.02 0.02 0.67],'FontSize',9); 111 | end 112 | end 113 | %Zp state plot 114 | Zp_kstates= (find(abs(Zp)> 5*eps) -1); 115 | for k=1:length(Zp_kstates) 116 | Fp_plot = [Zp_kstates(k) Zp_kstates(k)]; 117 | t = [uniqtimes(grad_cnt-1) uniqtimes(grad_cnt)]; 118 | plot(ax,t,Fp_plot,'--k');hold on; 119 | 120 | if(annot==1) 121 | intensity = round(Zp(Zp_kstates(k)+1)*100)/100; 122 | text(ax,t(1),Fp_plot(1),num2str(intensity),... 123 | 'Color',[1 0.47 0.42],'FontSize',9); 124 | end 125 | end 126 | end 127 | end 128 | 129 | title(ax,seq.name,'fontsize',12); 130 | xlabel(ax,'Time (ms)','fontsize',12);ylabel(ax,'k states','fontsize',12); 131 | grid(ax,'ON'); 132 | 133 | %% Plot gradient 134 | baseline = -kmax-1; 135 | M = length(uniqtimes); 136 | for m = 2:M 137 | if grad(m-1)>0 138 | col = 'g'; % positive gradient in green 139 | else 140 | col = 'r'; % negative gradient in red 141 | end 142 | area(ax,[uniqtimes(m-1),uniqtimes(m)],... 143 | [baseline+grad(m-1),baseline+grad(m-1)],'FaceColor',col,'BASEVALUE',baseline) 144 | 145 | end 146 | % kmax here is the # columns in the last omega matrix 147 | % so if kmax is 1, it means no nonzero gradients were used. 148 | if kmax == 1 149 | axis(ax,[0 timing(end) -1 1]); 150 | else 151 | axis(ax,[0 timing(end) -kmax-1-max(abs(grad)) kmax-1]); 152 | end 153 | 154 | xticks(ax,uniqtimes) 155 | -------------------------------------------------------------------------------- /mrf/EPG_Dict_Sim/Function/findEchoes.m: -------------------------------------------------------------------------------- 1 | function echoes = findEchoes(seq,om_store) 2 | %echoes = FINDECHOES(seq,om_store) 3 | % Finds echo timings and intensities given sequence seq and 4 | % om_store (the later being generated by EPG_custom.m) 5 | % 6 | % We only find the proper and unique echoes 7 | % Criteria: 8 | % (a) The F(0) component must be non-zero (>5*eps) 9 | % (b) If there are multiple echoes satisfying (a) at the same timing, 10 | % use the last value. So for grad->relax->RF, we only get F(0) after 11 | % the RF, and for grad->relax, we only get F(0) after the relaxation. 12 | % 13 | % output: echoes is N x 2 matrix where N is the number of echoes found 14 | % 1st col - timing; 2nd col - intensity (modulus of F(0)) 15 | 16 | echoes = []; 17 | timing = seq.time; 18 | for v = 1:length(om_store) 19 | if abs(om_store{v}(1,1)) > 5*eps %&& sum(rftimes == timing(v))==0 20 | newecho = [timing(v),abs(om_store{v}(1,1))]; 21 | if ~isempty(echoes) && echoes(end,1) == timing(v) 22 | % same timing - always take the 2nd one 23 | echoes = [echoes(1:end-1,:);newecho]; 24 | else 25 | echoes = [echoes;newecho]; 26 | end 27 | 28 | end 29 | end 30 | echoes = unique(echoes,'rows'); 31 | end 32 | 33 | -------------------------------------------------------------------------------- /mrf/EPG_Dict_Sim/Function/gen_MRF_dict.m: -------------------------------------------------------------------------------- 1 | function MRF_dict = gen_MRF_dict(TR, TE, FA, T1, T2, TI, kshots) 2 | % This script uses EPG to generate a dictionary based on the input of TR, 3 | % flip angle, TE, and T1/T2 range. The dictionary is processed using 4 | % sliding window to match with the image reconstruction method. The 5 | % dictionary is then normalized based on the norm. 6 | % IUPUT 7 | % TR Repetition time (s) 8 | % TE Echo time (s) 9 | % FA Flip angles (degree) 10 | % T1 T1 values for dictionary (s) 11 | % T2 T2 values for dictionary (s) 12 | % TI Inversion time, if TI=0, no inversion pulse is added. If TI~=0, 13 | % a 180 pulse with input TI value is added. (s) 14 | % kshots number of shots of spiral 15 | % 16 | % OUTPUT 17 | % MRF_dict A structure that contains a look up table for T1 and T2 values 18 | % used for each entry and a EPG simulated dictionary before 19 | % sliding window, after sliding window, and after being 20 | % normalized by the norm. 21 | % 22 | % 7/2019 Enlin Qian 23 | % # Copyright of the Board of Trustees of Columbia University in the City of New York 24 | 25 | 26 | %% Prepare variables for dictionary simulation 27 | T1 = T1.*1000; 28 | T2 = T2.*1000; 29 | TRs = TR'.*1000; 30 | TEs = TE'.*1000; 31 | TI = TI.*1000; 32 | num_TRs = size(TRs, 2); 33 | num_dict_entry = length(T1)*length(T2); 34 | dict_size = [num_dict_entry, num_TRs]; 35 | phis = zeros(1, num_TRs); 36 | alphas = FA'; 37 | Echo_Final = zeros(dict_size); 38 | dict_lut = zeros(num_dict_entry, 2); 39 | dict_SW = zeros(dict_size); 40 | dict_SW_norm = zeros(dict_size); 41 | 42 | %% Generate EPG dictionary 43 | n3 = 1; 44 | dict_progress = ceil(((1:1:num_dict_entry)./num_dict_entry)*100); 45 | for n1 = 1:length(T2) 46 | for n2 = 1:length(T1) 47 | if mod(n3, floor(num_dict_entry/10))==0 48 | fprintf('%d percent has been completed. \n' ,dict_progress(n3)); 49 | end 50 | [Echo_Final(n3,:),echoes,seq] = EPGsim_MRF(phis,alphas,TRs,TEs,T1(n2),T2(n1),TI); 51 | dict_lut(n3, 1) = T1(n2); 52 | dict_lut(n3, 2) = T2(n1); 53 | n3=n3+1; 54 | end 55 | end 56 | 57 | MRF_dict.lut = dict_lut; 58 | MRF_dict.dict = Echo_Final; 59 | clear dict_lut dict_progress 60 | 61 | %% Sliding window 62 | kshot_win = floor(kshots.*0.5); 63 | for n4 = 1: num_TRs 64 | SelectedRange = (n4-kshot_win-1):(n4+kshot_win-2); 65 | SelectedRange = SelectedRange(SelectedRange > 0 & SelectedRange <= num_TRs); 66 | dict_SW(:, n4) = sum(Echo_Final(:,SelectedRange),2); 67 | end 68 | MRF_dict.dict_SW = dict_SW; 69 | clear Echo_Final 70 | 71 | %% Normalized by the norm 72 | dict_norm = zeros(num_dict_entry, 1); 73 | for n5 = 1: num_dict_entry 74 | dict_norm(n5) = norm(dict_SW(n5,:)); 75 | dict_SW_norm(n5, :) = dict_SW(n5, :) / dict_norm(n5); 76 | end 77 | % dict_SW_norm = dict_SW_norm(:, 2:end); 78 | MRF_dict.dict_SW_norm = dict_SW_norm; 79 | clear dict_SW_norm dict_SW 80 | 81 | end -------------------------------------------------------------------------------- /mrf/EPG_Dict_Sim/Function/relax.m: -------------------------------------------------------------------------------- 1 | function omega_new = relax(tau,T1,T2,omega) 2 | %relax(tau,T1,T2,omega) 3 | %relax.m: updates omega with relaxation effects 4 | % INPUTS 5 | % tau: duration of relaxation in ms 6 | % T1,T2: time constants in ms 7 | % omega: the input (3 x n) matrix of k-states 8 | 9 | % Gehua Tong, Oct 7 2018 10 | 11 | if size(omega,1) ~= 3 12 | error('Size of k-state matrix incorrect. Input needs to be (3 x n)') 13 | end 14 | if T1 ~= 0 && T2 ~=0 15 | E1 = exp(-tau/T1); 16 | E2 = exp(-tau/T2); 17 | Emat = [E2 0 0; 18 | 0 E2 0; 19 | 0 0 E1]; 20 | omega_new = Emat*omega; 21 | omega_new(:,1) = omega_new(:,1) + [0,0,1-E1]'; % M0 = 1 default 22 | else 23 | omega_new = omega; 24 | end 25 | 26 | end 27 | 28 | -------------------------------------------------------------------------------- /mrf/EPG_Dict_Sim/Function/rf_rotation.m: -------------------------------------------------------------------------------- 1 | function T_phi_alpha = rf_rotation (phi,alpha) 2 | %RF_ROTATION(phi,alpha) 3 | % 3 x 3 rotation matrix in complex representation for RF pulse 4 | % with phase = phi (from the x axis) and filp angle = alpha 5 | % See Weigel 2015, Eq. 15 6 | 7 | phi = deg2rad(phi); 8 | alpha = deg2rad(alpha); 9 | 10 | T_phi_alpha = [cos(alpha/2).^2 exp(2*1i*phi)*sin(alpha/2).^2 -1i*exp(1i*phi)*sin(alpha); 11 | exp(-2*1i*phi)*sin(alpha/2).^2 cos(alpha/2).^2 1i*exp(-1i*phi)*sin(alpha); 12 | -1i*0.5.*exp(-1i*phi)* sin(alpha) 1i*0.5.*exp(1i*phi)* sin(alpha) cos(alpha)]; -------------------------------------------------------------------------------- /mrf/EPG_Dict_Sim/Function/shift_grad.m: -------------------------------------------------------------------------------- 1 | function omega_new = shift_grad(delk,omega) 2 | %SHIFT_GRAD(delk,omega) 3 | % Modified by: Gehua Tong 4 | % Date: 15 Oct 2018 5 | % Modified by: Sachin A B Anchan 6 | % Date: 30 June 2014 7 | % Shift applies to only F+ and F-* as it does not dephase in z 8 | % check size of previous omega to determine the effect - test multiple 9 | % times 10 | 11 | % delk: integer indicating discrete change in k 12 | % omega: inputted omega matrix (with columns of [F+,F-,Z]') 13 | 14 | [m,n] = size(omega); %previous time point 15 | % if(m~=3) 16 | % error('Still implementing equation 26, please use 3xk'); 17 | % end 18 | if delk == 0 19 | omega_new = omega; 20 | else 21 | if(n>1) % typical case: an RF pulse has happened and we have transverse components 22 | F = [fliplr(omega(1,:)) squeeze((omega(2,2:end)))]; %arrange to make it like eq 27 23 | % Negative shift 24 | if(delk < 0) 25 | F = [zeros(1,abs(delk)) F]; %negative shift moves the population downwards - 2n-1 + delk 26 | Z = [squeeze(omega(3,:)) zeros(1,abs(delk))]; %No change in z due to grads 27 | Fp = [fliplr(F(1:n)) zeros(1,abs(delk))]; 28 | Fm = F(n:end); 29 | % Here, V(k=1) moves into V'(k=+0), 30 | % so V'(k=-0) is the conjugate of V'(k=+0) 31 | Fm(1) = conj(Fm(1)); 32 | % Positive shift 33 | else 34 | F = [F zeros(1,delk)]; %positive shift pushes the population upwards 35 | Z = [squeeze(omega(3,:)) zeros(1,delk)]; 36 | Fp = fliplr(F(1:n+delk)); 37 | Fm = [F(n+delk:end) zeros(1,delk)]; 38 | % Here, V(k=-1) moves into V'(k=-0), 39 | % so V'(k=+0) is the conjugate of V'(k=-0) 40 | Fp(1) = conj(Fp(1)); 41 | end 42 | 43 | 44 | else % n = 1; this happens if pulse sequence starts with nonzero transverse 45 | % components and no RF pulse at t = 0 - gradient happens first 46 | % omega(1) (=F+(0)) and omega(2)(= F-(0)) must be complex conjugates!!! 47 | % omega(3) = Z(0) 48 | if(delk > 0) 49 | Fp = [zeros(1,abs(delk)) omega(1)]; 50 | Fm = [0 zeros(1,abs(delk))]; 51 | Z = [squeeze(omega(3)) zeros(1,abs(delk))]; 52 | else 53 | Fp = [0 zeros(1,abs(delk))]; 54 | Fm = [zeros(1,abs(delk)) omega(2)]; 55 | Z = [squeeze(omega(3)) zeros(1,abs(delk))]; 56 | 57 | end 58 | end 59 | 60 | omega_new = [Fp;Fm;Z]; 61 | end 62 | -------------------------------------------------------------------------------- /mrf/EPG_Dict_Sim/gen_MRF_dict_demo.m: -------------------------------------------------------------------------------- 1 | clc 2 | clear 3 | 4 | %This script is used as a demo for dict_sim_MRF.m. All TR, FA, and TE are 5 | %loaded based on the sequence generated in Sequence Design part. 6 | % 7/2019 Enlin Qian 7 | % # Copyright of the Board of Trustees of Columbia University in the City of New York 8 | addpath(genpath('.')); 9 | load('TR_TE_FA.mat') 10 | %% Dictionary Simulation 11 | % Modified based on ISMRM/NIST phantom specs - T1 array 12 | T1 = 0.02:0.005:0.1; 13 | T1 = [T1 0.1:0.01:0.5]; 14 | T1 = [T1 0.5:0.2:2]; 15 | % Modified based on ISMRM/NIST phantom specs - T2 array 16 | T2 = 0.005:0.002:0.02; 17 | T2 = [T2 0.02:0.01:0.1]; 18 | T2 = [T2 0.1:0.025:0.3]; 19 | T2 = [T2 0.3:0.1:1]; 20 | TI = 0.018; 21 | kshots=48; 22 | MRF_dict = gen_MRF_dict(TR_all, TE_all, FA_all, T1, T2, TI, kshots); 23 | 24 | -------------------------------------------------------------------------------- /mrf/Image_Reconstruction/Data/K_Traj4rec.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/mrf/Image_Reconstruction/Data/K_Traj4rec.mat -------------------------------------------------------------------------------- /mrf/Image_Reconstruction/Function/Complex_Chan_Combining.m: -------------------------------------------------------------------------------- 1 | function coil_filter = Complex_Chan_Combining(image1) 2 | % This script correct phase differences in each coil using method in [1]. 3 | % IUPUT 4 | % image1 reconstructed image 5 | % 6 | % OUTPUT 7 | % coil_filter filter used to correct phase from each coil 8 | % 9 | % [1] Roemer P, Edelstein W, Hayes C, Souza S, Mueller O. The NMR phased 10 | % array. Magn Reson Med. 1990;16(2):192-225. doi:10.1002/mrm.1910160203 11 | image1 = permute(image1,[1 2 4 3]); 12 | [Nx, Ny, Nt, C] = size(image1); 13 | filtsize = 5; 14 | Rs = zeros(Nx, Ny, C, C); 15 | 16 | % Correlation matrix 17 | for n1 = 1:C 18 | for n2 = 1:C 19 | for n3 = 1:Nt 20 | Rs(:,:,n1,n2) = Rs(:,:,n1,n2) + filter2(ones(filtsize),... 21 | image1(:,:,n3,n1).*conj(image1(:,:,n3,n2)),'same'); 22 | end 23 | end 24 | end 25 | 26 | % Get filter 27 | Rs = permute(Rs,[3,4,1,2]); 28 | Rs = Rs(:,:,:); 29 | [U,~,~] = pagesvd(Rs); % Page-wise singular value decomposition for speed 30 | coil_filter = squeeze(U(:,1,:)); 31 | coil_filter = permute(coil_filter,[2 1]); 32 | coil_filter = reshape(coil_filter, Nx, Ny, C); 33 | 34 | end -------------------------------------------------------------------------------- /mrf/Image_Reconstruction/Function/MRF_recon.m: -------------------------------------------------------------------------------- 1 | function image_data_final_Complex = MRF_recon() 2 | % This script uses sliding window method and complex coil combination to 3 | % reconstruct .dat raw data and trajectory file. This script requires MiRT 4 | % toolbox, visit their websites for more information: 5 | % https://web.eecs.umich.edu/~fessler/code/ 6 | % IUPUT 7 | % None User does not need to input any parameter. The script will 8 | % ask for raw data and trajectory file. The trajectory file is 9 | % attached as K_Traj4rec.mat in Sample_Data folder. 10 | % 11 | % OUTPUT 12 | % image_data_final_Complex Reconstructed images. 13 | % 7/2019 Enlin Qian 14 | % # Copyright of the Board of Trustees of Columbia University in the City of New York 15 | % 16 | % some variables: dim1: size of original raw data 17 | % dim2: size of concatenated raw data 18 | % dim3: size of ktrajectory data 19 | % dim4: size of concatenated raw data after cutting rewinders 20 | 21 | 22 | %% This stage takes in a .dat raw data file and outputs .mat file. 23 | acquired_raw_data = dat2mat_nonCart();%extract .dat information 24 | %the second dim of acquired data is acquired points, 4th dim is partition number 25 | dim1 = size(acquired_raw_data); 26 | acquired_points = dim1(2); 27 | acquired_raw_data_con = zeros(dim1(1)*dim1(4),dim1(2),dim1(3));%preallocate concatenated raw data 28 | for n1 = 1:dim1(2) 29 | for n2 = 1:dim1(3) 30 | acquired_raw_data_con(:,n1,n2) = [acquired_raw_data(:,n1,n2,1);... 31 | acquired_raw_data(:,n1,n2,2)];%concatenate second partition with first partition 32 | end 33 | end 34 | dim2 = size(acquired_raw_data_con); 35 | 36 | %% Stage 2, load spiral data 37 | [baseFileName,folder] = uigetfile('*.mat','Pick the trajectory file'); 38 | fullFileName = fullfile(folder, baseFileName); 39 | load(fullFileName) 40 | acquired_raw_data_con = acquired_raw_data_con(ind(1,:),:,:); % index based on variable "ind" 41 | dim3 = size(traj); 42 | kshots = size(ind,1); 43 | ktraj = repmat(traj,[1,ceil(acquired_points/kshots),1]); 44 | ktraj = ktraj(:,1:acquired_points,:);%repmat spiral data, check first spiral and 49 spiral 45 | 46 | %% Stage 3, multiply dcf with raw data 47 | dcf_reshape = dcf(1:dim3(1)); 48 | acquired_raw_data_final = bsxfun(@times,acquired_raw_data_con,dcf_reshape'); 49 | 50 | %% Stage 4, sliding windows reconstruction 51 | Jd = [5,5]; Nd = [256,256]; Kd =Nd.*2; 52 | image_data_final = zeros(Nd(1),Nd(2),dim2(3),acquired_points); 53 | image_data_final_Complex = zeros(Nd(1),Nd(2),acquired_points); 54 | kshot_win = floor(kshots.*0.5); 55 | % setting up parameters for nufft 56 | 57 | for n4 = 1:acquired_points%total # of images generated by sliding windows 58 | SelectedRange = (n4-kshot_win):(n4+kshot_win-1); 59 | SelectedRange = SelectedRange(SelectedRange > 0 & SelectedRange <= acquired_points); 60 | ktraj_temp = ktraj(:,SelectedRange,:); %recounstruct using full 48 spirals or partial spirals, trajectory has to be between 0-0.5 61 | ktraj_temp = reshape(ktraj_temp,[],2); 62 | om = squeeze(ktraj_temp.*2.*pi); 63 | st = nufft_init(om, Nd, Jd, Kd, Nd/2, 'minmax:kb'); 64 | for n5 = 1:dim2(3) 65 | fprintf('Reconstructing timepoints %d coil %d \n', n4, n5) 66 | acquired_raw_data_temp = acquired_raw_data_final(:,SelectedRange,n5); 67 | acquired_raw_data_temp = reshape(acquired_raw_data_temp,[],1); 68 | image_data_final(:,:,n5,n4) = nufft_adj(acquired_raw_data_temp,st); 69 | end 70 | end 71 | 72 | %% Complex coil combining 73 | for n6 = 1:acquired_points 74 | fprintf('Complex channel combining for timepoints %d \n', n6) 75 | sens = Complex_Chan_Combining(image_data_final(:,:,:,n6)); 76 | imtemp2 = squeeze(sum(bsxfun(@times,conj(sens),image_data_final(:,:,:,n6)),3)); 77 | 78 | % figure(101); 79 | % imagesc(abs(imtemp2));xlabel(num2str(n4)); 80 | % caxis auto; 81 | % axis equal tight; 82 | % colormap gray; 83 | % drawnow; 84 | image_data_final_Complex(:, :, n6) = imtemp2; 85 | end 86 | end 87 | -------------------------------------------------------------------------------- /mrf/Image_Reconstruction/Function/dat2mat_nonCart.m: -------------------------------------------------------------------------------- 1 | function [kspace_data]= dat2mat_nonCart() 2 | % This script reads in .dat raw data and convert it to kspace data. 3 | % IUPUT 4 | % None the user is asked to select a .dat raw data file 5 | % 6 | % OUTPUT 7 | % ksapce_data kspace data 8 | % 9 | % Created 8/2013 Sairam Geethanath 10 | % Modified 7/2019 Enlin Qian 11 | % # Copyright of the Board of Trustees of Columbia University in the City of New York 12 | 13 | %% Obtain the file 14 | [Filename,Pathname] = uigetfile('*.dat','Pick the raw data file'); 15 | 16 | %% Read data using mapVBVD 17 | twix_obj = mapVBVDVE(fullfile(Pathname,Filename)); 18 | 19 | % image_obj = twix_obj.image; %Body coil 20 | if(~iscell(twix_obj)) 21 | % if ( size(twix_obj.image) ==1) 22 | image_obj = twix_obj.image; 23 | else 24 | image_obj = twix_obj{2}.image; 25 | end 26 | 27 | sizeData = image_obj.sqzSize; %kx, nch, ky, slices, partitions 28 | dimsData = image_obj.sqzDims; 29 | dimsallData = image_obj.dataDims; 30 | 31 | %% Concatenate slices and partitions together and has a N x N acquisition set 32 | kspace_data = zeros(sizeData); 33 | 34 | sl = 1; 35 | 36 | partitions=1; 37 | 38 | %% Determine k-space shift to the center 39 | % temp = squeeze(image_obj(:,1,:,round(sizeData(4)/2),round(sizeData(5)/2))); 40 | % [~,idx] = max(abs(temp(:))); 41 | % [idx,idy] = ind2sub(size(temp),idx); 42 | 43 | %% 44 | 45 | 46 | tic; 47 | % for nch=1:size(kspace_data,2) %number of channels 48 | 49 | % for narms=1:size(kspace_data,1) %number of arms 50 | kspace_data = squeeze(image_obj()); 51 | 52 | % temp = squeeze(image_obj(:,nch,:,sl,partitions)); 53 | % temp = circshift(temp, [round(size(temp,1)/2) - idx,round(size(temp,2)/2) - idy ]); 54 | % trunc_part =round(0.5 .*(size(temp,1) - size(temp,2))); 55 | % temp = squeeze(temp(trunc_part+1:end-trunc_part,:)); 56 | % 57 | % kspace_data(:,:,nslices,nch) = temp; 58 | 59 | 60 | 61 | 62 | % end 63 | toc; 64 | 65 | kspace_data = permute(kspace_data,[1 3 2 4]); %kx, ky, slices, partitions, nch 66 | kspace_data = squeeze(kspace_data); 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /mrf/Image_Reconstruction/Function/read_twix_hdr.m: -------------------------------------------------------------------------------- 1 | function [prot,rstraj] = read_twix_hdr(fid) 2 | % This function reads raw data header information from siemens MRI scanners 3 | % (currently VB and VD software versions are supported and tested). 4 | % 5 | % Created 11/2014 Philipp Ehses (philipp.ehses@tuebingen.mpg.de) 6 | 7 | nbuffers = fread(fid, 1,'uint32'); 8 | 9 | prot = []; 10 | for b=1:nbuffers 11 | namesz = 0; 12 | byte = 1; 13 | while byte~=0 % look for NULL-character 14 | byte = fread(fid, 1, 'uint8'); 15 | namesz = namesz+1; 16 | end 17 | fseek(fid,-namesz,'cof'); 18 | bufname = fread(fid,namesz,'char=>char').'; 19 | bufname(end) = []; % delete NULL character 20 | buflen = fread(fid, 1,'uint32'); 21 | buffer = fread(fid, buflen, 'char=>char').'; 22 | buffer = regexprep(buffer,'\n\s*\n',''); % delete empty lines 23 | prot.(bufname) = parse_buffer(buffer); 24 | end 25 | 26 | if nargout>1 27 | rstraj = []; 28 | if isfield(prot.Meas,'alRegridMode') && prot.Meas.alRegridMode(1)>1 29 | ncol = prot.Meas.alRegridDestSamples(1); 30 | dwelltime = prot.Meas.aflRegridADCDuration(1)/ncol; 31 | gr_adc = zeros(1,ncol,'single'); 32 | time_adc = prot.Meas.alRegridDelaySamplesTime(1) + dwelltime * (0.5:ncol); 33 | ixUp = time_adc <= prot.Meas.alRegridRampupTime(1); 34 | ixFlat = (time_adc <= prot.Meas.alRegridRampupTime(1)+prot.Meas.alRegridFlattopTime(1)) & ~ixUp; 35 | ixDn = ~ixUp & ~ixFlat; 36 | gr_adc(ixFlat) = 1; 37 | if prot.Meas.alRegridMode(1) == 2 38 | % trapezoidal gradient 39 | gr_adc(ixUp) = time_adc(ixUp)/prot.Meas.alRegridRampupTime(1); 40 | gr_adc(ixDn) = 1 - (time_adc(ixDn)-prot.Meas.alRegridRampupTime(1)-prot.Meas.alRegridFlattopTime(1))/prot.Meas.alRegridRampdownTime(1); 41 | elseif prot.Meas.alRegridMode(1) == 4 42 | % sinusoidal gradient 43 | gr_adc(ixUp) = sin(pi/2*time_adc(ixUp)/prot.Meas.alRegridRampupTime(1)); 44 | gr_adc(ixDn) = sin(pi/2*(1+(time_adc(ixDn)-prot.Meas.alRegridRampupTime(1)-prot.Meas.alRegridFlattopTime(1))/prot.Meas.alRegridRampdownTime(1))); 45 | else 46 | warning('regridding mode unknown'); 47 | return; 48 | end 49 | rstraj = (cumsum(gr_adc(:)) - ncol/2)/sum(gr_adc(:)); 50 | rstraj = rstraj - rstraj(ncol/2+1); 51 | end 52 | end 53 | 54 | end 55 | 56 | function prot = parse_buffer(buffer) 57 | [ascconv,xprot] = regexp(buffer,'### ASCCONV BEGIN[^\n]*\n(.*)\s### ASCCONV END ###','tokens','split'); 58 | 59 | if ~isempty(ascconv) 60 | ascconv = ascconv{:}{:}; 61 | prot = parse_ascconv(ascconv); 62 | else 63 | prot = struct(); 64 | end 65 | 66 | if ~isempty(xprot) 67 | xprot = xprot{:}; 68 | xprot = parse_xprot(xprot); 69 | if isstruct(xprot) 70 | name = cat(1,fieldnames(prot),fieldnames(xprot)); 71 | val = cat(1,struct2cell(prot),struct2cell(xprot)); 72 | [~,ix] = unique(name); 73 | prot = cell2struct(val(ix),name(ix)); 74 | end 75 | end 76 | end 77 | 78 | function xprot = parse_xprot(buffer) 79 | xprot = []; 80 | tokens = regexp(buffer, '\s*{([^}]*)','tokens'); 81 | tokens = [tokens, regexp(buffer, '\s*{\s*(\s*[0-9]*)?\s*([^}]*)','tokens')]; 82 | for m=1:numel(tokens) 83 | name = char(tokens{m}(1)); 84 | % field name has to start with letter 85 | if (~isletter(name(1))) 86 | name = strcat('x', name); 87 | end 88 | 89 | value = char(strtrim(regexprep(tokens{m}(end), '("*)|( *<\w*> *[^\n]*)', ''))); 90 | value = regexprep(value, '\s*', ' '); 91 | 92 | try %#ok 93 | value = eval(['[' value ']']); % inlined str2num() 94 | end 95 | 96 | xprot.(name) = value; 97 | end 98 | end 99 | 100 | function mrprot = parse_ascconv(buffer) 101 | mrprot = []; 102 | % [mv] was: vararray = regexp(buffer,'(?\S*)\s*=\s(?\S*)','names'); 103 | vararray = regexp(buffer,'(?\S*)\s*=\s*(?\S*)','names'); 104 | i = 0; 105 | for var=vararray 106 | try 107 | value = eval(['[' var.value ']']); % inlined str2num() 108 | catch 109 | value = var.value; 110 | end 111 | 112 | % now split array name and index (if present) 113 | v = regexp(var.name,'(?\w*)\[(?[0-9]*)\]|(?\w*)','names'); 114 | 115 | cnt = 0; 116 | tmp = cell(2,numel(v)); 117 | 118 | breaked = false; 119 | for k=1:numel(v) 120 | if ~isletter(v(k).name(1)) 121 | breaked = true; 122 | break; 123 | end 124 | cnt = cnt+1; 125 | tmp{1,cnt} = '.'; 126 | tmp{2,cnt} = v(k).name; 127 | 128 | if ~isempty(v(k).ix) 129 | cnt = cnt+1; 130 | tmp{1,cnt} = '{}'; 131 | tmp{2,cnt}{1} = 1 + str2double(v(k).ix); 132 | end 133 | end 134 | if ~breaked && ~isempty(tmp) 135 | S = substruct(tmp{:}); 136 | 137 | %% TODO _ delete later - only for DEBUG 138 | 139 | % var_name='mrprot_hat'; 140 | % for k =1:length(S) 141 | % if(strcmp(S(k).type,'.')) 142 | % var_name = [var_name,S(k).type,S(k).subs]; 143 | % elseif(strcmp(S(k).type,'{}')) 144 | % var_name = [var_name,'{',num2str(cell2mat(S(k).subs)),'}']; 145 | % end 146 | % 147 | % end 148 | % evalin('caller', [var_name,'=',num2str(value)]); 149 | %% 150 | mrprot = subsasgn(mrprot,S,value); 151 | end 152 | i = i + 1; 153 | end 154 | end 155 | 156 | -------------------------------------------------------------------------------- /mrf/Image_Reconstruction/MRF_recon_demo.m: -------------------------------------------------------------------------------- 1 | clc 2 | clear 3 | %This script is used as a demo for MRF_recon.m. The function takes in a 4 | %.dat raw data file and .mat trajectory file and using sliding windown 5 | %reconstruction and complex coil combination to reconstruct the image. 6 | %These two files can both be found under Image_Reconstruction/Data 7 | % 8/2019 Enlin Qian 8 | % # Copyright of the Board of Trustees of Columbia University in the City of New York 9 | 10 | %% Image Reconstruction 11 | addpath(genpath('.')); 12 | image_data_final_Complex = MRF_recon(); -------------------------------------------------------------------------------- /mrf/ROI_analysis_tool/Data/T1_map.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/mrf/ROI_analysis_tool/Data/T1_map.mat -------------------------------------------------------------------------------- /mrf/ROI_analysis_tool/Data/T1_map_rot45.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/mrf/ROI_analysis_tool/Data/T1_map_rot45.mat -------------------------------------------------------------------------------- /mrf/ROI_analysis_tool/Data/T2_map.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/mrf/ROI_analysis_tool/Data/T2_map.mat -------------------------------------------------------------------------------- /mrf/ROI_analysis_tool/Data/T2_map_rot30.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/mrf/ROI_analysis_tool/Data/T2_map_rot30.mat -------------------------------------------------------------------------------- /mrf/ROI_analysis_tool/Function/Circle_Analysis.m: -------------------------------------------------------------------------------- 1 | function [CircleMap, PointsIndex] = Circle_Analysis(Center, Radius, ImXSize, ImYSize) 2 | % Input center, radius, and map size and return index of pixels inside the 3 | % circle. 4 | % INPUT 5 | % Center Center of circle [x, y] 6 | % Radius Radius of circle (in pixels) 7 | % ImXSize Image size along x direction 8 | % ImYSize Image size along y direction 9 | % 10 | % OUTPUT 11 | % CircleMap Binary map for each circle 12 | % PointsIndex Pixel index for all pixels inside input circle 13 | % 14 | % 7/2019 Enlin Qian 15 | % # Copyright of the Board of Trustees of Columbia University in the City of New York 16 | % (x,y) = (colum, row) 17 | [X,Y] = meshgrid(1:ImXSize,1:ImYSize); 18 | DistanceMap = sqrt((X-Center(1)).^2+(Y-Center(2)).^2); 19 | CircleMap = DistanceMap<=Radius; 20 | PointsIndex = find(CircleMap); 21 | end -------------------------------------------------------------------------------- /mrf/ROI_analysis_tool/Function/NIST_ROI_ana.m: -------------------------------------------------------------------------------- 1 | function sphere_par = NIST_ROI_ana(map_data, map_type, map_size, fov) 2 | % Input map mat file and return ROI analysis of a ISMRM/NIST phantom, all 3 | % 14 spheres are detected. Their locations, radius, mean, and std are 4 | % returned in correct order. 5 | % INPUT 6 | % map_data parameter map, unit should be in second 7 | % map_type type of map (T1 or T2) 8 | % map_size size of map, for example, 128 means the map size is 128x128 9 | % fov field of view [mm] 10 | % 11 | % OUTPUT 12 | % sphere_par circle parameters. It has four fields which contain sphere 13 | % locations, radius, mean, and std in correct order. 14 | % 15 | % 7/2019 Enlin Qian 16 | % # Copyright of the Board of Trustees of Columbia University in the City of New York 17 | 18 | %% Check inputs 19 | if ~exist('map_data','var'), error('No map data is found'); end 20 | if ~exist('map_type','var'), error('No map type is found'); end 21 | if map_size<1, warning('dcs:map_size','map_size(=%g)<1',map_size); input(''); end 22 | if fov<1, warning('dcs:fov','fov(=%g)<1',fov); input(''); end 23 | 24 | %% Load standard parameters for ISMRM/NIST phantom 25 | NIST_std_par = gen_NIST_std_par(map_type, map_size, fov); 26 | 27 | %% Threshold Sphere 1 based on intensity 28 | map_binary = map_data>=NIST_std_par.intensity_range(1) & map_data<=NIST_std_par.intensity_range(2); 29 | 30 | %% Initial guess of circles to find Sphere 1 31 | [guess_center,guess_radii] = imfindcircles(map_binary,NIST_std_par.sphere_radius,... 32 | 'Sensitivity',0.95); 33 | 34 | %% Visualize initial guess of Sphere 1 35 | figure;imagesc(map_data); colormap hot; axis equal tight; 36 | viscircles(guess_center, guess_radii); 37 | 38 | %% If only 1 sphere is detected, if yes, use the circle, if no, pick the one closest to true value 39 | num_guess = size(guess_center, 1); 40 | if num_guess == 1 41 | Sphere1_center = guess_center; 42 | Sphere1_radii = guess_radii; 43 | else 44 | Mean_all = zeros(num_guess, 1); 45 | for n = 1: num_guess 46 | [~, PointsIndex] = Circle_Analysis(guess_center(n, :), guess_radii(n), map_size, map_size); 47 | Mean_all(n) = mean(map_data(PointsIndex)); 48 | end 49 | [~, Index] = min(abs(Mean_all - NIST_std_par.true_value(1))); 50 | Sphere1_center = guess_center(Index, :); 51 | Sphere1_radii = guess_radii(Index); 52 | end 53 | 54 | %% Find all template sphere locations based on Sphere 1 location 55 | NIST_sphere_loc = gen_NIST_sphere_loc(map_type, map_size, fov, Sphere1_center); 56 | 57 | %% Visualize the template (without rotation) 58 | % figure;imagesc(map_data); colormap hot; axis equal tight; 59 | % viscircles(NIST_sphere_loc.template_loc, repmat(Sphere1_radii, NIST_sphere_loc.num_spheres, 1)); 60 | 61 | %% Calculate transformation matrix for rotation 62 | rot_center = NIST_sphere_loc.temp_rot_center; 63 | template_vec = [NIST_sphere_loc.template_Sphere1_loc(1)-NIST_sphere_loc.temp_rot_center(1),... 64 | NIST_sphere_loc.template_Sphere1_loc(2)-NIST_sphere_loc.temp_rot_center(2)]; % Vector for template 65 | map_vec = [Sphere1_center(1)-rot_center(1), Sphere1_center(2)-rot_center(2)]; % Vector for image data 66 | rot_angle = acosd(dot(template_vec,map_vec)/(norm(template_vec)*norm(map_vec))); % Find the angle between two vectors 67 | trans_matrix = [cosd(rot_angle), -sind(rot_angle); 68 | sind(rot_angle), cosd(rot_angle)]; 69 | 70 | %% Multiply the template with the transformation matirx 71 | map_loc = (NIST_sphere_loc.template_loc - rot_center) * trans_matrix + rot_center; % rotation is respect to origin 72 | map_radii = repmat(Sphere1_radii, NIST_sphere_loc.num_spheres, 1); 73 | 74 | %% Visualize the new locations with rotation fixed 75 | figure;imagesc(map_data); colormap hot; axis equal tight; 76 | viscircles(map_loc, map_radii); 77 | 78 | %% Calculate mean and SD for each sphere 79 | for nx = 1: NIST_std_par.num_spheres 80 | [~, PointsIndex] = Circle_Analysis(map_loc(nx, :), map_radii(nx), map_size, map_size); 81 | Mean_all_sphere(nx) = mean(map_data(PointsIndex)); 82 | std_all_sphere(nx) = std(map_data(PointsIndex)); 83 | end 84 | 85 | %% Construct output variable circle_par 86 | sphere_par.all_sphere_loc = map_loc; 87 | sphere_par.all_sphere_rad = map_radii; 88 | sphere_par.all_sphere_mean = Mean_all_sphere'; 89 | sphere_par.all_sphere_std = std_all_sphere'; 90 | -------------------------------------------------------------------------------- /mrf/ROI_analysis_tool/Function/gen_NIST_sphere_loc.m: -------------------------------------------------------------------------------- 1 | function NIST_sphere_loc = gen_NIST_sphere_loc(map_type, map_size, fov, Sphere1_center) 2 | % Input map parameters and Sphere 1 loc to generate a map that finds all 3 | % locations of other spheres. 4 | % INPUT 5 | % map_type type of map (T1 or T2) 6 | % map_size size of map, for example, 128 means the map size is 128x128 7 | % fov field of view [mm] 8 | % Sphere1_loc centers of sphere 1 (x, y) 9 | % 10 | % OUTPUT 11 | % NIST_sphere_loc sphere locations for all spheres 12 | % 13 | % 7/2019 Enlin Qian 14 | % # Copyright of the Board of Trustees of Columbia University in the City of New York 15 | NIST_sphere_loc.num_spheres = 14; 16 | NIST_sphere_loc.voxel_size = fov/map_size; % unit in mm/voxel 17 | NIST_sphere_loc.temp_rot_center = [map_size/2, map_size/2]; % unit in pixel 18 | switch(map_type) 19 | case 'T1' 20 | NIST_sphere_loc.dist_map = [0, 31.324, 58.893, 81.810, 95.898, 100.317,... 21 | 95.991, 81.077, 58.860, 31.451, 35.380, 35.931, 73.124, 73.157]; % unit in mm 22 | NIST_sphere_loc.ang_map = [0, 70.0850, 53.3538, 35.3270, 16.9426, -0.6324,... 23 | -18.7705, -36.9326, -56.4287, -72.7011, 33.6653, -34.0284, 14.9729, -16.4091]; % unit in degree 24 | 25 | case 'T2' 26 | NIST_sphere_loc.dist_map = [0, 31.547, 58.642, 80.697, 95.713, 99.812,... 27 | 96.050, 80.936, 58.824, 30.036, 36.204, 35.882, 73.002, 72.552]; % unit in mm 28 | NIST_sphere_loc.ang_map = [0, 71.4899, 54.0302, 35.7043, 17.5603, -0.1549,... 29 | -18.3830, -35.8010, -54.2831, -70.3638, 33.1854, -33.0284, 15.2130, -16.2861]; % unit in degree 30 | end 31 | 32 | %% convert mm to voxel based on map_size and fov 33 | NIST_sphere_loc.dist_map = NIST_sphere_loc.dist_map/NIST_sphere_loc.voxel_size; % convert to unit in voxel 34 | 35 | %% Use Sphere 1 loc to calculate template Sphere1 loc 36 | dist_Sphere12center = sqrt((Sphere1_center(1)- NIST_sphere_loc.temp_rot_center(1))^2+... 37 | (Sphere1_center(2)- NIST_sphere_loc.temp_rot_center(2))^2); 38 | NIST_sphere_loc.template_Sphere1_loc = [map_size/2, map_size/2-dist_Sphere12center]; % pixel 39 | 40 | %% get coordinates for all spheres 41 | NIST_sphere_loc.template_loc = zeros(NIST_sphere_loc.num_spheres, 2); 42 | NIST_sphere_loc.template_loc(:, 1) = NIST_sphere_loc.template_Sphere1_loc(1, 1) +... 43 | NIST_sphere_loc.dist_map.*sind(NIST_sphere_loc.ang_map); % x axis 44 | NIST_sphere_loc.template_loc(:, 2) = NIST_sphere_loc.template_Sphere1_loc(1, 2) +... 45 | NIST_sphere_loc.dist_map.*cosd(NIST_sphere_loc.ang_map); % y axis 46 | 47 | -------------------------------------------------------------------------------- /mrf/ROI_analysis_tool/Function/gen_NIST_std_par.m: -------------------------------------------------------------------------------- 1 | function NIST_std_par = gen_NIST_std_par(map_type, map_size, fov) 2 | % Input map parameters and return phantom parameters based on map type, map 3 | % size and fov. 4 | % INPUT 5 | % map_type type of map (T1 or T2) 6 | % map_size size of map, for example, 128 means the map size is 128x128 7 | % fov field of view [mm] 8 | % 9 | % OUTPUT 10 | % phan_std_par standard phantom parameters. 11 | % 12 | % 7/2019 Enlin Qian 13 | % # Copyright of the Board of Trustees of Columbia University in the City of New York 14 | NIST_std_par.num_spheres = 14; 15 | NIST_std_par.voxel_size = fov/map_size; % unit in mm/voxel 16 | NIST_std_par.sphere_radius = 8; % unit in mm 17 | NIST_std_par.temp_rot_center = [map_size/2, map_size/2]; % unit in pixel 18 | 19 | switch(map_type) 20 | case 'T1' 21 | NIST_std_par.true_value = [1.989, 1.454, 0.9841, 0.706, 0.4967,... 22 | 0.3515, 0.24713, 0.1753, 0.1259, 0.089, 0.0627, 0.04453, 0.03084, 0.021719]; 23 | NIST_std_par.plane_radius = 170; % mm 24 | 25 | case 'T2' 26 | NIST_std_par.true_value = [0.5813, 0.4035, 0.2781, 0.19094, 0.13327,... 27 | 0.09689, 0.06407, 0.04642, 0.03197, 0.02256, 0.015813, 0.011237, 0.007911, 0.005592]; 28 | NIST_std_par.plane_radius = 195; % mm 29 | end 30 | NIST_std_par.intensity_range = [NIST_std_par.true_value(1)-0.2, NIST_std_par.true_value(1)+0.2]; 31 | 32 | %% convert mm to voxel based on map_size and fov 33 | NIST_std_par.sphere_radius = NIST_std_par.sphere_radius/NIST_std_par.voxel_size; % convert to unit in voxel 34 | NIST_std_par.plane_radius = NIST_std_par.plane_radius/NIST_std_par.voxel_size; % convert to unit in voxel 35 | 36 | end -------------------------------------------------------------------------------- /mrf/ROI_analysis_tool/ROI_ana_demo.m: -------------------------------------------------------------------------------- 1 | clc 2 | clear 3 | %This script is used as a demo for NIST_ROI_ana.m. For now, four sets of 4 | %data are used for testing. 5 | % T1_map.mat T1_map data 6 | % T1_map_rot45.mat T1_map data rotated counterclockwise 45 degrees 7 | % T2_map.mat T2_map data 8 | % T2_map_rot30.mat T2_map data rotated counterclockwise 30 degree 9 | % 10 | % 7/2019 Enlin Qian 11 | % # Copyright of the Board of Trustees of Columbia University in the City of New York 12 | 13 | %% Load data 14 | addpath(genpath('.')) 15 | load('T2_map_rot30.mat') 16 | sphere_par = NIST_ROI_ana(T2_map_rot, 'T2', 128, 210); -------------------------------------------------------------------------------- /mrf/Sequence_Design/Data/method_orig.mat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/imr-framework/mrf/cd54590d149e8e8142bfda7ffc6e8811f8ad92b4/mrf/Sequence_Design/Data/method_orig.mat -------------------------------------------------------------------------------- /mrf/Sequence_Design/Function/gen_MRF_sequence_pulseq.m: -------------------------------------------------------------------------------- 1 | function [kshot, dcf, ind, TR_all, FA_all, TE_all] = gen_MRF_sequence_pulseq() 2 | % This script uses pulseq to generate a sequence proposed in Jiang's paper[1] 3 | % INPUT 4 | % None User does not need to input any parameter. All parameters for 5 | % the sueqnece are pre set. If user wants to customize their own 6 | % MRF sequence, please modify the double for loops starting at 7 | % line 98 to add different blocks. 8 | % 9 | % OUTPUT 10 | % kshot Spiral trajector in k-space 11 | % dcf Density compensation function 12 | % ind Index (2nd dim) for k-space points on spiral 13 | % TR_all All TRs used for the sequence. 14 | % FA_all All FAs used for the sequence. 15 | % TE_all All TEs used for the sequence. 16 | 17 | % 7/2019 Enlin Qian 18 | % # Copyright of the Board of Trustees of Columbia University in the City of New York 19 | % [1] Jiang Y, Ma D, Seiberlich N, Gulani V, Griswold M. MR fingerprinting using 20 | % fast imaging with steady state precession (FISP) with spiral readout. Magn Reson Med. 21 | % 2015;74(6):spcone-spcone. doi:10.1002/mrm.26048 22 | 23 | %% Set system limits 24 | gamma = 42576000; % in Hz %Determined from Pulseq - do not change,%Hz/T 25 | Gmax = 32; % mT/m 26 | SRmax = 130;% T/m/s 27 | system = mr.opts('MaxGrad',Gmax,'GradUnit','mT/m',... 28 | 'MaxSlew',SRmax,'SlewUnit','T/m/s', 'gradRasterTime', 10e-6, 'rfRingdownTime',10e-6); 29 | seq=mr.Sequence(system); 30 | total_acq = 1000; % total 1000 time points 31 | 32 | %% Load data 33 | fov=225e-3; 34 | Nx=256;% Ny=256; 35 | sliceThickness=5e-3; 36 | load('method_orig_147.mat') 37 | TR_all = method.VariableTR*1e-3; % converted to s (make min TR 14.7) 38 | TE_all = method.VariableTE*1e-3; % converted to s 39 | FA_all = method.VariableFlip+0.01; % avoid 0 flip angles 40 | SRmax = SRmax.*0.8; 41 | 42 | %% setting up trajectory 43 | Nshots = 48; %# of spirals 44 | [ktraj,dcf,t,ind,out,G]=design_spiral_pulseq(fov*1000,Nx,Nshots,10,... 45 | '',Gmax,SRmax,'1H',true,true,true);%fov is in mm 46 | G = G.*gamma; %converting T/m to Hz/m 47 | 48 | %% Rotating G, the G from design_spiral_pulseq function has rewinders but no rotation 49 | % ktraj has rotations but no rewinders 50 | G = complex(G(1,:),G(2,:)); 51 | G = [0,G]; %add a zero because Siemens does not like odd gradient length 52 | Gn = zeros(size(G,2),Nshots); 53 | for ks = 1:Nshots 54 | Gn(:,ks) = (G.*exp(1i*(ks-1)/Nshots*2*pi))'; 55 | end 56 | 57 | %% Break ktraj into Nshots 58 | kshot = zeros(length(ktraj)/Nshots,Nshots); 59 | OneSpiralPoints = length(ktraj)/Nshots; %# of points in one spiral 60 | for n1 = 1:Nshots 61 | kshot(:,n1) = ktraj((n1-1)*OneSpiralPoints+1:n1*OneSpiralPoints).*1e3;% per m 62 | plot (kshot(:,n1));hold on;grid on;xlabel('kx (m-1)'); ylabel('ky(m-1)'); 63 | end 64 | 65 | %% Get gradient based on k data 66 | ktrajs = zeros(size(ktraj,1), size(ktraj,2), 2); 67 | ktrajs(:,:,1) = real(ktraj); 68 | ktrajs(:,:,2) = imag(ktraj); 69 | 70 | %% Construct flip angles and construct RF angles (RF shapes cant be more than 128 (Siemens limit)) 71 | adc = mr.makeAdc(length(Gn),'Dwell',system.gradRasterTime); 72 | for itr = 1:total_acq 73 | [rf, gz] = mr.makeSincPulse(deg2rad(FA_all(itr)),system,'Duration', 1e-3,... 74 | 'SliceThickness',sliceThickness,'apodization',0.5,'timeBwProduct',4); 75 | rf_all(itr) = rf; 76 | gz_all(itr) = gz; 77 | end 78 | 79 | %% Need to determine multi-slice frequency offsets 80 | Nslices=1; 81 | deltaz=Nslices*sliceThickness; 82 | z=-(deltaz/2):sliceThickness:(deltaz/2); 83 | gzReph = mr.makeTrapezoid('z',system,'Area',-gz.area/2,'Duration',1e-3); 84 | gx = mr.makeArbitraryGrad('x', squeeze(real(Gn(:,1))),system); 85 | % [rf2] = mr.makeBlockPulse(pi,system,'Duration',500e-6); 86 | [rf2, gz2] = mr.makeSincPulse(pi,system,'Duration', 2e-3,... 87 | 'SliceThickness',sliceThickness,'apodization',0.5,'timeBwProduct',4); 88 | rf2.deadTime = 100e-6;rf2.ringdownTime=30e-6;%changing properties only for the rf block 89 | gzSpoil = mr.makeTrapezoid('z',system,'Area',gz.area*2,'Duration',3*8e-4); 90 | 91 | %% Define sequence block 92 | numfullim = ceil(total_acq/Nshots); 93 | TI = method.InversionTime*1e-3; % unit in s 94 | % delay18 = TI - mr.calcDuration(gzSpoil)-mr.calcDuration(rf2)/2; 95 | delay18 = TI - mr.calcDuration(rf2)/2; %changed due to TI calibration to get TI = 18 ms 96 | delaySpoil = mr.makeDelay(delay18); 97 | % seq.addBlock(gzSpoil); 98 | seq.addBlock(rf2, gz2); 99 | % seq.addBlock(gzSpoil); 100 | seq.addBlock(delaySpoil); 101 | time = 0; 102 | for ds = 1:numfullim 103 | for ns=1:Nshots 104 | n = (ds-1)*Nshots+ns; 105 | if n <= total_acq %GE limitation, only 1000 acq point 106 | delayTE = mr.calcDuration(gzReph) + (mr.calcDuration(rf_all(n))/2); 107 | %% Calculate timing 108 | delayTR= TR_all(n) - TE_all(n) - mr.calcDuration(gx)/2; 109 | delayTR = delayTR - mod(delayTR, 1e-5); 110 | 111 | delay1 = mr.makeDelay(delayTE); 112 | delay2 = mr.makeDelay(delayTR); 113 | 114 | seq.addBlock(rf_all(n),gz_all(n)); 115 | seq.addBlock(gzReph); 116 | gx = mr.makeArbitraryGrad('x', squeeze(real(Gn(:,ns))),system); 117 | gy = mr.makeArbitraryGrad('y', squeeze(imag(Gn(:,ns))),system); 118 | seq.addBlock(delay1); 119 | seq.addBlock(gx,gy,adc); 120 | seq.addBlock(delay2); 121 | time = time + TR_all(n); 122 | end 123 | end 124 | end 125 | disp(time/60); 126 | seq.plot('TimeRange',[0 10*0.028]); 127 | fname = ['Spiral_2D_vari_1000_single_slice_Orig_Par', num2str(Nshots),'_',num2str(TE_all(1))]; 128 | seq.write([fname,'.seq']); 129 | end 130 | 131 | -------------------------------------------------------------------------------- /mrf/Sequence_Design/Function/gradient_lobe.m: -------------------------------------------------------------------------------- 1 | function grad = gradient_lobe(ga_des,dt,gmax,smax,g_off,verb) 2 | % This scripts calculates gradient lobe with a initial gradient value 3 | % for desired area. Results in triangluar or trapezoidal gradient shape. 4 | % INPUT 5 | % grad = gradient_lobe(ga_des,dt,gmax,smax,g_off) 6 | % ga_des Desired area of gradient lobe [s*T/m] 7 | % dt Sampling dwell time [s] 8 | % gmax Maximum gradient strength [T/m] 9 | % smax Maximum slew rate [T/m/s] 10 | % g_off Offset gradient value (default=0) [T/m] 11 | % 12 | % OUTPUT 13 | % grad Gradient waveform [T/m] 14 | % 15 | % Created 7/2018 Rolf Schulte 16 | % Modified 7/2019 Enlin Qian 17 | if (nargin<1), help(mfilename); return; end 18 | 19 | if ~exist('g_off','var'), g_off = []; end 20 | if isempty(g_off), g_off = 0; end; g_off = round(g_off,2); 21 | if ~exist('verb','var'), verb = []; end 22 | if isempty(verb), verb = false; end 23 | 24 | if gmax<0, error('gmax(=%g)<0',gmax); end 25 | if smax<0, error('smax(=%g)<0',smax); end 26 | if abs(g_off)>gmax, error('abs(g_off)(=%g)>gmax(=%g)',abs(g_off),gmax); end 27 | 28 | 29 | %% calculate positive lobes; invert when necessary 30 | sgn = sign(ga_des); 31 | ga_des = abs(ga_des); 32 | g_off = sgn*g_off; 33 | 34 | gm = sqrt(smax*abs(ga_des)+0.5*g_off^2); % nominal gradient strength 35 | if gmgmax % trapezoid: add gradient plateau in middle 46 | if verb, fprintf('Constructing trapezoid\n'); end 47 | 48 | % points for ramp up and down 49 | n_up = ceil((gmax-g_off)/smax/dt)+1; 50 | n_down = ceil(gmax/smax/dt)+1; 51 | 52 | % area for ramp up and down 53 | ga_up = 0.5*(gmax^2-g_off^2)/smax; 54 | ga_down = 0.5*gmax^2/smax; 55 | 56 | n_plt = ceil((ga_des-(ga_up+ga_down))/gmax/dt); 57 | % gmax_act = gmax; 58 | else % triangular gradient 59 | if verb, fprintf('Constructing triangle\n'); end 60 | n_up = ceil((gm-g_off)/smax/dt); 61 | if n_up==1 62 | warning('n_up==1; setting to 0'); 63 | n_up = 0; 64 | else 65 | n_up = n_up+1; 66 | end 67 | n_down = ceil(gm/smax/dt)+1; 68 | % gmax_act = gm; 69 | 70 | if n_up<0, warning('n_up<0'); end 71 | 72 | n_plt = 0; 73 | end 74 | 75 | %% calculate exact gmax_act to prevent rounding errors 76 | gmax_act = (2*ga_des/dt-n_up*g_off)/(n_up+n_down+2*n_plt); 77 | 78 | %% construct actual gradient waveform 79 | grad = sgn*[linspace(g_off,gmax_act,n_up),... 80 | gmax_act*ones(1,n_plt),... 81 | linspace(gmax_act,0,n_down)]; 82 | 83 | %% check waveform 84 | ga_act = sum(grad)*dt; 85 | ga_err = (sgn*ga_des-ga_act)/ga_des; 86 | smax_act = max(abs(diff(grad)))/dt; 87 | if smax_act>smax, warning('smax_act(=%g)>smax(=%g)',smax_act,smax); end 88 | if gmax_act>gmax, warning('gmax_act(=%g)>gmax(=%g)',gmax_act,gmax); end 89 | if abs(ga_err)>1d-6 90 | warning('abs(ga_err(=%g))>1d-6; ga_des=%g; ga_act=%g',... 91 | ga_err,ga_des,ga_act); 92 | end 93 | 94 | %% print info 95 | if verb, 96 | fprintf('gmax=%g; gmax_act=%g [T/m]\n',gmax,gmax_act); 97 | fprintf('smax=%g; smax_act=%g [T/m]\n',smax,smax_act); 98 | fprintf('n_up=%g; n_plt=%g; n_down=%g\n',n_up,n_plt,n_down); 99 | fprintf('ga_des=%g; ga_act=%g; err=%g[%%]\n',... 100 | sgn*ga_des,ga_act,ga_err*100); 101 | end 102 | 103 | end % end main function gradient_lobe.m 104 | -------------------------------------------------------------------------------- /mrf/Sequence_Design/Function/gyrogamma.m: -------------------------------------------------------------------------------- 1 | function g = gyrogamma(nucleus) 2 | % This scripts get gyromagnetic ratio of various spins (in radians) 3 | % INPUT 4 | % nucleus 'h1';'h2';'he3';'c13';'n15';'f19';'na23';'p31';'xe129';... 5 | % '13c1h': ratio gyrogamma('13C')/gyrogamma('1h') 6 | % 'h1' is default 7 | % 8 | % OUTPUT 9 | % g [rad/(s T)] 10 | % 11 | % Literature: 12 | % Levitt; "Spin Dynamics"; Wiley 13 | % DeGraaf; "In Vivo NMR Spectroscopy"; Wiley 14 | % Ratio: jbnmr6_135_1995_wishart,pac70_117_1998_markley 15 | % electron: wikipedia 16 | % 17 | % 11/2009 Rolf Schulte 18 | if ~exist('nucleus','var'), nucleus = 'h1'; end 19 | switch lower(nucleus) 20 | case {'h1','1h',1}, g = 267.522128d6; 21 | case {'h2','2h',2}, g = 41.066d6; fprintf('Spin 1\n'); 22 | case {'h3','3h'}, g = 285.349d6; 23 | case {'he3','3he',3}, g =-203.789d6; 24 | case {'li7','7li',7}, g = 103.962d6; % source wikipedia 25 | case {'b10','10b',10}, g = 28.747d6; fprintf('Spin 3\n'); 26 | case {'b11','11b',11}, g = 85.847d6; fprintf('Spin 3/2\n'); 27 | case {'c13','13c',13}, g = 67.283d6; 28 | case {'n14','14n',14}, g = 19.338d6; fprintf('Spin 1\n'); 29 | case {'n15','15n',15}, g = -27.126d6; 30 | case {'o17','17o',17}, g = -36.281d6; fprintf('Spin 5/2\n'); 31 | case {'f19','19f',19}, g = 251.815d6; 32 | case {'ne21','21ne',21}; g = -2.113d7; fprintf('Spin 3/2\n'); 33 | case {'na23','23na',23}, g = 70.808d6; fprintf('Spin 3/2\n'); 34 | case {'al27','27al',27}, g = 69.763d6; fprintf('Spin 5/2\n'); 35 | case {'si29','29si',29}, g = -53.190d6; 36 | case {'p31','31p',31}, g = 108.394d6; 37 | case {'cl35','35cl',35}, g = 10.610d6; fprintf('Spin 3/2\n'); 38 | case {'cl37','37cl',37}, g = 8.832d6; fprintf('Spin 3/2\n'); 39 | case {'k39','39k',39}, g = 12.5d6; fprintf('Spin 3/2\n'); 40 | case {'mn55','55mn',55}, g = 6.6317e+07; fprintf('Spin 5/2\n'); 41 | case {'cu63','63cu',63}, g = 71.118d6; fprintf('Spin 3/2\n'); 42 | case {'cu65','65cu',65}, g = 76.044d6; fprintf('Spin 3/2\n'); 43 | case {'kr83','83kr',83}, g = -1.033d7; fprintf('Spin 9/2\n'); 44 | case {'ag107','107ag',107}, g = -10.889d6; 45 | case {'ag109','109ag',109}, g = -12.518d6; 46 | case {'xe129','129xe',129}, g = -74.521d6; 47 | case {'xe131','131xe',131}, g = 2.209d7; fprintf('Spin 3/2\n'); 48 | case {'cs133','133cs',133}, g = 35.0878d6; fprintf('Spin 7/2\n'); 49 | case {'pb207','207pb',207}, g = 55.805d6; 50 | case {'13c1h'}, g = 0.251449530; fprintf('Ratio 13C/1H\n'); 51 | case {'e'}, g = 1.760859770d11; 52 | otherwise, error('Input undefined'); 53 | end 54 | -------------------------------------------------------------------------------- /mrf/Sequence_Design/Function/make_HSI.m: -------------------------------------------------------------------------------- 1 | function [B1,A,w1] = make_HSI(A0,beta,mu,t, disp) 2 | % This script implements a hyperbolic secant (HSI) pulse introduced in [1]. 3 | % A0 Maximum pulse amplitude (rad/s) 4 | % beta Constants 5 | % mu Constants 6 | % t Time 7 | % 8 | % OUTPUT 9 | % w1 Frequency as a function of time 10 | % A Amplitude as a function of time 11 | % B1 B1 field as a function of time 12 | 13 | % Created by Sairam 14 | % 9/2019 Modified by Enlin Qian 15 | % # Copyright of the Board of Trustees of Columbia University in the City of New York 16 | % [1] Garwood, M., & DelaBarre, L. (2001). The Return of the Frequency Sweep: 17 | % Designing Adiabatic Pulses for Contemporary NMR. Journal Of Magnetic Resonance, 18 | % 153(2), 155-177. doi: 10.1006/jmre.2001.2340 19 | 20 | A = A0.*sech(beta.*t); % Amplitude modulation function 21 | w1 = -mu.*beta.*tanh(beta.*t); 22 | B1 = A.*exp(-1i*w1.*t); 23 | 24 | %% 25 | if(disp) 26 | figure(211); subplot(511); stem(t,A,'k'); xlabel('time(ms)'); ylabel('AM envelope'); hold all; 27 | subplot(512); plot(t,w1,'k');xlabel('time(ms)'); ylabel('FM envelope');hold all; 28 | subplot(513);plot(t,real(B1)); hold on; plot(t, imag(B1)); xlabel('time(ms)'); ylabel ('B1'); legend('B1x','B1y'); 29 | subplot(514);plot(real(B1), imag(B1)); xlabel('B1x'); ylabel('B1y'); 30 | subplot(515); plot(A,w1); xlabel(''); ylabel('myuB');hold on; 31 | % figure(2); plot(a); 32 | end -------------------------------------------------------------------------------- /mrf/Sequence_Design/Function/voronoi_area.m: -------------------------------------------------------------------------------- 1 | function dcf_out = voronoi_area(k) 2 | % Calculate the area (density) of a k-space trajectory via Voronoi 3 | % triangulation 4 | % INPUT 5 | % k k-space trajectory ([-0.5 0.5]*res) 6 | % 7 | % OUTPUT 8 | %dcf_out area assosiated with each k-space point 9 | % 10 | % Created Florian Wiesinger 11 | % Modified 7/2006 Rolf Schulte 12 | 13 | if (nargin<1), help(mfilename); dcf = NaN; return; end; 14 | if size(k,1)~=1, error('size(k,1)~=1'); end 15 | 16 | fufa = 0.7; % fudge factor to reduce outside areas 17 | 18 | tmp = version; 19 | if str2double(tmp(1))>7 20 | [ku,ki] = unique(k,'stable'); 21 | else 22 | [ku,ki] = unique(k); 23 | end 24 | nupts = length(k)-length(ki); 25 | nsimi = sum(abs(diff(sort(k)))<0.02); 26 | if nsimi>nupts, 27 | warning('voronoi_area:nsimi',... 28 | 'Detected %g similar points -> check dcf',nsimi); 29 | end 30 | if nupts>0, 31 | fprintf('%g non-unique points excluded\n',nupts); 32 | end 33 | kx = real(ku).'; 34 | ky = imag(ku).'; 35 | kxy = [kx,ky]; 36 | [V,C] = voronoin(kxy); % calculate voronoi vertices 37 | dcf = zeros(1,length(kxy)); 38 | makx = max(abs(kx)); 39 | maky = max(abs(ky)); 40 | makxy = min([makx maky]); 41 | tmp1 = 0; 42 | 43 | for i1 = 1:length(C)%length(kxy), % loop through all triangles 44 | x = V(C{i1},1); 45 | y = V(C{i1},2); 46 | % check for points outside the sampled area 47 | if any(isinf(x)) || any(isinf(y)) || ... 48 | any(abs(x)>makx) || any(abs(y)>maky) || ... 49 | any(sqrt(x.^2+y.^2)>makxy), 50 | % outside: radius -> approximate area 51 | tmp1 = tmp1+1; 52 | radii = sort(sqrt( (x-kx(i1)).^2 + (y-ky(i1)).^2 )); 53 | dcf(i1) = radii(1)*radii(2)*fufa; 54 | % dcf(i1) = mean(radii(1:2))^2; 55 | % dcf(i1) = mean(radii(1:2))^2*pi; 56 | else 57 | % inside: correct area 58 | dcf(i1) = polyarea(x,y); 59 | end 60 | end 61 | 62 | if any(isinf(dcf(:))), 63 | dcf(isinf(dcf)) = 0; 64 | warning('voronoi_area:inf','dcf contains inf -> setting to zero'); 65 | end 66 | dcf_out = zeros(1,length(k)); 67 | dcf_out(1,ki) = dcf; 68 | 69 | % 70 | mean_dcf_unsamp = mean(dcf_out(dcf_out>1)); 71 | if mean_dcf_unsamp>1, 72 | warning('voronoi_area:unsamp','Numerically stable?'); 73 | fprintf('mean(dcf(dcf>1))=%g\n',mean_dcf_unsamp); 74 | figure,plot(dcf_out); 75 | end 76 | 77 | -------------------------------------------------------------------------------- /mrf/Sequence_Design/sequence_design_demo.m: -------------------------------------------------------------------------------- 1 | clc 2 | clear 3 | %This script is used as a demo for gen_MRF_sequence_pulse.m. The function 4 | %uses TR, TE and FA from Spiral_Design/Data/method_orig.mat to construct a 5 | %sequence. 6 | % 8/2019 Enlin Qian 7 | % # Copyright of the Board of Trustees of Columbia University in the City of New York 8 | 9 | %% Sequence Design 10 | addpath(genpath('.')); 11 | [kshot, dcf, ind, TR_all, FA_all, TE_all] = gen_MRF_sequence_pulseq(); -------------------------------------------------------------------------------- /mrf/demo_MRF.m: -------------------------------------------------------------------------------- 1 | %% This script functions as a wrapper for all components of MRF package 2 | clc 3 | clear 4 | 5 | %% Sequence Design 6 | addpath(genpath('.')); 7 | [kshot, dcf, ind, TR_all, FA_all, TE_all] = gen_MRF_sequence_pulseq(); 8 | 9 | %% Image Reconstruction 10 | image_data_final_Complex = MRF_recon(); 11 | 12 | %% Dictionary Simulation 13 | T1=0.02:0.005:0.065; 14 | T1=[T1, 0.09:0.03:0.36]; 15 | T1=[T1, 0.5:0.1:4]; 16 | T2=0.005:0.002:0.011; 17 | T2=[T2, 0.015:0.005:0.045]; 18 | T2=[T2, 0.065:0.03:0.245]; 19 | T2=[T2, 0.35:0.05:0.5]; 20 | T2=[T2, 0.7:0.1:2]; 21 | TI=18; 22 | kshots=48; 23 | MRF_dict = gen_MRF_dict(TR_all, TE_all, FA_all, T1, T2, TI, kshots); 24 | 25 | %% Dictionary Matching 26 | load('dict_example.mat') 27 | Par_map = MRF_Dict_Matching(MRF_dict, image_data_final_Complex); 28 | 29 | %% ROI Analysis Tool --------------------------------------------------------------------------------