Hi, I have two queries I'm looking for help with.
1. Why is there a scaling difference between the magnitude of the data recorded in the noise scans, and the output of the rmegpreproc pipeline? I find about 30 orders of magnitude difference between the variance of the empty room scan and the variance of the data outputted by rmegpreproc. Have the data been uniformly scaled? If so, by how much? This would be useful information, for example, when source localising using the empty room data as an estimate of the noise. 2. When source localizing with a beamformer, I find an unusual variance profile in the resting state data. Normally when we look at resting data, the source variance is concentrated in a 'halo' around the outside of the cortex. In the HCP data, this halo is present, but there is also a bright stripe bisecting the brain around the central sulcus. We find this suprising, but have been unable to determine what's causing it. The effect is very repeatable between participants. I attach a screenshot of the effect, and two scripts to replicate the analysis. Any help or insights would be greatly appreciated. Many thanks, Giles _______________________________________________ HCP-Users mailing list HCP-Users@humanconnectome.org http://lists.humanconnectome.org/mailman/listinfo/hcp-users
% script to replicate weird source variance activity in HCP MEG data % Giles Colclough % 12 February 2015 %% Load in relevant data dataDir = '/home/gileslc/data/hcp/HCPsensor/'; subjID = 185442; iSession = 5; megDir = fullfile(datadir, num2str(subjID), '/MEG/Restin/rmegpreproc/'); anatomyDir = fullfile(datadir, num2str(subjID), '/MEG/anatomy/'); megFile = fullfile(megDir, sprintf('%d_MEG_%d-Restin_rmegpreproc.mat', subjID, iSession)); headFile = fullfile(anatomyDir, sprintf('%d_MEG_anatomy_headmodel.mat', subjID)); sourceFile = fullfile(anatomyDir, sprintf('%d_MEG_anatomy_sourcemodel_3d8mm.mat', subjID)); % use 8mm resolution load(megFile); % loads data load(headFile); % loads headmodel load(sourceFile); % loads sourcemodel3d mni_brain_2mm = '/home/gileslc/OSL-Repo/osl2/std_masks/MNI152_T1_2mm_brain.nii.gz'; mni_brain_8mm = '/home/gileslc/OSL-Repo/osl2/std_masks/MNI152_T1_8mm_brain.nii.gz'; % downsampled MNI152_T1_2mm_brain.nii.gz %% Prepare the data grad = data.grad; % apply gradiometers - copied from hcp_icamne L100. grad = ft_apply_montage(grad, grad.balance.Supine, 'keepunused', 'yes', 'inverse', 'yes'); % Convert everything into mm sourcemodel3d = ft_convert_units(sourcemodel3d,'mm'); headmodel = ft_convert_units(headmodel,'mm'); grad = ft_convert_units(grad,'mm'); %% Compute the leadfields cfg = []; cfg.vol = headmodel; cfg.grid = sourcemodel3d; cfg.grad = grad; cfg.channel = data.label; cfg.normalize = 'no'; cfg.reducerank = 2; % prepare leadfields gridLF = ft_prepare_leadfield(cfg); %% Reshape data sourcedata = data; dat = cat(2, data.trial{:}); time = (1:size(dat,2))./data.fsample; % not real time, due to bad segments having been removed Fs = data.fsample; %% Bandpass filter before source localization % use wide-band 4-30 Hz reconstruction Fbp = [4 30]; N = 5; filteredData = ft_preproc_bandpassfilter(dat, data.fsample, Fbp, N); %% Compute the beamformer weights C = cov(dat.'); % reduce dimensionality dimensionality = 220; invC = pinv_plus(C,dimensionality); % rank for leadfields reduce_rank = 2; for i = length(gridLF.inside):-1:1; lf = gridLF.leadfield{gridLF.inside(i)}; tmp = lf' * invC *lf; nn = size(lf,2); % collapse to scalar [eta,~] = svds(real(pinv_plus(tmp(1:nn,1:nn),reduce_rank,0)),1); lf = lf * eta; lf_mag(i) = norm(lf); % LCMV weights W{i} = lf'*invC/(lf' * invC * lf); W_mag(i) = norm(W{i}); % Apply weights normalisation W{i} = W{i} ./ sqrt(W{i}*W{i}'); end%for % reformat W weights = cat(1, W{:}); %% Compute source variance sourceVar = diag(weights * C * weights.'); %% Output nifti file % we need to to a bit of convoluted resampling to get into mni space for % fslview % declare empty volume of same size as grid vol = zeros(length(sourcemodel3d.cfg.grid.template.xgrid), ... length(sourcemodel3d.cfg.grid.template.ygrid), ... length(sourcemodel3d.cfg.grid.template.zgrid)); % fill in volume with source variance at correct locations for vox = sourcemodel3d.cfg.grid.template.inside; vol(sourcemodel3d.cfg.grid.template.pos(vox,1) == sourcemodel3d.cfg.grid.template.xgrid,... sourcemodel3d.cfg.grid.template.pos(vox,2) == sourcemodel3d.cfg.grid.template.ygrid,... sourcemodel3d.cfg.grid.template.pos(vox,3) == sourcemodel3d.cfg.grid.template.zgrid) = ... sourceVar(vox == sourcemodel3d.cfg.grid.template.inside); end%for % resample to appropriate nifti space [~, dims, scales] = read_avw(mni_brain_8mm); mni_grid_x = 90 - (0:dims(1)-1)*scales(1); mni_grid_y = -126 + (0:dims(2)-1)*scales(2); mni_grid_z = -72 + (0:dims(3)-1)*scales(3); % turn grid vectors into full matrices [mni_grid_x, mni_grid_y, mni_grid_z] = ndgrid(mni_grid_x, mni_grid_y, mni_grid_z); x_mm = round(sourcemodel3d.cfg.grid.template.xgrid * 10); y_mm = round(sourcemodel3d.cfg.grid.template.ygrid * 10); z_mm = round(sourcemodel3d.cfg.grid.template.zgrid * 10); % perform interpolation Vq = interpn(x_mm, y_mm, z_mm,... vol, ... mni_grid_x, ... mni_grid_y, ... mni_grid_z); % output nifti niiFileName = 'source_variance.nii'; niiFileName_2mm = 'source_variance_ds2mm.nii'; save_avw(Vq, niiFileName, 'f', [8 8 8 1]); % dilate volume to avoid edge effects unix(['fslmaths ' niiFileName ' -kernel gauss 8 -dilM ' niiFileName_2mm]); % resample unix(['flirt -in ' niiFileName_2mm ' -applyxfm -init ' getenv('FSLDIR') '/etc/flirtsch/ident.mat -out ' niiFileName_2mm ' -paddingsize 0.0 -interp trilinear -ref ' mni_brain_2mm]); % mask unix(['fslmaths ' niiFileName_2mm ' -mas ' mni_brain_2mm ' ' niiFileName_2mm]); %% View % look for an unusual high variance plane bisecting the front and back of % the brain - about the location of the central sulcus % This is markedly different to the normal 'halo' of high power around the % outside of the brain unix(['fslview ' mni_brain_8mm ' ' niiFileName ' -l Red-Yellow -b 6e-27,1.5e-26 -t 0.9 &']) unix(['fslview ' mni_brain_2mm ' ' niiFileName_2mm ' -l Red-Yellow -b 6e-27,1.5e-26 -t 0.9 &'])
function [X, pca_order] = pinv_plus(A,varargin) % PINV_PLUS Modified Pseudoinverse which allows a specified % dimensionality (order) to be passed in. % % pinv_plus(A) is the same as pinv(A) % % [X, pca_order]=pinv_plus(A,pca_order) uses at most only the top pca_order PCs to compute inverse % % pinv_plus(A,pca_order,1) uses precisely the top pca_order PCs to compute inverse % % If pca_order=-1 then calls spm_pca_order to compute order to use % % Class support for input A: % float: double, single % % Mark Woolrich tol=[]; r=size(A,1); if nargin >= 2, pca_order = varargin{1}; if(pca_order==-1), pca_order=spm_pca_order(A); end; else pca_order = size(A,1); end; max_r=pca_order; if nargin >= 3, fix_to_max_r=varargin{2}; else fix_to_max_r=0; end; if isempty(A) % quick return X = zeros(size(A'),class(A)); return end % [U,S,V] = svd(A,0); s = diag(S); [m,n] = size(A); if n > m X = pinv(A',varargin{:})'; else if(max_r<size(A,1)) %[U,S,V] = svds(A,max_r); [U,S,V] = svd(A,0); max_r=min(length(diag(S)),max_r); else [U,S,V] = svd(A,0); end; if m > 1, s = diag(S); elseif m == 1, s = S(1); else s = 0; end tol=[]; if max_r < 0 diffs=abs(diff(s)./s(1:end-1)); for i=2:length(diffs), if(diffs(i) > 6*mean(diffs(1:i))), break; end; end; max_r = i; %figure;plot(diffs);ho;plot(r,diffs(r),'*'); end; % max_r % fix_to_max_r if(fix_to_max_r==1), r=max_r; else, tol=max(m,n) * eps(max(s)); %tol=max(size(A)) * norm(A) * eps(class(A)); r = sum(s > tol); r = min(r,max_r); end; %figure;plot(s); s2=s; if (r == 0) X = zeros(size(A'),class(A)); else s = diag(ones(r,1)./s(1:r)); X = V(:,1:r)*s*U(:,1:r)'; end pca_order=r; end