/
ft_realtime_fmriproxy.m
152 lines (130 loc) · 4.76 KB
/
ft_realtime_fmriproxy.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
function ft_realtime_fmriproxy(cfg)
% FT_REALTIME_FMRIPROXY simulates an fMRI acquisition system by writing volumes in a
% cycle of about 2 seconds. The voxel data is written as a column vector with X*Y*Z
% channels, where X and Y are the readout and phase-encoding resolution, and Z is the
% number of slices. The voxel data consists of a ellipsoid (a bit like a head) with
% added lateralized activation (20 scan cycle) and noise.
%
% This function also writes out events of type='scan' and value='pulse' when the
% simulated scanner initiates a scan, and value='ready' when a hypothetical
% processing pipeline is finished with that scan, just after writing out the volume
% data itself. There is an artificial delay of 1.3*TR between the two events.
%
% Use as
% ft_realtime_fmriproxy(cfg)
%
% The target to write the data to is configured as
% cfg.target.datafile = string, target destination for the data (default = 'buffer://localhost:1972')
%
% You can also select a resolution of the simulated volumes (default = [64,64,20]) like
% cfg.voxels = [64 64 32]
% and the repetition time (TR, default = 0.08*number of slices) in seconds using
% cfg.TR = 2.0
%
% To stop this realtime function, you have to press Ctrl-C
%
% See also FT_REALTIME_SIGNALPROXY, FT_REALTIME_SIGNALVIEWER
% Copyright (C) 2010, Stefan Klanke / Robert Oostenveld
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% for the documentation and details.
%
% FieldTrip is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% FieldTrip is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id$
% set the defaults
if isempty(cfg) || ~isfield(cfg, 'target') || ~isfield(cfg.target, 'datafile')
cfg.target.datafile = 'buffer://localhost:1972';
end
cfg.target.dataformat = [];
if isfield(cfg, 'voxels')
voxels = cfg.voxels(1:3);
else
voxels = [64 64 20];
end
if isfield(cfg,'TR')
TR = cfg.TR;
Tslice = TR / voxels(3);
else
Tslice = 0.08;
TR = Tslice * voxels(3);
end
nifti = [];
nifti.dim = voxels;
nifti.pixdim = [3.5 3.5 3.5]; % size of voxel in mm
nifti.slice_duration = Tslice;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% create a FieldTrip compatible header structure
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
hdr = [];
hdr.nChans = prod(voxels);
hdr.nSamples = 0;
hdr.Fs = 1/TR;
hdr.nSamplesPre = 0;
hdr.nTrials = 1;
hdr.nifti_1 = encode_nifti1(nifti);
% prepare two event structure that will go along with every sample/scan
evp = [];
evp.type = 'scan';
evp.value = 'pulse';
evp.offset = 0;
evp.duration = 0;
evp.sample = 0;
evr = evp;
evr.value = 'ready';
% assume acquisition + processing takes 30% of a TR cycle
TP = 0.3 * TR;
% make some fake MRI data
% Sphere = volume containing a spherical "head"
% Left/Right = volume of same size, adds a bit of fake activation
x = linspace(-1,1,voxels(1));
y = linspace(-1,1,voxels(2));
z = linspace(-1,1,voxels(3));
[X,Y,Z] = meshgrid(x,y,z);
R = sqrt(X.^2 + Y.^2 + Z.^2);
Sphere = single(1200 * (1./(1 + exp(40*(R-0.8)))));
R = sqrt((X-0.4).^2 + Y.^2 + Z.^2);
Left = single(60 * (1./(1 + exp(40*(R-0.4)))));
R = sqrt((X+0.4).^2 + Y.^2 + Z.^2);
Right = single(60 * (1./(1 + exp(40*(R-0.4)))));
stopwatch = tic;
% write header to FieldTrip buffer
ft_write_data(cfg.target.datafile, single([]), 'header', hdr, 'dataformat', cfg.target.dataformat, 'append', false);
numPulse = 0;
numScan = 0;
while true
% simulate acquisition of pixeldata
t0 = toc(stopwatch);
% write 'scan pulse' event
numPulse = numPulse + 1;
evp.sample = numPulse;
fprintf('Sending pulse: %3i, clock time = %f\n', numPulse, t0);
ft_write_event(cfg.target.datafile, evp);
if numPulse > 1
% fake acquisition + processing
lateral = 0.5 + 0.5*sin(2*pi*numScan/20);
Noise = single(30*randn(voxels));
scan = single(Sphere + lateral*Left + (1-lateral)*Right + Noise);
tp = toc(stopwatch);
pause(TP - (tp-t0));
ft_write_data(cfg.target.datafile, scan(:), 'append', true);
% write 'scan ready' event
numScan = numScan + 1;
evr.sample = numScan;
fprintf('Scans written: %3i, clock time = %f\n', numScan, toc(stopwatch));
ft_write_event(cfg.target.datafile, evr);
end
tr = toc(stopwatch);
pause(numPulse*TR - tr);
end