standart_RF.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490
  1. # -*- coding: utf-8 -*-
  2. """
  3. A subroutine functions to create different excitation and refocusing
  4. pulses accompanied by combined SS and spoil gradients.
  5. Requires the params structure as input.
  6. @author: petrm
  7. """
  8. # import
  9. from pypulseq.make_sinc_pulse import make_sinc_pulse
  10. from pypulseq.make_trapezoid import make_trapezoid
  11. from pypulseq.make_extended_trapezoid import make_extended_trapezoid
  12. from pypulseq.calc_duration import calc_duration
  13. import numpy as np
  14. # def tse_excitation_grad(params, scanner_parameters, area_gz_spoil, flip180):
  15. #
  16. # return
  17. def refocusing_grad(params, scanner_parameters, gz90_area, flip180, rf180_phase, t_refwd, spoil_duration, united: bool):
  18. # Create 180 degree SS refocusing pulse with SS and spoiled gradients
  19. rf180, gz_ref, _ = make_sinc_pulse(
  20. flip_angle=flip180,
  21. system=scanner_parameters,
  22. duration=params.t_ref,
  23. slice_thickness=params.sl_thkn,
  24. apodization=params.apodization,
  25. time_bw_product=round(params.t_BW_product_ref, 8),
  26. phase_offset=rf180_phase,
  27. use="refocusing",
  28. return_gz=True,
  29. delay = scanner_parameters.rf_dead_time
  30. )
  31. gz180 = make_trapezoid(channel="z", system=scanner_parameters, amplitude=gz_ref.amplitude,
  32. flat_time=t_refwd, rise_time=params.dG)
  33. if spoil_duration == 'min':
  34. gz_spoil_dur_min = params.dG + (gz90_area)/scanner_parameters.max_grad
  35. gz_spoil_dur_min = np.ceil(gz_spoil_dur_min / scanner_parameters.grad_raster_time) * scanner_parameters.grad_raster_time
  36. if gz_spoil_dur_min < 2 * params.dG:
  37. gz_spoil_dur_min = 2 * params.dG + scanner_parameters.grad_raster_time
  38. gz_spoil1 = make_trapezoid(channel='z', system=scanner_parameters, area= gz90_area,
  39. duration=gz_spoil_dur_min, rise_time=params.dG)
  40. gz_spoil2 = make_trapezoid(channel='z', system=scanner_parameters, area= gz90_area,
  41. duration=gz_spoil_dur_min, rise_time=params.dG)
  42. else:
  43. spoil_duration = float(spoil_duration)
  44. spoil_duration = np.ceil(spoil_duration / scanner_parameters.grad_raster_time) * scanner_parameters.grad_raster_time
  45. gz_spoil1 = make_trapezoid(channel='z', system=scanner_parameters, area= gz90_area,
  46. duration=spoil_duration, rise_time=params.dG)
  47. gz_spoil2 = make_trapezoid(channel='z', system=scanner_parameters, area= gz90_area,
  48. duration=spoil_duration, rise_time=params.dG)
  49. # SS refocusing gradient with spoilers
  50. gz_sp1_times = np.array(
  51. [
  52. 0,
  53. gz_spoil1.rise_time,
  54. gz_spoil1.rise_time + gz_spoil1.flat_time,
  55. gz_spoil1.rise_time + gz_spoil1.flat_time + gz_spoil1.fall_time
  56. ]
  57. )
  58. gz_sp1_amp = np.array(
  59. [
  60. 0,
  61. gz_spoil1.amplitude,
  62. gz_spoil1.amplitude,
  63. gz180.amplitude
  64. ]
  65. )
  66. gz_sp1 = make_extended_trapezoid(channel='z', system=scanner_parameters, times=gz_sp1_times, amplitudes=gz_sp1_amp)
  67. gz_sp2_times = np.array(
  68. [
  69. 0,
  70. gz180.flat_time
  71. ]
  72. )
  73. gz_sp2_amp = np.array(
  74. [
  75. gz180.amplitude,
  76. gz180.amplitude
  77. ]
  78. )
  79. gz_sp2 = make_extended_trapezoid(channel='z', system=scanner_parameters, times=gz_sp2_times, amplitudes=gz_sp2_amp)
  80. gz_sp3_times = np.array(
  81. [
  82. 0,
  83. gz_spoil2.rise_time,
  84. gz_spoil2.rise_time + gz_spoil2.flat_time,
  85. gz_spoil2.rise_time + gz_spoil2.flat_time + gz_spoil2.fall_time
  86. ]
  87. )
  88. gz_sp3_amp = np.array(
  89. [
  90. gz180.amplitude,
  91. gz_spoil2.amplitude,
  92. gz_spoil2.amplitude,
  93. 0
  94. ]
  95. )
  96. gz_sp3 = make_extended_trapezoid(channel='z', system=scanner_parameters, times=gz_sp3_times, amplitudes=gz_sp3_amp)
  97. if united:
  98. return rf180, gz_sp1, gz_sp2, gz_sp3
  99. else:
  100. return rf180, gz_spoil1, gz180, gz_spoil2
  101. '''
  102. def readout_grad_x(params, scanner_parameters, spoil_duration, rewind_duration, united: bool, phi_radial):
  103. """
  104. merged with spoiler gradients readout block in x direction
  105. phi_radial - angle for radial aquisition
  106. (0 - for cartesian)
  107. @author: petrm
  108. """
  109. # Create readout gradient
  110. readout_time = round(1 / params.BW_pixel, 8)
  111. k_read = np.double(params.Nf) / np.double(params.FoV_f)
  112. t_gx = np.ceil(readout_time / scanner_parameters.grad_raster_time) * scanner_parameters.grad_raster_time
  113. gx = make_trapezoid(channel='x', system=scanner_parameters, flat_area=k_read * np.cos(phi_radial),
  114. flat_time=t_gx + 2 * scanner_parameters.adc_dead_time, rise_time=params.dG)
  115. # generate gx spoiler gradient - G_crr
  116. if spoil_duration == 'min':
  117. gx_spoil = make_trapezoid(channel='x', system=scanner_parameters, area=gx.area,
  118. rise_time=params.dG)
  119. if gx_spoil.flat_time == 0:
  120. gx_spoil = make_trapezoid(channel='x', system=scanner_parameters, area=gx.area,
  121. rise_time=params.dG, flat_time=params.dG)
  122. else:
  123. spoil_duration = float(spoil_duration)
  124. spoil_duration = (np.ceil(spoil_duration / scanner_parameters.grad_raster_time)
  125. * scanner_parameters.grad_raster_time)
  126. gx_spoil = make_trapezoid(channel='x', system=scanner_parameters, area=gx.area,
  127. duration=spoil_duration, rise_time=params.dG)
  128. # readout gradient with spoilers
  129. gx_sp1_times = np.array(
  130. [
  131. 0,
  132. scanner_parameters.grad_raster_time * np.round(
  133. (gx_spoil.rise_time) / scanner_parameters.grad_raster_time),
  134. scanner_parameters.grad_raster_time * np.round(
  135. (gx_spoil.rise_time + gx_spoil.flat_time) / scanner_parameters.grad_raster_time),
  136. scanner_parameters.grad_raster_time * np.round(
  137. (gx_spoil.rise_time + gx_spoil.flat_time + gx_spoil.fall_time) / scanner_parameters.grad_raster_time)
  138. ]
  139. )
  140. gx_sp1_amp = np.array(
  141. [
  142. 0,
  143. gx_spoil.amplitude,
  144. gx_spoil.amplitude,
  145. gx.amplitude
  146. ]
  147. )
  148. gx_sp1 = make_extended_trapezoid(channel='x', system=scanner_parameters, times=gx_sp1_times, amplitudes=gx_sp1_amp)
  149. gx_sp2_times = np.array(
  150. [
  151. 0,
  152. scanner_parameters.grad_raster_time * np.round(
  153. (gx.flat_time) / scanner_parameters.grad_raster_time)
  154. ]
  155. )
  156. gx_sp2_amp = np.array(
  157. [
  158. gx.amplitude,
  159. gx.amplitude
  160. ]
  161. )
  162. gx_sp2 = make_extended_trapezoid(channel='x', system=scanner_parameters, times=gx_sp2_times, amplitudes=gx_sp2_amp)
  163. gx_sp3_times = np.array(
  164. [
  165. 0,
  166. scanner_parameters.grad_raster_time * np.round(
  167. (gx_spoil.rise_time) / scanner_parameters.grad_raster_time),
  168. scanner_parameters.grad_raster_time * np.round(
  169. (gx_spoil.rise_time + gx_spoil.flat_time) / scanner_parameters.grad_raster_time),
  170. scanner_parameters.grad_raster_time * np.round(
  171. (gx_spoil.rise_time + gx_spoil.flat_time + gx_spoil.fall_time) / scanner_parameters.grad_raster_time)
  172. ]
  173. )
  174. gx_sp3_amp = np.array(
  175. [
  176. gx.amplitude,
  177. gx_spoil.amplitude,
  178. gx_spoil.amplitude,
  179. 0
  180. ]
  181. )
  182. gx_sp3 = make_extended_trapezoid(channel='x', system=scanner_parameters, times=gx_sp3_times, amplitudes=gx_sp3_amp)
  183. if rewind_duration == 'min':
  184. gx_pre = make_trapezoid(channel="x", system=scanner_parameters, area=gx.area * 1.5,
  185. rise_time=params.dG)
  186. if gx_pre.flat_time == 0:
  187. gx_pre = make_trapezoid(channel='x', system=scanner_parameters, area=gx.area * 1.5,
  188. rise_time=params.dG, flat_time=params.dG)
  189. else:
  190. rewind_duration = float(rewind_duration)
  191. rewind_duration = (np.ceil(rewind_duration / scanner_parameters.grad_raster_time)
  192. * scanner_parameters.grad_raster_time)
  193. gx_pre = make_trapezoid(channel="x", system=scanner_parameters, area=gx.area * 1.5,
  194. rise_time=params.dG, duration=rewind_duration)
  195. if united:
  196. return gx_sp1, gx_sp2, gx_sp3, t_gx, gx_pre
  197. else:
  198. return gx_spoil, gx, gx_spoil, t_gx, gx_pre
  199. '''
  200. def readout_grad_y(params, scanner_parameters, spoil_duration, rewind_duration,
  201. united: bool, phi_radial, phase_encoding_area):
  202. """
  203. merged with spoiler gradients readout block in y direction
  204. phi_radial - angle for radial acquisition
  205. (0 - for cartesian)
  206. phase_encoding_area - additional gradient of phase encoding for spoiler
  207. @author: petrm
  208. """
  209. phase_encoding_area = phase_encoding_area * np.cos(phi_radial)
  210. # Create readout gradient
  211. readout_time = round(1 / params.BW_pixel, 8)
  212. k_read = np.double(params.Nf) / np.double(params.FoV_f)
  213. t_gx = np.ceil(readout_time / scanner_parameters.grad_raster_time) * scanner_parameters.grad_raster_time
  214. if phi_radial == 0.0:
  215. gx = make_trapezoid(channel='y', system=scanner_parameters, area=0,
  216. flat_time=t_gx + 2 * scanner_parameters.adc_dead_time, rise_time=params.dG)
  217. else:
  218. gx = make_trapezoid(channel='y', system=scanner_parameters, flat_area=k_read * np.sin(phi_radial),
  219. flat_time=t_gx + 2 * scanner_parameters.adc_dead_time, rise_time=params.dG)
  220. # generate gx spoiler gradient - G_crr
  221. if spoil_duration == 'min':
  222. gx_spoil_dur_min = params.dG + (gx.area + abs(phase_encoding_area))/scanner_parameters.max_grad
  223. gx_spoil_dur_min = np.ceil(gx_spoil_dur_min / scanner_parameters.grad_raster_time) * scanner_parameters.grad_raster_time
  224. if gx_spoil_dur_min < 2 * params.dG:
  225. gx_spoil_dur_min = 2 * params.dG + scanner_parameters.grad_raster_time
  226. gx_spoil1 = make_trapezoid(channel='y', system=scanner_parameters, area=gx.area + phase_encoding_area,
  227. duration=gx_spoil_dur_min, rise_time=params.dG)
  228. gx_spoil2 = make_trapezoid(channel='y', system=scanner_parameters, area=gx.area - phase_encoding_area,
  229. duration=gx_spoil_dur_min, rise_time=params.dG)
  230. else:
  231. spoil_duration = float(spoil_duration)
  232. spoil_duration = (np.ceil(spoil_duration / scanner_parameters.grad_raster_time)
  233. * scanner_parameters.grad_raster_time)
  234. gx_spoil1 = make_trapezoid(channel='y', system=scanner_parameters, area=gx.area + phase_encoding_area,
  235. duration=spoil_duration, rise_time=params.dG)
  236. gx_spoil2 = make_trapezoid(channel='y', system=scanner_parameters, area=gx.area - phase_encoding_area,
  237. duration=spoil_duration, rise_time=params.dG)
  238. # readout gradient with spoilers
  239. gx_sp1_times = np.array(
  240. [
  241. 0,
  242. scanner_parameters.grad_raster_time * np.round(
  243. (gx_spoil1.rise_time) / scanner_parameters.grad_raster_time),
  244. scanner_parameters.grad_raster_time * np.round(
  245. (gx_spoil1.rise_time + gx_spoil1.flat_time) / scanner_parameters.grad_raster_time),
  246. scanner_parameters.grad_raster_time * np.round(
  247. (gx_spoil1.rise_time + gx_spoil1.flat_time + gx_spoil1.fall_time) / scanner_parameters.grad_raster_time)
  248. ]
  249. )
  250. gx_sp1_amp = np.array(
  251. [
  252. 0,
  253. gx_spoil1.amplitude,
  254. gx_spoil1.amplitude,
  255. gx.amplitude
  256. ]
  257. )
  258. gx_sp1 = make_extended_trapezoid(channel='y', system=scanner_parameters, times=gx_sp1_times, amplitudes=gx_sp1_amp)
  259. gx_sp2_times = np.array(
  260. [
  261. 0,
  262. scanner_parameters.grad_raster_time * np.round(
  263. (gx.flat_time) / scanner_parameters.grad_raster_time)
  264. ]
  265. )
  266. gx_sp2_amp = np.array(
  267. [
  268. gx.amplitude,
  269. gx.amplitude
  270. ]
  271. )
  272. gx_sp2 = make_extended_trapezoid(channel='y', system=scanner_parameters, times=gx_sp2_times, amplitudes=gx_sp2_amp)
  273. gx_sp3_times = np.array(
  274. [
  275. 0,
  276. scanner_parameters.grad_raster_time * np.round(
  277. (gx_spoil2.rise_time) / scanner_parameters.grad_raster_time),
  278. scanner_parameters.grad_raster_time * np.round(
  279. (gx_spoil2.rise_time + gx_spoil2.flat_time) / scanner_parameters.grad_raster_time),
  280. scanner_parameters.grad_raster_time * np.round(
  281. (gx_spoil2.rise_time + gx_spoil2.flat_time + gx_spoil2.fall_time) / scanner_parameters.grad_raster_time)
  282. ]
  283. )
  284. gx_sp3_amp = np.array(
  285. [
  286. gx.amplitude,
  287. gx_spoil2.amplitude,
  288. gx_spoil2.amplitude,
  289. 0
  290. ]
  291. )
  292. gx_sp3 = make_extended_trapezoid(channel='y', system=scanner_parameters, times=gx_sp3_times, amplitudes=gx_sp3_amp)
  293. if rewind_duration == 'min':
  294. gx_pre_dur_min = params.dG + (gx.area * 1.5) / scanner_parameters.max_grad
  295. gx_pre_dur_min = np.ceil(gx_pre_dur_min / scanner_parameters.grad_raster_time) * scanner_parameters.grad_raster_time
  296. if gx_pre_dur_min < 2 * params.dG:
  297. gx_pre_dur_min = 2 * params.dG + scanner_parameters.grad_raster_time
  298. gx_pre = make_trapezoid(channel="y", system=scanner_parameters, area=gx.area * 1.50,
  299. duration=gx_pre_dur_min, rise_time=params.dG)
  300. else:
  301. rewind_duration = float(rewind_duration)
  302. rewind_duration = (np.ceil(rewind_duration / scanner_parameters.grad_raster_time)
  303. * scanner_parameters.grad_raster_time)
  304. gx_pre = make_trapezoid(channel="y", system=scanner_parameters, area=gx.area * 1.50,
  305. rise_time=params.dG, duration=rewind_duration)
  306. if united:
  307. return gx_sp1, gx_sp2, gx_sp3, t_gx, gx_pre
  308. else:
  309. return gx_spoil1, gx, gx_spoil2, t_gx, gx_pre
  310. def readout_grad_x(params, scanner_parameters, spoil_duration, rewind_duration,
  311. united: bool, phi_radial, phase_encoding_area, **kwargs):
  312. """
  313. merged with spoiler gradients readout block in y direction
  314. phi_radial - angle for radial acquisition
  315. (0 - for cartesian)
  316. phase_encoding_area - additional gradient of phase encoding for spoiler
  317. @author: petrm
  318. """
  319. if 'dixon_delta_te' in kwargs:
  320. dixon_delta_te = kwargs['dixon_delta_te'] #TODO: add exceptions??
  321. else:
  322. dixon_delta_te = 0
  323. phase_encoding_area = phase_encoding_area * np.sin(phi_radial) * (-1)
  324. # Create readout gradient
  325. readout_time = round(1 / params.BW_pixel, 8)
  326. k_read = np.double(params.Nf) / np.double(params.FoV_f)
  327. t_gx = np.ceil(readout_time / scanner_parameters.grad_raster_time) * scanner_parameters.grad_raster_time
  328. gx = make_trapezoid(channel='x', system=scanner_parameters, flat_area=k_read * np.cos(phi_radial),
  329. flat_time=t_gx + 2 * scanner_parameters.adc_dead_time, rise_time=params.dG)
  330. if vars(params).get('Dixon') is not None:
  331. if params.Dixon == True:
  332. Dixon_prephasor_area = gx.amplitude * dixon_delta_te
  333. else:
  334. Dixon_prephasor_area = 0
  335. # generate gx spoiler gradient - G_crr
  336. if spoil_duration == 'min':
  337. gx_spoil_dur_min = 2 * params.dG + (gx.area + abs(phase_encoding_area) + abs(Dixon_prephasor_area))/scanner_parameters.max_grad
  338. gx_spoil_dur_min = np.ceil(gx_spoil_dur_min / scanner_parameters.grad_raster_time) * scanner_parameters.grad_raster_time
  339. if gx_spoil_dur_min < 2 * params.dG:
  340. gx_spoil_dur_min = 2 * params.dG + scanner_parameters.grad_raster_time
  341. gx_spoil2 = make_trapezoid(channel='x', system=scanner_parameters, area=gx.area + phase_encoding_area + Dixon_prephasor_area,
  342. rise_time=params.dG, duration=gx_spoil_dur_min)
  343. gx_spoil1 = make_trapezoid(channel='x', system=scanner_parameters, area=gx.area - phase_encoding_area - Dixon_prephasor_area,
  344. rise_time=params.dG, duration=gx_spoil_dur_min)
  345. else:
  346. spoil_duration = float(spoil_duration)
  347. spoil_duration = (np.ceil(spoil_duration / scanner_parameters.grad_raster_time)
  348. * scanner_parameters.grad_raster_time)
  349. gx_spoil1 = make_trapezoid(channel='x', system=scanner_parameters, area=gx.area + phase_encoding_area + Dixon_prephasor_area,
  350. duration=spoil_duration, rise_time=params.dG)
  351. gx_spoil2 = make_trapezoid(channel='x', system=scanner_parameters, area=gx.area - phase_encoding_area - Dixon_prephasor_area,
  352. duration=spoil_duration, rise_time=params.dG)
  353. # readout gradient with spoilers
  354. gx_sp1_times = np.array(
  355. [
  356. 0,
  357. scanner_parameters.grad_raster_time * np.round(
  358. (gx_spoil1.rise_time) / scanner_parameters.grad_raster_time),
  359. scanner_parameters.grad_raster_time * np.round(
  360. (gx_spoil1.rise_time + gx_spoil1.flat_time) / scanner_parameters.grad_raster_time),
  361. scanner_parameters.grad_raster_time * np.round(
  362. (gx_spoil1.rise_time + gx_spoil1.flat_time + gx_spoil1.fall_time) / scanner_parameters.grad_raster_time)
  363. ]
  364. )
  365. gx_sp1_amp = np.array(
  366. [
  367. 0,
  368. gx_spoil1.amplitude,
  369. gx_spoil1.amplitude,
  370. gx.amplitude
  371. ]
  372. )
  373. gx_sp1 = make_extended_trapezoid(channel='x', system=scanner_parameters, times=gx_sp1_times, amplitudes=gx_sp1_amp)
  374. gx_sp2_times = np.array(
  375. [
  376. 0,
  377. scanner_parameters.grad_raster_time * np.round(
  378. (gx.flat_time) / scanner_parameters.grad_raster_time)
  379. ]
  380. )
  381. gx_sp2_amp = np.array(
  382. [
  383. gx.amplitude,
  384. gx.amplitude
  385. ]
  386. )
  387. gx_sp2 = make_extended_trapezoid(channel='x', system=scanner_parameters, times=gx_sp2_times, amplitudes=gx_sp2_amp)
  388. gx_sp3_times = np.array(
  389. [
  390. 0,
  391. scanner_parameters.grad_raster_time * np.round(
  392. (gx_spoil2.rise_time) / scanner_parameters.grad_raster_time),
  393. scanner_parameters.grad_raster_time * np.round(
  394. (gx_spoil2.rise_time + gx_spoil2.flat_time) / scanner_parameters.grad_raster_time),
  395. scanner_parameters.grad_raster_time * np.round(
  396. (gx_spoil2.rise_time + gx_spoil2.flat_time + gx_spoil2.fall_time) / scanner_parameters.grad_raster_time)
  397. ]
  398. )
  399. gx_sp3_amp = np.array(
  400. [
  401. gx.amplitude,
  402. gx_spoil2.amplitude,
  403. gx_spoil2.amplitude,
  404. 0
  405. ]
  406. )
  407. gx_sp3 = make_extended_trapezoid(channel='x', system=scanner_parameters, times=gx_sp3_times, amplitudes=gx_sp3_amp)
  408. if rewind_duration == 'min':
  409. gx_pre_dur_min = params.dG + (gx.area * 1.5)/scanner_parameters.max_grad
  410. gx_pre_dur_min = np.ceil(gx_pre_dur_min / scanner_parameters.grad_raster_time) * scanner_parameters.grad_raster_time
  411. if gx_pre_dur_min < 2 * params.dG:
  412. gx_pre_dur_min = 2 * params.dG + scanner_parameters.grad_raster_time
  413. gx_pre = make_trapezoid(channel="x", system=scanner_parameters, area=gx.area * 1.50,
  414. duration = gx_pre_dur_min, rise_time=params.dG)
  415. else:
  416. rewind_duration = float(rewind_duration)
  417. rewind_duration = (np.ceil(rewind_duration / scanner_parameters.grad_raster_time)
  418. * scanner_parameters.grad_raster_time)
  419. gx_pre = make_trapezoid(channel="x", system=scanner_parameters, area=gx.area * 1.50,
  420. rise_time=params.dG, duration=rewind_duration)
  421. if united:
  422. return gx_sp1, gx_sp2, gx_sp3, t_gx, gx_pre
  423. else:
  424. return gx_spoil1, gx, gx_spoil2, t_gx, gx_pre