Giter Club home page Giter Club logo

Comments (5)

ftadel avatar ftadel commented on May 23, 2024

Current code proposition (also include in the .zip above):

% Trying to rebuild missing from the HCP pre-processed files. 
% We want to reconstruct separate matrices from the .tra matrix, with the help of the .balance field:
%   - the sparse coil-channel correspondance matrix
%   - the noise-compensation matrix applied by 4D acquisition system
%   - the PCA/ICA cleaning procedures
%
% Authors: Francois Tadel, 2017

% Load example structure: Subject HCP/891667, resting state recordings pre-processed with FieldTrip
ftMat = load('891667_MEG_3-Restin_rmegpreproc_5trials.mat');
ftMat = ftMat.data;
grad = ftMat.grad;


% === FIX STRUCTURE ===
% Suggestion from JM: Fix glitches in the grad structure with ft_datatype_sens
% Reference: http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3298#c6
% Problem: does not fix retroactively the history in the .balance field
grad = ft_datatype_sens(grad);


% === REVERT TO THE ORIGINAL .TRA MATRIX ===
% Suggestion from JM: Use ft_apply_montage to revert to the original .tra matrix
% Reference: http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3298#c3
%
% Problems: There are lots of inconsistencies in the .balance fields of the HCP files:
%   1) The output channel units and types in transformation "pca" are set to "unknown"
%   2) Random naming chanunitorg/chanunitold fields
%   3) Channel types change randomly between "meg" (eg. pca) and "megmag" (eg. invcomp)
% Reference: http://bugzilla.fieldtriptoolbox.org/show_bug.cgi?id=3298#c5

% Get the list of montages to undo
montageList = {grad.balance.current};
if ~isempty(grad.balance.previous)
    montageList = cat(2, montageList, grad.balance.previous{:});
end

% Undo montages one by one
for iMontage = 1:length(montageList)
    % Make sure the montage is defined in the structure
    mont = montageList{iMontage};
    if ~isfield(grad.balance, mont)
        continue;
    end
    
    % ISSUE #1: Trying to fix units and types  (with randomness of issue #2)
    if isfield(grad.balance.(mont), 'chanunitnew') && strcmpi(grad.balance.(mont).chanunitnew{1}, 'unknown')
        if isfield(grad.balance.(mont), 'chanunitorg')
            grad.balance.(mont).chanunitnew = grad.balance.(mont).chanunitorg;
        elseif isfield(grad.balance.(mont), 'chanunitold')
            grad.balance.(mont).chanunitnew = grad.balance.(mont).chanunitold;
        end
    end
    if isfield(grad.balance.(mont), 'chantypenew') && strcmpi(grad.balance.(mont).chantypenew{1}, 'unknown')
        if isfield(grad.balance.(mont), 'chantypeorg')
            grad.balance.(mont).chantypenew = grad.balance.(mont).chantypeorg;
        elseif isfield(grad.balance.(mont), 'chantypeold')
            grad.balance.(mont).chantypenew = grad.balance.(mont).chantypeold;
        end
    end
    
%     % ISSUE #3: Trying to fix the channel types
%     % DOES NOT WORK BECAUSE THE ORDER OF THE CHANNELS CHANGE
%     if isfield(grad.balance.(mont), 'chantypenew') && (length(grad.balance.(mont).chantypenew) == length(grad.chantype))
%         grad.balance.(mont).chantypenew = grad.chantype;
%     end
%     if isfield(grad.balance.(mont), 'chantypeorg') && (length(grad.balance.(mont).chantypeorg) == length(grad.chantype))
%         grad.balance.(mont).chantypeorg = grad.chantype;
%     end
%     if isfield(grad.balance.(mont), 'chantypeold') && (length(grad.balance.(mont).chantypeold) == length(grad.chantype))
%         grad.balance.(mont).chantypeold = grad.chantype;
%     end
    
    % Reverse transformation
    grad = ft_apply_montage(grad, grad.balance.(mont), 'inverse', 'yes', 'keepunused', 'yes');
