hns_loadfiff5.p

Neuromag独自のFIFFは、MNE-python開発団によって、Windows、Linux、MacOSのpython上で読み書きできるようになりました。 MNE-CやMNE-pythonではFIFFのタグを独自に追加したFIFFファイルが出現しています。 順問題や逆問題の変数にも新たなFIFFのタグがつけられ、 epoch毎切りだした、時間×チャンネル×エポックからなる三次元配列のタグとかもあります。 MNE-pythonは、いろいろな解析手法が開陳されていますが、従来の解析方法はカバーしていません。 そこでまだまだMATLABを使い続ける必要がありそうです。 MNE-pythonのshow_fiff機能を参考に、新たに付加されたFIFFのタグに対応したhns_loadfiff5を作成しました。 FIFFの構造は一般には公開されてないと思いますので、pcodeでコードを隠匿しました。

hns_loadfiff5.pは http://meg.aalip.jp/matlab/data/hns_loadfiff5.p から入手してください。

尚、hns_loadfiff4と出力される構造体に変更があります。 MATLAB R2017bで実行しています。MATLABはR2016から大幅な変更があり、旧いversionだとうまく動作しないかもしれません。

Contents

加算波形表示

データはMNE-pythonのサンプルデータとします。 mne-sample-data-pathにパスを通しておいてください。 4つの加算波形があります。 pythonだと変数の中身を確認するのが大変ですが、MATLABだと簡単で便利です。 FIFFファイル自体はブロック構造が入れ子入れ子という複雑な構造になっています。 hns_fiff4は利用しやすく変数をまとめているのです。 hns_fiff5でも4との互換性を保つため主な変数は残しています。 また脳波用のSSPがありましたので、PCA_100xとして追加することにしました。 脳波のチャンネル情報の位置情報を表示させていますが、HPIでプロットしたものではなく、合ってるかどうか不明です。

F=hns_loadfiff5('sample_audvis-ave.fif') % ;はナシ
% ベースラインの設定
time=F.ave_0001(:,end);
t=find(time>=-0.2 & time<0);% baseline
baseline=mean(F.ave_0001(t,1:end-1));
data=F.ave_0001(:,1:end-1)-ones(length(time),1)*baseline;
% チャンネル名
nch=length(F.ChanName);
ch=zeros(1,nch);
for n=1:nch
   if contains(F.ChanName{n},'MEG')
       if ismember(F.ChanName{n}(end),{'2','3'})
           ch(n)=1;% gradiometer
       else
           ch(n)=2;% magnetometer
       end
   elseif contains(F.ChanName{n},'EEG')
       ch(n)=3; % EEG
   end
end
% SSPの設定 脳波はPCA_100nとしました。
for m=1:2
    if m==1 % MEG
        x=[1,2];
        ch0=1;
        ch1=999;
    elseif m==2 % EEG
        x=3;
        ch0=1001;
        ch1=1999;
    end
    chs=find(ismember(ch,x));
    SSP=eye(length(chs));
    for n=ch0:ch1
        nPCA=sprintf('PCA_%04.0f',n);
        if isfield(F,nPCA)
            nPCA=eval(['F.',nPCA]);
            SSP=SSP-nPCA*nPCA';
        else
            break;
        end
    end
   data(:,chs)=data(:,chs)*SSP;
end
% 波形表示
figure;
for n=1:3
    subplot(3,1,n);
    x=find(ismember(ch,n));
    plot(time,data(:,x),'b');
    axis tight;
    switch n
        case 1;title('planar gradiometer');
        case 2;title('magnetometer');
        case 3;title('EEG');
    end
