MRArbGrad 4.3.0__tar.gz → 4.4.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/LICENSE +1 -1
- mrarbgrad-4.4.1/MANIFEST.in +1 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1/MRArbGrad.egg-info}/PKG-INFO +1 -1
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/MRArbGrad.egg-info/SOURCES.txt +4 -4
- {mrarbgrad-4.3.0/MRArbGrad.egg-info → mrarbgrad-4.4.1}/PKG-INFO +1 -1
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/Function.py +184 -48
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/Utility.py +108 -27
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/__init__.py +1 -1
- mrarbgrad-4.4.1/mrarbgrad_src/__pycache__/Function.cpython-312.pyc +0 -0
- mrarbgrad-4.4.1/mrarbgrad_src/__pycache__/Utility.cpython-312.pyc +0 -0
- mrarbgrad-4.4.1/mrarbgrad_src/__pycache__/__init__.cpython-312.pyc +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/ext/traj/MrTraj.h +2 -2
- mrarbgrad-4.4.1/mrarbgrad_src/ext.cpython-312-x86_64-linux-gnu.so +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/pyproject.toml +1 -1
- mrarbgrad-4.3.0/MANIFEST.in +0 -1
- mrarbgrad-4.3.0/example/example_BuiltInTraj.py +0 -105
- mrarbgrad-4.3.0/example/example_ExternalFunction2D.py +0 -80
- mrarbgrad-4.3.0/example/example_ExternalSamples2D.py +0 -84
- mrarbgrad-4.3.0/example/example_ExternalSamples3D.py +0 -72
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/MRArbGrad.egg-info/dependency_links.txt +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/MRArbGrad.egg-info/requires.txt +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/MRArbGrad.egg-info/top_level.txt +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/README.md +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/ext/mag/Mag.cpp +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/ext/mag/Mag.h +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/ext/main.cpp +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/ext/traj/Cones.h +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/ext/traj/MrTraj_2D.h +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/ext/traj/Rosette.h +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/ext/traj/Seiffert.h +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/ext/traj/Shell3d.h +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/ext/traj/Spiral.h +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/ext/traj/TrajFunc.h +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/ext/traj/VDSpiral.h +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/ext/traj/Yarnball.h +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/ext/utility/Intp.h +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/ext/utility/LinIntp.h +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/ext/utility/SplineIntp.h +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/ext/utility/global.cpp +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/ext/utility/global.h +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/ext/utility/v3.cpp +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/ext/utility/v3.h +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/trajfunc/__init__.py +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/mrarbgrad_src/trajfunc/main.py +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/setup.cfg +0 -0
- {mrarbgrad-4.3.0 → mrarbgrad-4.4.1}/setup.py +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Copyright
|
|
1
|
+
Copyright 2026 Rui Luo
|
|
2
2
|
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
4
4
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
graft mrarbgrad_src
|
|
@@ -12,13 +12,13 @@ MRArbGrad.egg-info/SOURCES.txt
|
|
|
12
12
|
MRArbGrad.egg-info/dependency_links.txt
|
|
13
13
|
MRArbGrad.egg-info/requires.txt
|
|
14
14
|
MRArbGrad.egg-info/top_level.txt
|
|
15
|
-
example/example_BuiltInTraj.py
|
|
16
|
-
example/example_ExternalFunction2D.py
|
|
17
|
-
example/example_ExternalSamples2D.py
|
|
18
|
-
example/example_ExternalSamples3D.py
|
|
19
15
|
mrarbgrad_src/Function.py
|
|
20
16
|
mrarbgrad_src/Utility.py
|
|
21
17
|
mrarbgrad_src/__init__.py
|
|
18
|
+
mrarbgrad_src/ext.cpython-312-x86_64-linux-gnu.so
|
|
19
|
+
mrarbgrad_src/__pycache__/Function.cpython-312.pyc
|
|
20
|
+
mrarbgrad_src/__pycache__/Utility.cpython-312.pyc
|
|
21
|
+
mrarbgrad_src/__pycache__/__init__.cpython-312.pyc
|
|
22
22
|
mrarbgrad_src/ext/main.cpp
|
|
23
23
|
mrarbgrad_src/ext/mag/Mag.cpp
|
|
24
24
|
mrarbgrad_src/ext/mag/Mag.h
|
|
@@ -23,10 +23,24 @@ def calGrad4ExFunc\
|
|
|
23
23
|
p0:float64 = 0e0,
|
|
24
24
|
p1:float64 = 1e0,
|
|
25
25
|
) -> tuple[NDArray, NDArray]:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
"""
|
|
27
|
+
Generate gradient waveforms for external functions.
|
|
28
|
+
|
|
29
|
+
Args:
|
|
30
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
31
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
32
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
33
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
34
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
35
|
+
getK (Callable | None, optional): Trajectory function.
|
|
36
|
+
getDkDp (Callable | None, optional): 1st order derivative to trajectory function.
|
|
37
|
+
getD2kDp2 (Callable | None, optional): 2nd order derivative to trajectory function.
|
|
38
|
+
p0 (float64, optional): Lower bound of the trajectory parameter.
|
|
39
|
+
p1 (float64, optional): Upper bound of the trajectory parameter.
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
tuple[NDArray, NDArray]: Gradient waveform (in `Hz/pix`); Corresponding parameter
|
|
43
|
+
"""
|
|
30
44
|
return ext.calGrad4ExFunc\
|
|
31
45
|
(
|
|
32
46
|
float64(fov),
|
|
@@ -55,10 +69,20 @@ def calGrad4ExSamp\
|
|
|
55
69
|
|
|
56
70
|
arrK: NDArray = np.empty((0,3)),
|
|
57
71
|
) -> tuple[NDArray, NDArray]:
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
72
|
+
"""
|
|
73
|
+
Generate gradient waveforms for external trajectory samples.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
77
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
78
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
79
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
80
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
81
|
+
arrK (NDArray, optional): External trajectory samples, shape: `[nK,nAx]`
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
tuple[NDArray, NDArray]: Gradient waveform (in `Hz/pix`); Corresponding parameter
|
|
85
|
+
"""
|
|
62
86
|
return ext.calGrad4ExSamp\
|
|
63
87
|
(
|
|
64
88
|
float64(fov),
|
|
@@ -83,10 +107,21 @@ def getG_Spiral\
|
|
|
83
107
|
nSlice: int64 = 1,
|
|
84
108
|
kRhoPhi: float64 = 0.5 / (4 * pi)
|
|
85
109
|
) -> tuple[list[NDArray], list[NDArray]]:
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
110
|
+
"""
|
|
111
|
+
Generate gradient waveforms for a standard spiral trajectory.
|
|
112
|
+
|
|
113
|
+
Args:
|
|
114
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
115
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
116
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
117
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
118
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
119
|
+
nSlice (int64, optional): Number of slices.
|
|
120
|
+
kRhoPhi (float64, optional): Shape parameter.
|
|
121
|
+
|
|
122
|
+
Returns:
|
|
123
|
+
tuple[list[NDArray], list[NDArray]]: List of trajectory start points (in `/pix`); List of gradient waveforms (in `Hz/pix`)
|
|
124
|
+
"""
|
|
90
125
|
return ext.getG_Spiral\
|
|
91
126
|
(
|
|
92
127
|
float64(fov),
|
|
@@ -113,10 +148,22 @@ def getG_VDSpiral\
|
|
|
113
148
|
kRhoPhi0: float64 = 0.5 / (8 * pi),
|
|
114
149
|
kRhoPhi1: float64 = 0.5 / (2 * pi),
|
|
115
150
|
) -> tuple[list[NDArray], list[NDArray]]:
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
151
|
+
"""
|
|
152
|
+
Generate gradient waveforms for a variable density (VD) spiral trajectory.
|
|
153
|
+
|
|
154
|
+
Args:
|
|
155
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
156
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
157
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
158
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
159
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
160
|
+
nSlice (int64, optional): Number of slices.
|
|
161
|
+
kRhoPhi0 (float64, optional): Inner shape parameter.
|
|
162
|
+
kRhoPhi1 (float64, optional): Outer shape parameter.
|
|
163
|
+
|
|
164
|
+
Returns:
|
|
165
|
+
tuple[list[NDArray], list[NDArray]]: List of trajectory start points (in `/pix`); List of gradient waveforms (in `Hz/pix`)
|
|
166
|
+
"""
|
|
120
167
|
return ext.getG_VDSpiral\
|
|
121
168
|
(
|
|
122
169
|
float64(fov),
|
|
@@ -143,10 +190,21 @@ def getG_VDSpiral_RT\
|
|
|
143
190
|
kRhoPhi0: float64 = 0.5 / (8 * pi),
|
|
144
191
|
kRhoPhi1: float64 = 0.5 / (2 * pi),
|
|
145
192
|
) -> tuple[list[NDArray], list[NDArray]]:
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
193
|
+
"""
|
|
194
|
+
Generate gradient waveforms for a real-time variable density spiral trajectory.
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
198
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
199
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
200
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
201
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
202
|
+
kRhoPhi0 (float64, optional): Inner shape parameter.
|
|
203
|
+
kRhoPhi1 (float64, optional): Outer shape parameter.
|
|
204
|
+
|
|
205
|
+
Returns:
|
|
206
|
+
tuple[list[NDArray], list[NDArray]]: List of trajectory start points (in `/pix`); List of gradient waveforms (in `Hz/pix`)
|
|
207
|
+
"""
|
|
150
208
|
return ext.getG_VDSpiral_RT\
|
|
151
209
|
(
|
|
152
210
|
float64(fov),
|
|
@@ -174,10 +232,23 @@ def getG_Rosette\
|
|
|
174
232
|
om2: float64 = 3*pi,
|
|
175
233
|
tMax: float64 = 1e0,
|
|
176
234
|
) -> tuple[list[NDArray], list[NDArray]]:
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
235
|
+
"""
|
|
236
|
+
Generate gradient waveforms for a rosette trajectory.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
240
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
241
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
242
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
243
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
244
|
+
nSlice (int64, optional): Number of slices.
|
|
245
|
+
om1 (float64, optional): Shape parameter.
|
|
246
|
+
om2 (float64, optional): Shape parameter.
|
|
247
|
+
tMax (float64, optional): Shape parameter.
|
|
248
|
+
|
|
249
|
+
Returns:
|
|
250
|
+
tuple[list[NDArray], list[NDArray]]: List of trajectory start points (in `/pix`); List of gradient waveforms (in `Hz/pix`)
|
|
251
|
+
"""
|
|
181
252
|
return ext.getG_Rosette\
|
|
182
253
|
(
|
|
183
254
|
float64(fov),
|
|
@@ -208,10 +279,24 @@ def getG_Rosette_Trad\
|
|
|
208
279
|
tMax: float64 = 1e0,
|
|
209
280
|
tAcq: float64 = 2.523e-3,
|
|
210
281
|
) -> tuple[list[NDArray], list[NDArray]]:
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
282
|
+
"""
|
|
283
|
+
Generate gradient waveforms for a traditional rosette trajectory.
|
|
284
|
+
|
|
285
|
+
Args:
|
|
286
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
287
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
288
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
289
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
290
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
291
|
+
nSlice (int64, optional): Number of slices.
|
|
292
|
+
om1 (float64, optional): Shape parameter.
|
|
293
|
+
om2 (float64, optional): Shape parameter.
|
|
294
|
+
tMax (float64, optional): Shape parameter.
|
|
295
|
+
tAcq (float64, optional): Acquisition duration.
|
|
296
|
+
|
|
297
|
+
Returns:
|
|
298
|
+
tuple[list[NDArray], list[NDArray]]: List of trajectory start points (in `/pix`); List of gradient waveforms (in `Hz/pix`)
|
|
299
|
+
"""
|
|
215
300
|
return ext.getG_Rosette_Trad\
|
|
216
301
|
(
|
|
217
302
|
float64(fov),
|
|
@@ -239,10 +324,20 @@ def getG_Shell3d\
|
|
|
239
324
|
|
|
240
325
|
kRhoTht: float64 = 0.5 / (2 * pi),
|
|
241
326
|
) -> tuple[list[NDArray], list[NDArray]]:
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
327
|
+
"""
|
|
328
|
+
Generate gradient waveforms for a 3D shell trajectory.
|
|
329
|
+
|
|
330
|
+
Args:
|
|
331
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
332
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
333
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
334
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
335
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
336
|
+
kRhoTht (float64, optional): Shape parameter.
|
|
337
|
+
|
|
338
|
+
Returns:
|
|
339
|
+
tuple[list[NDArray], list[NDArray]]: List of trajectory start points (in `/pix`); List of gradient waveforms (in `Hz/pix`)
|
|
340
|
+
"""
|
|
246
341
|
return ext.getG_Shell3d\
|
|
247
342
|
(
|
|
248
343
|
float64(fov),
|
|
@@ -266,10 +361,20 @@ def getG_Yarnball\
|
|
|
266
361
|
|
|
267
362
|
kRhoPhi: float64 = 0.5 / (2 * pi),
|
|
268
363
|
) -> tuple[list[NDArray], list[NDArray]]:
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
364
|
+
"""
|
|
365
|
+
Generate gradient waveforms for a yarnball trajectory.
|
|
366
|
+
|
|
367
|
+
Args:
|
|
368
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
369
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
370
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
371
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
372
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
373
|
+
kRhoPhi (float64, optional): Shape parameter.
|
|
374
|
+
|
|
375
|
+
Returns:
|
|
376
|
+
tuple[list[NDArray], list[NDArray]]: List of trajectory start points (in `/pix`); List of gradient waveforms (in `Hz/pix`)
|
|
377
|
+
"""
|
|
273
378
|
return ext.getG_Yarnball\
|
|
274
379
|
(
|
|
275
380
|
float64(fov),
|
|
@@ -293,10 +398,20 @@ def getG_Yarnball_RT\
|
|
|
293
398
|
|
|
294
399
|
kRhoPhi: float64 = 0.5 / (2 * pi)
|
|
295
400
|
) -> tuple[list[NDArray], list[NDArray]]:
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
401
|
+
"""
|
|
402
|
+
Generate gradient waveforms for a real-time yarnball trajectory.
|
|
403
|
+
|
|
404
|
+
Args:
|
|
405
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
406
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
407
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
408
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
409
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
410
|
+
kRhoPhi (float64, optional): Shape parameter.
|
|
411
|
+
|
|
412
|
+
Returns:
|
|
413
|
+
tuple[list[NDArray], list[NDArray]]: List of trajectory start points (in `/pix`); List of gradient waveforms (in `Hz/pix`)
|
|
414
|
+
"""
|
|
300
415
|
return ext.getG_Yarnball_RT\
|
|
301
416
|
(
|
|
302
417
|
float64(fov),
|
|
@@ -321,10 +436,21 @@ def getG_Seiffert\
|
|
|
321
436
|
m: float64 = 0.07,
|
|
322
437
|
uMax: float64 = 20.0,
|
|
323
438
|
) -> tuple[list[NDArray], list[NDArray]]:
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
439
|
+
"""
|
|
440
|
+
Generate gradient waveforms for a Seiffert spiral trajectory.
|
|
441
|
+
|
|
442
|
+
Args:
|
|
443
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
444
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
445
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
446
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
447
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
448
|
+
m (float64, optional): Shape parameter.
|
|
449
|
+
uMax (float64, optional): Shape parameter.
|
|
450
|
+
|
|
451
|
+
Returns:
|
|
452
|
+
tuple[list[NDArray], list[NDArray]]: List of trajectory start points (in `/pix`); List of gradient waveforms (in `Hz/pix`)
|
|
453
|
+
"""
|
|
328
454
|
return ext.getG_Seiffert\
|
|
329
455
|
(
|
|
330
456
|
float64(fov),
|
|
@@ -349,10 +475,20 @@ def getG_Cones\
|
|
|
349
475
|
|
|
350
476
|
kRhoPhi: float64 = 0.5 / (4 * pi),
|
|
351
477
|
) -> tuple[list[NDArray], list[NDArray]]:
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
478
|
+
"""
|
|
479
|
+
Generate gradient waveforms for a 3D cones trajectory.
|
|
480
|
+
|
|
481
|
+
Args:
|
|
482
|
+
fov (float64, optional): Field of view, unit: `m`.
|
|
483
|
+
nPix (int64, optional): Number of pixel, unit: `a.u.`.
|
|
484
|
+
sLim (float64, optional): l2 Slew limit, unit: `Hz/pix/s`.
|
|
485
|
+
gLim (float64, optional): l2 Gradient limit, unit: `Hz/pix`.
|
|
486
|
+
dt (float64, optional): Time step, unit: `s`.
|
|
487
|
+
kRhoPhi (float64, optional): Shape parameter.
|
|
488
|
+
|
|
489
|
+
Returns:
|
|
490
|
+
tuple[list[NDArray], list[NDArray]]: List of trajectory start points (in `/pix`); List of gradient waveforms (in `Hz/pix`)
|
|
491
|
+
"""
|
|
356
492
|
return ext.getG_Cones\
|
|
357
493
|
(
|
|
358
494
|
float64(fov),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from numpy import *
|
|
2
2
|
from numpy.linalg import norm
|
|
3
3
|
from numpy.typing import *
|
|
4
|
+
from itertools import product
|
|
4
5
|
|
|
5
6
|
goldrat = (1+sqrt(5))/2
|
|
6
7
|
goldang = (2*pi)/(1+goldrat)
|
|
@@ -8,6 +9,86 @@ goldang = (2*pi)/(1+goldrat)
|
|
|
8
9
|
def getGoldrat()->float: return goldrat
|
|
9
10
|
def getGoldang()->float: return goldang
|
|
10
11
|
|
|
12
|
+
def unitcvt(x:float, fov:float, nPix:int, dir:int, gamma:float=42.5756e6) -> float:
|
|
13
|
+
"""
|
|
14
|
+
This package uses `Hz/pix` for gradient unit, and `Hz/pix/s` for slew unit, and `pix` for length unit. This unit system has several good properties for theory derivation. You may need this helper function for unit conversion in case you are not familiar with this unit system.
|
|
15
|
+
|
|
16
|
+
You may need `dir=1,2` to convert common units (like `mT/m` for gradient and `T/m/s` for slew) to units supported by this package (like `Hz/pix` for gradient and `Hz/pix/s` for slew), before you call any gradient generation functions, or `dir=-1` when converting gradients generated by this package in `Hz/pix` back to `mT/m`.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
x (float): Input value.
|
|
20
|
+
fov (float): Field of view.
|
|
21
|
+
nPix (int): Number of pixels.
|
|
22
|
+
dir (int):
|
|
23
|
+
`1`: from `mT/m` to `Hz/pix`.
|
|
24
|
+
`2`: from `T/m/s` to `Hz/pix/s`.
|
|
25
|
+
`-1`: from `Hz/pix` to `mT/m`.
|
|
26
|
+
`-2`: from `Hz/pix/s` to `T/m/s`.
|
|
27
|
+
gamma (float): Gyromagnetic ratio `Hz/T`.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
float: Converted value.
|
|
31
|
+
"""
|
|
32
|
+
if dir==1:
|
|
33
|
+
return x * (1e-3*gamma*fov/nPix)
|
|
34
|
+
if dir==2:
|
|
35
|
+
return x * (gamma*fov/nPix)
|
|
36
|
+
if dir==-1:
|
|
37
|
+
return x / (1e-3*gamma*fov/nPix)
|
|
38
|
+
if dir==-2:
|
|
39
|
+
return x / (gamma*fov/nPix)
|
|
40
|
+
raise RuntimeError("dir")
|
|
41
|
+
|
|
42
|
+
def getK_Cartesian(nPix:int, nAx:int) -> list[NDArray]:
|
|
43
|
+
"""
|
|
44
|
+
Generates a Cartesian sampling pattern.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
nPix (int): Number of pixels.
|
|
48
|
+
nAx (int): Number of dimensions.
|
|
49
|
+
|
|
50
|
+
Returns:
|
|
51
|
+
list[NDArray]: List of trajectories in `[nK,nAx]`.
|
|
52
|
+
"""
|
|
53
|
+
arrK1D = linspace(-0.5, 0.5, nPix, endpoint=0)
|
|
54
|
+
lstArrK:list[NDArray] = []
|
|
55
|
+
|
|
56
|
+
for arrKyKz in product(arrK1D, repeat=nAx-1):
|
|
57
|
+
arrK = empty((nPix,nAx), dtype=float32)
|
|
58
|
+
arrK[:,0] = arrK1D
|
|
59
|
+
arrK[:,1:] = arrKyKz
|
|
60
|
+
lstArrK.append(arrK)
|
|
61
|
+
|
|
62
|
+
return lstArrK
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def getK_Radial(nPix:int, nAx:int, nSpoke:int, enGoldAng:bool) -> list:
|
|
66
|
+
"""
|
|
67
|
+
Generates a Radial sampling pattern.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
nPix (int): Number of pixels.
|
|
71
|
+
nAx (int): Number of dimensions.
|
|
72
|
+
nSpoke (int): Number of radial spokes.
|
|
73
|
+
enGoldAng (bool): If True, uses the golden angle for spoke spacing.
|
|
74
|
+
|
|
75
|
+
Returns:
|
|
76
|
+
list: A list of numpy arrays, each of shape [nPix, nAx], representing radial spokes.
|
|
77
|
+
"""
|
|
78
|
+
if nAx!=2: raise NotImplementedError("nAx!=2")
|
|
79
|
+
lstArrK = []
|
|
80
|
+
arrK1D = linspace(-0.5, 0.5, nPix, endpoint=0)
|
|
81
|
+
|
|
82
|
+
for iSpoke in range(nSpoke):
|
|
83
|
+
if enGoldAng: tht = iSpoke * goldang
|
|
84
|
+
else: tht = iSpoke * (pi / nSpoke)
|
|
85
|
+
arrK = empty((nPix,nAx), dtype=float32)
|
|
86
|
+
arrK[:,0] = arrK1D * cos(tht)
|
|
87
|
+
arrK[:,1] = arrK1D * sin(tht)
|
|
88
|
+
lstArrK.append(arrK)
|
|
89
|
+
|
|
90
|
+
return lstArrK
|
|
91
|
+
|
|
11
92
|
def gradClip(lstArrGrad:list[NDArray]|NDArray, dt:float, sLim:float, gLim:float) -> list[NDArray]|NDArray:
|
|
12
93
|
"""
|
|
13
94
|
Clip the slewrate and gradient amlitude of a list of gradient waveforms
|
|
@@ -64,70 +145,70 @@ def genPermTab(n:int) -> list[int]:
|
|
|
64
145
|
lstIdx.append(i*inc%n)
|
|
65
146
|
return lstIdx
|
|
66
147
|
|
|
67
|
-
def cvtGrad2Traj(
|
|
148
|
+
def cvtGrad2Traj(arrGrad:NDArray, dtGrad:int|float, dtAdc:int|float, nShift:int|float=1.0) -> tuple[NDArray, NDArray]:
|
|
68
149
|
"""
|
|
69
150
|
# description:
|
|
70
151
|
interpolate gradient waveform and calculate trajectory
|
|
71
152
|
|
|
72
153
|
# parameter
|
|
73
|
-
`
|
|
74
|
-
`dtGrad`, `
|
|
154
|
+
`arrGrad`: array of gradient waveform
|
|
155
|
+
`dtGrad`, `dtAdc`: temporal resolution of gradient system and ADC
|
|
75
156
|
|
|
76
157
|
# return:
|
|
77
158
|
interpolated trajectory and gradient
|
|
78
159
|
"""
|
|
79
|
-
dtShift = nShift*
|
|
80
|
-
nGrad,
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
for iDim in range(
|
|
84
|
-
|
|
85
|
-
arrDk = zeros_like(
|
|
86
|
-
arrDk[0,:] = (
|
|
87
|
-
arrDk[1:,:] = (
|
|
160
|
+
dtShift = nShift*dtAdc
|
|
161
|
+
nGrad, nAx = arrGrad.shape
|
|
162
|
+
nAdc = int(dtGrad/dtAdc)*(nGrad-1)
|
|
163
|
+
arrGrad_Resamp = zeros([nAdc,nAx], dtype=float64)
|
|
164
|
+
for iDim in range(nAx):
|
|
165
|
+
arrGrad_Resamp[:,iDim] = interp(dtAdc*arange(nAdc)+dtShift, dtGrad*arange(nGrad), arrGrad[:,iDim])
|
|
166
|
+
arrDk = zeros_like(arrGrad_Resamp)
|
|
167
|
+
arrDk[0,:] = (arrGrad[0,:] + arrGrad_Resamp[0,:])*dtShift/2
|
|
168
|
+
arrDk[1:,:] = (arrGrad_Resamp[:-1] + arrGrad_Resamp[1:])*dtAdc/2
|
|
88
169
|
arrK = cumsum(arrDk,axis=0)
|
|
89
|
-
return arrK,
|
|
170
|
+
return arrK, arrGrad_Resamp
|
|
90
171
|
|
|
91
|
-
def delGrad(
|
|
172
|
+
def delGrad(arrGrad:NDArray, tau:int|float) -> NDArray:
|
|
92
173
|
"""
|
|
93
174
|
# description:
|
|
94
175
|
delay the input gradient waveform by time constant tau
|
|
95
176
|
|
|
96
177
|
# parameter
|
|
97
|
-
`
|
|
178
|
+
`arrGrad`: array of single gradient waveform
|
|
98
179
|
`tau`: time constant in RL circuit transfer function
|
|
99
180
|
|
|
100
181
|
# return:
|
|
101
182
|
delayed gradient waveform
|
|
102
183
|
"""
|
|
103
|
-
assert
|
|
104
|
-
if tau == 0: return
|
|
105
|
-
nPt, nAx =
|
|
184
|
+
assert arrGrad.ndim == 2, "only single gradient waveform is supported."
|
|
185
|
+
if tau == 0: return arrGrad.copy() # avoid divided-by-0 later
|
|
186
|
+
nPt, nAx = arrGrad.shape
|
|
106
187
|
|
|
107
188
|
# perform oversample to get better impluse response profile
|
|
108
189
|
ov = clip(10/tau, 1, 1e3).astype(int64) # the smaller the ov, the bigger oversampling is needed
|
|
109
|
-
|
|
190
|
+
arrGrad_ov = zeros([nPt*ov,nAx], dtype=arrGrad.dtype)
|
|
110
191
|
for iAx in range(nAx):
|
|
111
|
-
|
|
192
|
+
arrGrad_ov[:,iAx] = interp(linspace(0,nPt,nPt*ov,0), linspace(0,nPt,nPt,0), arrGrad[:,iAx]) # oversample
|
|
112
193
|
nPt *= ov
|
|
113
194
|
tau *= ov
|
|
114
195
|
|
|
115
196
|
# derive impluse response of RL circuit
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
197
|
+
arrGrad_Pad = zeros_like(arrGrad_ov)
|
|
198
|
+
arrGrad_Pad[:nPt//2,:] = arrGrad_ov[-1:,:]
|
|
199
|
+
arrGrad_Pad[nPt//2:,:] = arrGrad_ov[:1,:]
|
|
200
|
+
arrGrad_ov = concatenate([arrGrad_ov, arrGrad_Pad], axis=0)
|
|
120
201
|
arrT = linspace(0,2*nPt,2*nPt,0) + 0.5
|
|
121
202
|
arrImpResRL = (1/tau)*exp(-arrT/tau)
|
|
122
203
|
if abs(arrImpResRL.sum() - 1) > 1e-2: raise ValueError(f"arrImpResRL.sum() = {arrImpResRL.sum():.2f} (supposed to be 1) (tau too small or too large)")
|
|
123
204
|
|
|
124
205
|
# perform convolution between input waveform and impulse response
|
|
125
|
-
|
|
206
|
+
arrGrad_ov = fft.ifft(fft.fft(arrGrad_ov,axis=0)*fft.fft(arrImpResRL)[:,newaxis], axis=0).real
|
|
126
207
|
|
|
127
208
|
# de-oversample
|
|
128
|
-
|
|
209
|
+
arrGrad = arrGrad_ov[:nPt:ov,:]
|
|
129
210
|
|
|
130
|
-
return
|
|
211
|
+
return arrGrad
|
|
131
212
|
|
|
132
213
|
def rotate(arr:NDArray, ang:float64, axis:int64) -> NDArray:
|
|
133
214
|
if axis==0: # x
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from .Function import calGrad4ExFunc, calGrad4ExSamp
|
|
2
2
|
from .Function import getG_Cones, getG_Rosette, getG_Rosette_Trad, getG_Seiffert, getG_Shell3d, getG_Spiral, getG_VDSpiral, getG_VDSpiral_RT, getG_Yarnball, getG_Yarnball_RT
|
|
3
3
|
from .Function import setSolverMtg, setTrajRev, setGoldAng, setShuf, setMaxG0, setMaxG1, setMagGradSamp, setMagTrajSamp, setMagOverSamp, setMagSFS, setMagGradRep, setMagTrajRep, setDbgPrint, saveF64, loadF64, saveF32, loadF32
|
|
4
|
-
from .Utility import _calDiaphony, rotate, _calJacElip, _calCompElipInt, _calSphFibPt, cvtGrad2Traj, getGoldang, getGoldrat, rand3d, gradClip, genPermTab
|
|
4
|
+
from .Utility import _calDiaphony, rotate, _calJacElip, _calCompElipInt, _calSphFibPt, cvtGrad2Traj, getGoldang, getGoldrat, rand3d, gradClip, genPermTab, unitcvt, getK_Cartesian, getK_Radial
|
|
5
5
|
|
|
6
6
|
from . import trajfunc
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
bool gMrTraj_enMtg = false; // whether to use Lustig's minTimeGrad solver
|
|
14
14
|
f64 gMrTraj_g0Norm = 0e0; // initial gradient amplitude
|
|
15
15
|
f64 gMrTraj_g1Norm = 0e0; // final gradient amplitude
|
|
16
|
-
i64 gMrTraj_nGradSampRsv = 10000; // buffer size of
|
|
16
|
+
i64 gMrTraj_nGradSampRsv = 10000; // buffer size of MAG solver
|
|
17
17
|
i64 gMrTraj_nTrajSampRsv = 10000; // num. of samp. when doing Traj. Rep.
|
|
18
18
|
|
|
19
19
|
/*
|
|
@@ -204,7 +204,7 @@ protected:
|
|
|
204
204
|
minRotang = std::min(minRotang, rotang);
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
-
// ensure the rot. Num. is
|
|
207
|
+
// ensure the rot. Num. is an integer
|
|
208
208
|
return (i64)std::ceil(2e0*M_PI/minRotang);
|
|
209
209
|
}
|
|
210
210
|
|
|
Binary file
|
mrarbgrad-4.3.0/MANIFEST.in
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
global-include *.py *.c *.cpp *.h
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import mrarbgrad as mag
|
|
2
|
-
from numpy import *
|
|
3
|
-
from matplotlib.pyplot import *
|
|
4
|
-
from numpy.linalg import norm
|
|
5
|
-
|
|
6
|
-
gamma = 42.5756e6
|
|
7
|
-
fov = 0.256
|
|
8
|
-
nPix = 256
|
|
9
|
-
dtGrad = 10e-6
|
|
10
|
-
dtADC = 2.5e-6
|
|
11
|
-
sLim = 50 * gamma * fov/nPix
|
|
12
|
-
gLim = 20e-3 * gamma * fov/nPix
|
|
13
|
-
# gLim = 1/nPix/dtADC
|
|
14
|
-
argCom = dict(fov=fov, nPix=nPix, sLim=sLim, gLim=gLim, dt=dtGrad)
|
|
15
|
-
|
|
16
|
-
mag.setSolverMtg(0) # set solver, 0 for proposed method, 1 for baseline method, baseline method may be removed due to copyright reason
|
|
17
|
-
mag.setTrajRev(0) # reverse the trajectory
|
|
18
|
-
mag.setGoldAng(1) # enable golden-angle interleaving (only for 2D)
|
|
19
|
-
mag.setShuf(0) # enable TR-shuffling
|
|
20
|
-
mag.setMaxG0(0) # use maximum possible initial gradient amplitude
|
|
21
|
-
mag.setMaxG1(0) # use maximum possible final gradient amplitude
|
|
22
|
-
mag.setMagOverSamp(8) # set oversampling ratio (default: 8, reduce only if hardware performance is too low to support real-time)
|
|
23
|
-
mag.setMagSFS(0) # disable DTFBS (experimental)
|
|
24
|
-
mag.setMagGradRep(1) # enable gradient reparameterization (experimental)
|
|
25
|
-
mag.setMagTrajRep(1) # enable trajectory reparameterization (experimental)
|
|
26
|
-
mag.setDbgPrint(1) # enable debug info (for benchmark purpose)
|
|
27
|
-
|
|
28
|
-
# calculate gradient
|
|
29
|
-
# lstArrK0, lstArrGrad = mag.getG_Spiral(**argCom); nAx = 2
|
|
30
|
-
# lstArrK0, lstArrGrad = mag.getG_VDSpiral(**argCom); nAx = 2
|
|
31
|
-
# lstArrK0, lstArrGrad = mag.getG_VDSpiral_RT(**argCom); nAx = 2
|
|
32
|
-
# lstArrK0, lstArrGrad = mag.getG_Rosette(**argCom); nAx = 2
|
|
33
|
-
# lstArrK0, lstArrGrad = mag.getG_Rosette_Trad(**argCom); nAx = 2
|
|
34
|
-
# lstArrK0, lstArrGrad = mag.getG_Shell3d(**argCom); nAx = 3
|
|
35
|
-
lstArrK0, lstArrGrad = mag.getG_Yarnball(**argCom); nAx = 3
|
|
36
|
-
# lstArrK0, lstArrGrad = mag.getG_Seiffert(**argCom); nAx = 3
|
|
37
|
-
# lstArrK0, lstArrGrad = mag.getG_Cones(**argCom); nAx = 3
|
|
38
|
-
|
|
39
|
-
# lstArrGrad = mag.gradClip(lstArrGrad, dtGrad, sLim, gLim) # clip slew/grad amp with hardware constraint
|
|
40
|
-
|
|
41
|
-
print("")
|
|
42
|
-
print(f"Intlea Num.: {len(lstArrGrad)}")
|
|
43
|
-
nRO_Max = amax([arrG.shape[0] for arrG in lstArrGrad])
|
|
44
|
-
print(f"Tacq: {nRO_Max*dtGrad*1e3:.3f} ms")
|
|
45
|
-
tTR = (nRO_Max*dtGrad + 2e-3)
|
|
46
|
-
print(f"TR: {tTR*1e3:.3f} ms")
|
|
47
|
-
tScan = tTR*len(lstArrGrad)
|
|
48
|
-
print(f"Tscan: {tScan:.3e} s")
|
|
49
|
-
|
|
50
|
-
# derive shape parameter
|
|
51
|
-
if nAx==2:
|
|
52
|
-
lstArrK0 = [arrK0[:2] for arrK0 in lstArrK0]
|
|
53
|
-
lstArrGrad = [arrG[:,:2] for arrG in lstArrGrad]
|
|
54
|
-
nRO, nAx = lstArrGrad[0].shape
|
|
55
|
-
|
|
56
|
-
# derive slewrate
|
|
57
|
-
lstArrSlew = [diff(arrG, axis=0)/dtGrad for arrG in lstArrGrad]
|
|
58
|
-
sMax = max(norm(concatenate(lstArrSlew)/gamma*nPix/fov, axis=-1))
|
|
59
|
-
gMax = max(norm(concatenate(lstArrGrad)/gamma*nPix/fov, axis=-1))
|
|
60
|
-
|
|
61
|
-
# derive trajectory
|
|
62
|
-
lstArrK = []
|
|
63
|
-
for arrK0, arrGrad in zip(lstArrK0, lstArrGrad):
|
|
64
|
-
arrK, _ = mag.cvtGrad2Traj(arrGrad, dtGrad, dtADC)
|
|
65
|
-
arrK += arrK0
|
|
66
|
-
lstArrK.append(arrK)
|
|
67
|
-
|
|
68
|
-
iArrK = len(lstArrK)*2//3
|
|
69
|
-
|
|
70
|
-
# k-space and g-space
|
|
71
|
-
figure(figsize=(18,9), dpi=120)
|
|
72
|
-
|
|
73
|
-
subplot(221, projection="3d" if nAx==3 else None)
|
|
74
|
-
plot(*lstArrK[iArrK].T, ".-")
|
|
75
|
-
axis("equal")
|
|
76
|
-
grid("on")
|
|
77
|
-
title(f"kspace {1}/{len(lstArrGrad)}")
|
|
78
|
-
|
|
79
|
-
subplot(223, projection="3d" if nAx==3 else None)
|
|
80
|
-
plot(*lstArrGrad[iArrK].T, ".-")
|
|
81
|
-
axis("equal")
|
|
82
|
-
grid("on")
|
|
83
|
-
title("gspace")
|
|
84
|
-
|
|
85
|
-
# gradient and slewrate
|
|
86
|
-
subplot(222)
|
|
87
|
-
for iAx in range(nAx):
|
|
88
|
-
plot(lstArrGrad[iArrK][:,iAx]/gamma*nPix/fov, ".-")
|
|
89
|
-
grid("on")
|
|
90
|
-
title(f"Gradient")
|
|
91
|
-
|
|
92
|
-
subplot(224)
|
|
93
|
-
plot(norm(lstArrSlew[iArrK],axis=-1)/gamma*nPix/fov, ".-", c="tab:blue")
|
|
94
|
-
ylim(sLim/gamma*nPix/fov*0.9, sLim/gamma*nPix/fov*1.1)
|
|
95
|
-
grid("on")
|
|
96
|
-
|
|
97
|
-
twinx()
|
|
98
|
-
plot(norm(lstArrGrad[iArrK],axis=-1)/gamma*nPix/fov*1e3, ".-", c="tab:orange")
|
|
99
|
-
ylim(gLim/gamma*nPix/fov*0.9*1e3, gLim/gamma*nPix/fov*1.1*1e3)
|
|
100
|
-
grid("on")
|
|
101
|
-
title(f"Grad & Slew amp., max grad:{gMax*1e3:.3f}, max slew:{sMax:.3f}")
|
|
102
|
-
|
|
103
|
-
subplots_adjust(0.05,0.1,0.95,0.9, 0.2, 0.2)
|
|
104
|
-
|
|
105
|
-
show()
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
from numpy import *
|
|
2
|
-
from numpy.linalg import norm
|
|
3
|
-
from matplotlib.pyplot import *
|
|
4
|
-
import mrarbgrad as mag
|
|
5
|
-
|
|
6
|
-
gamma = 42.5756e6
|
|
7
|
-
fov = 0.256
|
|
8
|
-
nPix = 256
|
|
9
|
-
dtGrad = 10e-6
|
|
10
|
-
dtADC = 1e-6
|
|
11
|
-
sLim = 50 * gamma * fov/nPix
|
|
12
|
-
gLim = 20e-3 * gamma * fov/nPix
|
|
13
|
-
# gLim = 1/nPix/dtADC
|
|
14
|
-
|
|
15
|
-
# Rosette
|
|
16
|
-
nAx = 2
|
|
17
|
-
om1 = 19*pi
|
|
18
|
-
om2 = 17*pi
|
|
19
|
-
def Rosette(t):
|
|
20
|
-
rho = 0.5*sin(om1*t)
|
|
21
|
-
return array\
|
|
22
|
-
([
|
|
23
|
-
rho*cos(om2*t),
|
|
24
|
-
rho*sin(om2*t),
|
|
25
|
-
0*t
|
|
26
|
-
])
|
|
27
|
-
|
|
28
|
-
pLim = [0,1]
|
|
29
|
-
|
|
30
|
-
# derive slew-rate constrained trajectory
|
|
31
|
-
mag.setMaxG0(0)
|
|
32
|
-
mag.setMaxG1(0)
|
|
33
|
-
arrGrad = mag.calGrad4ExFunc(fov, nPix, sLim, gLim, dtGrad, Rosette, None, None, pLim[0], pLim[1])[0]
|
|
34
|
-
# arrGrad = mag.gradClip(arrGrad, dtGrad, sLim, gLim) # clip slew/grad amp with hardware constraint
|
|
35
|
-
nRO = arrGrad.shape[0]
|
|
36
|
-
|
|
37
|
-
arrSlew = diff(arrGrad, axis=0)/dtGrad
|
|
38
|
-
print(f"sMax: {max(norm(arrSlew,axis=-1))/(42.58e6)*(nPix/fov)}")
|
|
39
|
-
|
|
40
|
-
arrK = mag.cvtGrad2Traj(arrGrad, dtGrad, dtADC, 0.5)[0]
|
|
41
|
-
|
|
42
|
-
# derive reference trajectory
|
|
43
|
-
arrP_Ref = linspace(pLim[0], pLim[1], int(1e4))
|
|
44
|
-
arrK_Ref = Rosette(arrP_Ref).T
|
|
45
|
-
|
|
46
|
-
# plot
|
|
47
|
-
figure(figsize=(20,10), dpi=120)
|
|
48
|
-
|
|
49
|
-
subplot(221, projection=None if nAx==2 else "3d")
|
|
50
|
-
if nAx==2: plot(arrK_Ref[:,0], arrK_Ref[:,1], "--", label="K_Ref")
|
|
51
|
-
if nAx==3: plot(arrK_Ref[:,0], arrK_Ref[:,1], arrK_Ref[:,2], "--", label="K_Ref")
|
|
52
|
-
if nAx==2: plot(arrK[:,0], arrK[:,1], ".-", label="K_Imp")
|
|
53
|
-
if nAx==3: plot(arrK[:,0], arrK[:,1], arrK[:,2], ".-", label="K_Imp")
|
|
54
|
-
xlim(-0.5,0.5)
|
|
55
|
-
ylim(-0.5,0.5)
|
|
56
|
-
axis("equal")
|
|
57
|
-
grid("on")
|
|
58
|
-
legend()
|
|
59
|
-
title("k-Space")
|
|
60
|
-
|
|
61
|
-
subplot(222)
|
|
62
|
-
for iAx in range(nAx):
|
|
63
|
-
plot(arrGrad[:,iAx]/(42.58e6)*(nPix/fov), ".-")
|
|
64
|
-
grid("on")
|
|
65
|
-
title("Gradient")
|
|
66
|
-
|
|
67
|
-
subplot(223, projection=None if nAx==2 else "3d")
|
|
68
|
-
if nAx==2: plot(arrGrad[:,0], arrGrad[:,1], ".-")
|
|
69
|
-
if nAx==3: plot(arrGrad[:,0], arrGrad[:,1], arrGrad[:,2], ".-")
|
|
70
|
-
axis("equal")
|
|
71
|
-
grid("on")
|
|
72
|
-
title("g-Space")
|
|
73
|
-
|
|
74
|
-
subplot(224)
|
|
75
|
-
plot(norm(arrSlew,axis=-1)/(42.58e6)*(nPix/fov), ".-")
|
|
76
|
-
ylim(sLim/(42.58e6)*(nPix/fov)*0.9, sLim/(42.58e6)*(nPix/fov)*1.1)
|
|
77
|
-
grid("on")
|
|
78
|
-
title(f"Slewrate, max:{max(norm(arrSlew,axis=-1))/(42.58e6)*(nPix/fov):.3f}")
|
|
79
|
-
|
|
80
|
-
show()
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
from numpy import *
|
|
2
|
-
from numpy.linalg import norm
|
|
3
|
-
from matplotlib.pyplot import *
|
|
4
|
-
import mrarbgrad as mag
|
|
5
|
-
|
|
6
|
-
gamma = 42.5756e6
|
|
7
|
-
fov = 0.256
|
|
8
|
-
nPix = 256
|
|
9
|
-
dtGrad = 10e-6
|
|
10
|
-
dtADC = 2.5e-6
|
|
11
|
-
sLim = 50 * gamma * fov/nPix
|
|
12
|
-
gLim = 20e-3 * gamma * fov/nPix
|
|
13
|
-
# gLim = 1/nPix/dtADC
|
|
14
|
-
|
|
15
|
-
# Rosette
|
|
16
|
-
om1 = 5*pi
|
|
17
|
-
om2 = 3*pi
|
|
18
|
-
pLim = [0,1]
|
|
19
|
-
def TrajFunc(t):
|
|
20
|
-
rho = 0.5*sin(om1*t)
|
|
21
|
-
return array\
|
|
22
|
-
([
|
|
23
|
-
rho*cos(om2*t),
|
|
24
|
-
rho*sin(om2*t),
|
|
25
|
-
zeros_like(t)
|
|
26
|
-
])
|
|
27
|
-
|
|
28
|
-
# sample
|
|
29
|
-
arrP = linspace(pLim[0], pLim[1], 1000)
|
|
30
|
-
arrK = TrajFunc(arrP).T
|
|
31
|
-
nAx = 2
|
|
32
|
-
|
|
33
|
-
# derive slew-rate constrained trajectory
|
|
34
|
-
for i in range(1):
|
|
35
|
-
arrGrad = mag.calGrad4ExSamp(fov, nPix, sLim, gLim, dtGrad, arrK)[0]
|
|
36
|
-
# arrGrad = mag.gradClip(arrGrad, dtGrad, sLim, gLim) # clip slew/grad amp with hardware constraint
|
|
37
|
-
nRO = arrGrad.shape[0]
|
|
38
|
-
|
|
39
|
-
arrSlew = diff(arrGrad, axis=0)/dtGrad
|
|
40
|
-
print(f"sMax: {max(norm(arrSlew,axis=-1))/(42.58e6)*(nPix/fov)}")
|
|
41
|
-
|
|
42
|
-
arrK, _ = mag.cvtGrad2Traj(arrGrad, dtGrad, dtADC, 0.5)
|
|
43
|
-
arrK += TrajFunc(pLim[0])
|
|
44
|
-
print(f"Err: {norm(arrK[-1,:]-TrajFunc(pLim[1])):.1e}")
|
|
45
|
-
|
|
46
|
-
# derive reference trajectory
|
|
47
|
-
arrP_Ref = linspace(pLim[0], pLim[1], int(1e4))
|
|
48
|
-
arrK_Ref = TrajFunc(arrP_Ref).T
|
|
49
|
-
|
|
50
|
-
# plot
|
|
51
|
-
figure(figsize=(20,10), dpi=120)
|
|
52
|
-
|
|
53
|
-
subplot(221, projection=None if nAx==2 else "3d")
|
|
54
|
-
if nAx==2: plot(arrK_Ref[:,0], arrK_Ref[:,1], "--", label="K_Ref")
|
|
55
|
-
if nAx==3: plot(arrK_Ref[:,0], arrK_Ref[:,1], arrK_Ref[:,2], "--", label="K_Ref")
|
|
56
|
-
if nAx==2: plot(arrK[:,0], arrK[:,1], ".-", label="K_Imp")
|
|
57
|
-
if nAx==3: plot(arrK[:,0], arrK[:,1], arrK[:,2], ".-", label="K_Imp")
|
|
58
|
-
xlim(-0.5,0.5)
|
|
59
|
-
ylim(-0.5,0.5)
|
|
60
|
-
axis("equal")
|
|
61
|
-
grid("on")
|
|
62
|
-
legend()
|
|
63
|
-
title("k-Space")
|
|
64
|
-
|
|
65
|
-
subplot(222)
|
|
66
|
-
for iAx in range(nAx):
|
|
67
|
-
plot(arrGrad[:,iAx]/(42.58e6)*(nPix/fov), ".-")
|
|
68
|
-
grid("on")
|
|
69
|
-
title("Gradient")
|
|
70
|
-
|
|
71
|
-
subplot(223, projection=None if nAx==2 else "3d")
|
|
72
|
-
if nAx==2: plot(arrGrad[:,0], arrGrad[:,1], ".-")
|
|
73
|
-
if nAx==3: plot(arrGrad[:,0], arrGrad[:,1], arrGrad[:,2], ".-")
|
|
74
|
-
axis("equal")
|
|
75
|
-
grid("on")
|
|
76
|
-
title("g-Space")
|
|
77
|
-
|
|
78
|
-
subplot(224)
|
|
79
|
-
plot(norm(arrSlew,axis=-1)/(42.58e6)*(nPix/fov), ".-")
|
|
80
|
-
ylim(sLim/(42.58e6)*(nPix/fov)*0.9, sLim/(42.58e6)*(nPix/fov)*1.1)
|
|
81
|
-
grid("on")
|
|
82
|
-
title(f"Slewrate, max:{max(norm(arrSlew,axis=-1))/(42.58e6)*(nPix/fov):.3f}")
|
|
83
|
-
|
|
84
|
-
show()
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
from numpy import *
|
|
2
|
-
from numpy.linalg import norm
|
|
3
|
-
from matplotlib.pyplot import *
|
|
4
|
-
import mrarbgrad as mag
|
|
5
|
-
|
|
6
|
-
gamma = 42.5756e6
|
|
7
|
-
fov = 0.256
|
|
8
|
-
nPix = 256
|
|
9
|
-
dtGrad = 10e-6
|
|
10
|
-
dtADC = 2.5e-6
|
|
11
|
-
sLim = 50 * gamma * fov/nPix
|
|
12
|
-
gLim = 20e-3 * gamma * fov/nPix
|
|
13
|
-
# gLim = 1/nPix/dtADC
|
|
14
|
-
|
|
15
|
-
# Yarnball
|
|
16
|
-
nAx = 3
|
|
17
|
-
|
|
18
|
-
kRhoPhi = 0.5/(2*pi)
|
|
19
|
-
Yarnball = lambda sqrtTht: mag.trajfunc.Yarnball(sqrtTht, kRhoPhi)
|
|
20
|
-
pLim = mag.trajfunc.prange_Yarnball(kRhoPhi)
|
|
21
|
-
|
|
22
|
-
arrP = linspace(pLim[0], pLim[1], 1000)
|
|
23
|
-
arrK = Yarnball(arrP)
|
|
24
|
-
|
|
25
|
-
# derive slew-rate constrained trajectory
|
|
26
|
-
mag.setDbgPrint(1)
|
|
27
|
-
arrGrad = mag.calGrad4ExSamp(fov, nPix, sLim, gLim, dtGrad, arrK)[0]
|
|
28
|
-
# arrGrad = mag.gradClip(arrGrad, dtGrad, sLim, gLim) # clip slew/grad amp with hardware constraint
|
|
29
|
-
nRO = arrGrad.shape[0]
|
|
30
|
-
|
|
31
|
-
arrSlew = diff(arrGrad, axis=0)/dtGrad
|
|
32
|
-
print(f"sMax: {max(norm(arrSlew,axis=-1))/(42.58e6)*(nPix/fov)}")
|
|
33
|
-
|
|
34
|
-
arrK, _ = mag.cvtGrad2Traj(arrGrad, dtGrad, dtADC, 0.5)
|
|
35
|
-
|
|
36
|
-
# derive reference trajectory
|
|
37
|
-
arrP_Ref = linspace(pLim[0], pLim[1], int(1e4))
|
|
38
|
-
arrK_Ref = Yarnball(arrP_Ref)
|
|
39
|
-
|
|
40
|
-
# plot
|
|
41
|
-
figure(figsize=(20,10), dpi=120)
|
|
42
|
-
|
|
43
|
-
subplot(221, projection="3d")
|
|
44
|
-
plot(arrK_Ref[:,0], arrK_Ref[:,1], arrK_Ref[:,2], "--", label="K_Ref")
|
|
45
|
-
plot(arrK[:,0], arrK[:,1], arrK[:,2], ".-", label="K_Imp")
|
|
46
|
-
xlim(-0.5,0.5)
|
|
47
|
-
ylim(-0.5,0.5)
|
|
48
|
-
axis("equal")
|
|
49
|
-
grid("on")
|
|
50
|
-
legend()
|
|
51
|
-
title("k-Space")
|
|
52
|
-
|
|
53
|
-
subplot(222)
|
|
54
|
-
for iAx in range(nAx):
|
|
55
|
-
plot(arrGrad[:,iAx]/(42.58e6)*(nPix/fov), ".-")
|
|
56
|
-
grid("on")
|
|
57
|
-
title("Gradient")
|
|
58
|
-
|
|
59
|
-
subplot(223, projection=None if nAx==2 else "3d")
|
|
60
|
-
if nAx==2: plot(arrGrad[:,0], arrGrad[:,1], ".-")
|
|
61
|
-
if nAx==3: plot(arrGrad[:,0], arrGrad[:,1], arrGrad[:,2], ".-")
|
|
62
|
-
axis("equal")
|
|
63
|
-
grid("on")
|
|
64
|
-
title("g-Space")
|
|
65
|
-
|
|
66
|
-
subplot(224)
|
|
67
|
-
plot(norm(arrSlew,axis=-1)/(42.58e6)*(nPix/fov), ".-")
|
|
68
|
-
ylim(sLim/(42.58e6)*(nPix/fov)*0.9, sLim/(42.58e6)*(nPix/fov)*1.1)
|
|
69
|
-
grid("on")
|
|
70
|
-
title(f"Slewrate, max:{max(norm(arrSlew,axis=-1))/(42.58e6)*(nPix/fov):.3f}")
|
|
71
|
-
|
|
72
|
-
show()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|