end


% === REBUILD ORIGINAL COIL-CHANNEL MATRIX ===
% Remove small values (probably due to the multiple matrix inversions) to keep only the ones
grad.tra(abs(grad.tra) < 0.1) = 0;

% For each channel
for i = 1:length(ftMat.label)
    % MEG sensors
    if isfield(ftMat, 'grad') && ~isempty(ftMat.grad) && isfield(ftMat.grad, 'tra') && isfield(ftMat.grad, 'label') && ~isempty(ftMat.grad.label) && ismember(ftMat.label{i}, ftMat.grad.label)
        % Find channel index
        ichan = find(strcmpi(ftMat.label{i}, grad.label));
        % Find corresponding coils
        icoils = find(grad.tra(ichan,:));
        
        % Error: Two many coils
        if (length(icoils) > 2)
            error(['Wrong number of coils for channel ', ftMat.label{i}, ': Cannot import this file correctly...']);
        end
        % Get sensor properties
        Loc    = ftMat.grad.coilpos(icoils,:)';
        Orient = ftMat.grad.coilori(icoils,:)';
        Weight = ftMat.grad.tra(ichan,icoils);
    end
end

from fieldtrip.

schoffelen avatar schoffelen commented on May 23, 2024

I agree that it's a mess

what seems to work for me (that is, it produces a tra matrix that can be used for channel/coil mapping), when I remove the chanunitNEW/OLD/ORG and chantypeNEW/OLD/ORG from the montage prior to using it in ft_apply_montage, i.e.

montage = somegrad.balance.(somename);
montage = removefields(montage, {'chanunitnew' 'chanunitold' 'chanunitorg' 'chantypenew' 'chantypeold' 'chantypeorg'}); % this is a fieldtrip function that behaves the same as rmfield, apart from that it does not throw an error if a field is missing

somenewgrad = ft_apply_montage(somegrad, montage, 'keepunused', 'yes', 'inverse', 'yes');

from fieldtrip.

schoffelen avatar schoffelen commented on May 23, 2024

Some additional comments: I recall that we had quite some discussions in the HCP MEG team about how to handle the Supine weights, and I believe that we settled on removing this from the grad.tra matrix prior to further processing. Note that we did not 'undo' the same balancing on the sensor data. The reason we decided to do this I don't fully remember, but I think that applying the Supine weights to the leadfields caused strangely distorted topographies, which we did not trust in the end. Another observation, albeit anecdotally, was that the source reconstructed resting state maps made more 'sense' to the Chieti team, when using unbalanced (by Supine weights) gradiometer arrays.

Perhaps @gmichalareas or @robertoostenveld can confirm this.

Anyway, the resulting tra matrix is not fully sparse (containing only 0's and 1's, which could be due to the fact that this appears to be data from the resting state condition (data.cfg.previous.previous.previous{1}.previous.previous.previous.previous.previous.previous.datafile) tells me this, and it could well be that it's due to the 'invcomp' step being not full rank due to discarded channels

from fieldtrip.

ftadel avatar ftadel commented on May 23, 2024

Thanks for the suggestion, now I can rebuild the coil-channel matrix.

From what I understand from your second message: the first step of processing of the continuous 4D recordings was to undo the 4D noise compensation. But what do you mean with "Note that we did not 'undo' the same balancing on the sensor data"? Did you just remove it from the .tra matrix without applying the corresponding inverse transform to the MEG recordings?
Are we supposed to use this "invcomp" projector in the computation of the forward operator?

Is this formally documented somewhere? Do you have any written trace of why you decided to cancel the 4D noise compensation? This would be worth sharing with the users of the HCP-MEG data.
Do you know if there any published study of the impact of the 4D noise compensation on the source modeling?

from fieldtrip.

robertoostenveld avatar robertoostenveld commented on May 23, 2024

This seems to be HCP specific, not related to the FieldTrip code. So let me close it here.

from fieldtrip.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.