end
% 頭皮プロット点とセンサ表示
figure('color',[1,1,1]);
plot3(F.DigitPts(:,1),F.DigitPts(:,2),F.DigitPts(:,3),'ro','markerfacecolor',[1,0.5,0]);
hold on;
p=F.ChInform(:,ch==2);
N=size(p,2);
X=F.MEG2HEAD;
p0=X(:,1:3)*p(1:3,:)+diag(X(:,4))*ones(3,N);
px=X(:,1:3)*p(4:6,:)*0.014;
py=X(:,1:3)*p(7:9,:)*0.014;
pz=X(:,1:3)*p(10:12,:)*0.0003;
p0=p0+pz;
V=zeros(3,N,4);
V(:,:,1)=p0+px+py;
V(:,:,2)=p0+px-py;
V(:,:,3)=p0-px-py;
V(:,:,4)=p0-px+py;
h=fill3(squeeze(V(1,:,:))',squeeze(V(2,:,:))',squeeze(V(3,:,:))',ones(4,N));
set(h,'facecolor',[0,1,1],'facealpha',0.5);
p0=F.ChInform(:,ch==3);
plot3(p0(1,:),p0(2,:),p0(3,:),'b^','markerfacecolor',[0.5,0.5,1]);% HPIでプロットした脳波位置と同一かどうか不明
daspect([1,1,1]);
view([-150,0]);
axis tight;
rotate3d on;
F = 

  フィールドをもつ struct:

        file_id: [1×1 struct]
    dir_pointer: 5535745
      free_list: -1
           meas: [1×1 struct]
            nop: []
            dir: [677×4 int32]
       filename: 'sample_audvis-ave.fif'
       ave_0001: [421×377 double]
       ave_0002: [421×377 double]
       ave_0003: [421×377 double]
       ave_0004: [421×377 double]
       DigitPts: [146×3 double]
       ChInform: [12×376 double]
       ChanName: {1×376 cell}
       ExamDate: '03-Dec-2002 04:01:10'
       MEG2HEAD: [3×8 single]
       CalXRnge: [1×377 double]
       PCA_0001: [306×1 double]
       PCA_0002: [306×1 double]
       PCA_0003: [306×1 double]
       PCA_1001: [60×1 double]
        version: 'Released on 13-Nov-2017↵Since 13-Nov-2017↵by Akira Hashizume'
           list: [677×5 int32]

自発波形表示

サンプルデータには脳波のSSP情報はないようです。 加算波形とは異なり、CalXRngeとraw_dataをかけて波形を表示させます。

F=hns_loadfiff5('sample_audvis_raw.fif') % ;はナシ
%
% チャンネル名
nch=length(F.ChanName);
ch=zeros(1,nch);
for n=1:nch
   if contains(F.ChanName{n},'MEG')
       if ismember(F.ChanName{n}(end),{'2','3'})
           ch(n)=1;% gradiometer
       else
           ch(n)=2;% magnetometer
       end
   elseif contains(F.ChanName{n},'EEG')
       ch(n)=3; % EEG
   end
end
% SSP
SSP=eye(length(F.PCA_0001));
for n=1:999
   if isfield(F,sprintf('PCA_%04.0f',n))
       nPCA=eval(sprintf('F.PCA_%04.0f;',n));
       SSP=SSP-nPCA*nPCA';
   end
end
% 30~60秒を表示することとする。
sfreq=F.CalXRnge(end);
t=round([30,60]*sfreq);
t=t(1):t(end);
time=t/sfreq;
figure;
for n=1:3
    subplot(3,1,n);
    chn=find(ch==n);
    nch=length(chn);
    data=diag(F.CalXRnge(chn))*double(F.raw_data(chn,t));
    plot(time,data,'b');
    set(gca,'xlim',[time(1),time(end)]);
    switch n
        case 1;title(sprintf('planar gradiometer %dch',nch));
        case 2;title(sprintf('magnetometer %dch',nch));
        case 3;title(sprintf('EEG %dch',nch));
    end
end
F = 

  フィールドをもつ struct:

         file_id: [1×1 struct]
     dir_pointer: -1
       free_list: -1
            meas: [1×1 struct]
             nop: []
    bad_channels: [1×1 struct]
         ch_name: 'MEG 2443:EEG 053'
        filename: 'sample_audvis_raw.fif'
        DigitPts: [146×3 double]
        ChInform: [12×376 double]
        ChanName: {1×376 cell}
        ExamDate: '03-Dec-2002 04:01:10'
        MEG2HEAD: [3×8 single]
        CalXRnge: [1×377 double]
        raw_data: [376×166800 int16]
        PCA_0001: [306×1 double]
        PCA_0002: [306×1 double]
        PCA_0003: [306×1 double]
         version: 'Released on 13-Nov-2017↵Since 13-Nov-2017↵by Akira Hashizume'
            list: [918×5 int32]

エポックファイル

F.EpocDatahは時間×チャンネル×試行からなる三次元配列です。 planar gradiometerでエポックを切り出し、aaa-epo.fifで保存したファイルを読み込みんでみます。 planar gradiometerだけですのでSSPはありません。 stack波形を試行順にx軸方向に並べました。

F=hns_loadfiff5('aaa-epo.fif') % ;はナシ
figure;
t=F.EpocTime;%/F.meas.meas_info.sfreq;
for n=1:size(F.EpocData,3)
    xx=squeeze(F.EpocData(:,:,n));
    plot(t+(n-1),xx,'b');
    if n==1;hold on;end
end
axis tight;
F = 

  フィールドをもつ struct:

        file_id: [1×1 struct]
    dir_pointer: -1
      free_list: -1
           meas: [1×1 struct]
            nop: []
       filename: 'aaa-epo.fif'
       EpocTime: [106×1 double]
       EpocData: [106×204×67 double]
       DigitPts: [146×3 double]
       ChInform: [12×204 double]
       ChanName: {1×204 cell}
       ExamDate: '03-Dec-2002 04:01:10'
       MEG2HEAD: [3×8 single]
       CalXRnge: [1×205 double]
        version: 'Released on 13-Nov-2017↵Since 13-Nov-2017↵by Akira Hashizume'
           list: [471×5 int32]

空間フィルタファイル

MNE側で独自に拡張したFIFFファイルでxxx-inv.fifという名前になっています。 まだ詳細不明な項目が残ったままになっています。 電流源の置き方に、脳表三角メッシュの頂点に置く場合と等間隔で脳を分割した格子点とがあります。 計算量を減らすため、電流源を間引いて電流源推定しています。 脳表メッシュでは 左半球の△310810を△8192にし、電流源を155407点中3732点に減らし、 右半球の△313728を△8192にし、電流源を156866点中3766点に減らしています。 格子点では電流源を13104点中3757点に減らしています。

% 脳表メッシュ
filename='sample_audvis-meg-eeg-oct-6-meg-eeg-inv.fif';
F=hns_loadfiff5(filename)% ;はナシ
disp('F.mne');
F.mne
disp('F.mne.mne_source_space{1} % left hemisphere');
F.mne.mne_source_space{1}
disp('F.mne.mne_source_space{2} % right hemisphere');
F.mne.mne_source_space{2}
for m=1:2
    figure;
    for n=1:2
        S=F.mne.mne_source_space{n};
        p=double(S.source_rr);% メッシュ頂点
        if m==1
            h=trimesh(S.tris',p(1,:),p(2,:),p(3,:));
        else
            h=trimesh(S.use_tris',p(1,:),p(2,:),p(3,:));
        end
        set(h,'edgecolor',[1,1,1]*0.6,'facecolor','none','facealpha',0.5);
        hold on;
        q=double(S.source_nn); % 方向
        k=find(S.inuse==1);% 使用された格子点
        quiver3(p(1,k),p(2,k),p(3,k),q(1,k),q(2,k),q(3,k),'o','markersize',2);
    end
    daspect([1,1,1]);
    axis tight;
    view([-148,6]);
    rotate3d on;
    title('polygonmesh');
end

% 格子点
F=hns_loadfiff5('sample_audvis-meg-vol-7-meg-inv.fif') % ;はナシ
disp('F.mne');
F.mne
disp('F.mne.mne_source_space'); % lattices
F.mne.mne_source_space
figure;
S=F.mne.mne_source_space;
p=double(S.source_rr);% 格子点
q=double(S.source_nn);% 方向
k=find(S.inuse==1);% 使用された格子点
plot3(p(1,:),p(2,:),p(3,:),'color',[1,1,1]*0.9,'marker','.');
hold on;
quiver3(p(1,k),p(2,k),p(3,k),q(1,k),q(2,k),q(3,k),'ro','markersize',2);% 13104点中3757点使用
daspect([1,1,1]);
axis tight;
view([-148,6]);
rotate3d on;
title('lattices');
F = 

  フィールドをもつ struct:

        file_id: [1×1 struct]
    dir_pointer: -1
      free_list: -1
            mne: [1×1 struct]
            nop: []
        mne_env: [1×1 struct]
       filename: 'sample_audvis-meg-eeg-oct-6-meg-eeg-inv.fif'
        version: 'Released on 13-Nov-2017↵Since 13-Nov-2017↵by Akira Hashizume'
           list: [560×5 int32]

F.mne

ans = 

  フィールドをもつ struct:

               mne_meg_file: [1×1 struct]
    mne_trans_coord_meg2mri: [1×1 struct]
                  xfit_proj: [1×1 struct]
           mne_source_space: {[1×1 struct]  [1×1 struct]}
                    mne_inv: [1×1 struct]

F.mne.mne_source_space{1} % left hemisphere

ans = 

  フィールドをもつ struct:

              space_type: 1
                space_id: 101
             subj_his_id: 'sample'
             coord_frame: 4
              n_vertices: 155407
               source_rr: [3×155407 single]
               source_nn: [3×155407 single]
                   inuse: [1×155407 int32]
                  n_used: 3732
                    nrti: 310810
                    tris: [3×310810 int32]
                nuse_tri: 8192
                use_tris: [3×8192 int32]
           nearest_array: [1×155407 int32]
            nearest_dist: [1×155407 single]
    source_potential_sol: [155407×155407 double]
              dist_limit: -829934272

F.mne.mne_source_space{2} % right hemisphere

ans = 

  フィールドをもつ struct:

              space_type: 1
                space_id: 102
             subj_his_id: 'sample'
             coord_frame: 4
              n_vertices: 156866
               source_rr: [3×156866 single]
               source_nn: [3×156866 single]
                   inuse: [1×156866 int32]
                  n_used: 3766
                    nrti: 313728
                    tris: [3×313728 int32]
                nuse_tri: 8192
                use_tris: [3×8192 int32]
           nearest_array: [1×156866 int32]
            nearest_dist: [1×156866 single]
    source_potential_sol: [156866×156866 double]
              dist_limit: -829934272


F = 

  フィールドをもつ struct:

        file_id: [1×1 struct]
    dir_pointer: -1
      free_list: -1
            mne: [1×1 struct]
            nop: []
        mne_env: [1×1 struct]
       filename: 'sample_audvis-meg-vol-7-meg-inv.fif'
        version: 'Released on 13-Nov-2017↵Since 13-Nov-2017↵by Akira Hashizume'
           list: [487×5 int32]

F.mne

ans = 

  フィールドをもつ struct:

               mne_meg_file: [1×1 struct]
    mne_trans_coord_meg2mri: {[1×1 struct]  [1×1 struct]}
                  xfit_proj: [1×1 struct]
           mne_source_space: [1×1 struct]
                    mne_inv: [1×1 struct]

F.mne.mne_source_space

ans = 

  フィールドをもつ struct:

                  space_type: 2
                 coord_frame: 4
                  n_vertices: 13104
                   source_rr: [3×13104 single]
                   source_nn: [3×13104 single]
                       inuse: [1×13104 int32]
                      n_used: 3757
    source_space_nneighbours: [1×13104 int32]
     source_space_neighbours: [1×340704 int32]
                 coord_trans: [1×1 struct]
     source_space_voxel_dims: [21 26 24]
     mne_trans_coord_meg2mri: [1×1 struct]

STCファイル

STCファイルはsources time courseの略です。電流源の経時変化情報が記載されています。 電流源の位置は記載されていません。

for n=1:2
    if n==1
        filename='sample_audvis-meg-eeg-lh.stc';% 左半球
        figure;
        st='left hemisphere';
    else
        filename='sample_audvis-meg-eeg-rh.stc';% 右半球
        st='right hemisphere';
    end
    F=hns_loadfiff5(filename)
    subplot(1,2,n);
    time=(1:size(F.data,2))'*F.tstep;
    plot(time,F.data,'b');
    set(gca,'xlim',[time(1),time(end)],'ylim',[0,30]);
    title(st);
end
F = 

  フィールドをもつ struct:

        tmin: 0
       tstep: 0.0100
    vertices: [3732×1 uint32]
        data: [3732×25 single]


F = 

  フィールドをもつ struct:

        tmin: 0
       tstep: 0.0100
    vertices: [3766×1 uint32]
        data: [3766×25 single]

Wファイル

WファイルはSTCファイルのある一時点の電流源の番号と電流の大きさを示すデータです。 要するにSTCファイルのverticesとdataの1行分のデータです。 どの時間のデータか?の情報はありません。

filename='sample_audvis-meg-oct-6-fwd-sensmap-lh.w';
F=hns_loadfiff5(filename)
F = 

  フィールドをもつ struct:

    vertices: [3732×1 uint32]
        data: [3732×1 single]

labelファイル

これ、実はテキストファイルです。

clear F;
filename='lh.cortex.label';
F=hns_loadfiff5(filename)
F = 

  フィールドをもつ struct:

     comment: '#!ascii label  , from subject  vox2ras=TkReg ↵'
    vertices: [147147×1 int32]
         pos: [147147×3 double]
      values: [147147×1 double]