Home > NoiseTools > nt_cca_mm.m

nt_cca_mm

PURPOSE ^

[D,E,R]=nt_cca_mm(x,y,ssize,ldaflag,nccs) - calculate metrics for match-mismatch task

SYNOPSIS ^

function [D,E,R,EXTRA]=nt_cca_mm(x,y,ssize,ldaflag,nccs)

DESCRIPTION ^

[D,E,R]=nt_cca_mm(x,y,ssize,ldaflag,nccs) - calculate metrics for match-mismatch task

  D: d-prime 
  E: error rate
  R: correlation coefficient over entire trial
  EXTRA: struct with additional info:
    .D_match: matrix of euclidean distances for matching segments
    .D_mismatch: matrix of euclidean distances averaged over mismatched segments
    .rms_eeg: matrix of RMS of EEG segments
    .rms_stim: matrix of RMS of stim segments

  x,y: data as trial arrays
  ssize: samples, segment size [default: all]
  ldaflag: 0: first CC, 1: LDA, 2: sum, p<1: weight with exp p
  nccs: number of CCs to keep [default: all]

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function [D,E,R,EXTRA]=nt_cca_mm(x,y,ssize,ldaflag,nccs)
0002 %[D,E,R]=nt_cca_mm(x,y,ssize,ldaflag,nccs) - calculate metrics for match-mismatch task
0003 %
0004 %  D: d-prime
0005 %  E: error rate
0006 %  R: correlation coefficient over entire trial
0007 %  EXTRA: struct with additional info:
0008 %    .D_match: matrix of euclidean distances for matching segments
0009 %    .D_mismatch: matrix of euclidean distances averaged over mismatched segments
0010 %    .rms_eeg: matrix of RMS of EEG segments
0011 %    .rms_stim: matrix of RMS of stim segments
0012 %
0013 %  x,y: data as trial arrays
0014 %  ssize: samples, segment size [default: all]
0015 %  ldaflag: 0: first CC, 1: LDA, 2: sum, p<1: weight with exp p
0016 %  nccs: number of CCs to keep [default: all]
0017 
0018 zscore=1;
0019 lda=1;
0020 
0021 if nargin<2; error('!'); end
0022 if nargin<3; ssize=[]; end
0023 if nargin<4||isempty(ldaflag); ldaflag=1; end
0024 if nargin<5; nccs=[]; end
0025 
0026 if ssize ~= round(ssize); error('!'); end
0027 
0028 % find smallest trial size across trials
0029 nsamples=size(x{1},1); % min size over trials
0030 ntrials=numel(x);
0031 for iTrial=1:ntrials
0032     if size(x{iTrial}) ~= size(y{iTrial}); error('!'); end
0033     nsamples=min(nsamples,size(x{iTrial},1));
0034 end
0035 if isempty(ssize); ssize=nsamples; end % default: segment size = nsamples
0036 nsamples=ssize*floor(nsamples/ssize); % reduce nsamples to multiple of wsize
0037 
0038 % clip all trials to smallest size
0039 if nsamples<1; error('!'); end
0040 for iTrial=1:ntrials
0041     x{iTrial}=nt_demean(x{iTrial}(1:nsamples,:)); % clip trials to new length
0042     y{iTrial}=nt_demean(y{iTrial}(1:nsamples,:));
0043 end
0044 nsegments=nsamples/ssize; % number of segments per trial
0045 
0046 % sanity check
0047 if 0 
0048     % scramble (should yield approx d-prime==0 and error == 50%)
0049     for iTrial=1:ntrials
0050         y{iTrial}=y{1+mod(iTrial+5,ntrials)};
0051         %disp([iTrial, 1+mod(iTrial+5,ntrials)]);
0052     end
0053 end
0054 
0055 % cross-validated CCA
0056 shifts=[0]; 
0057 [AA,BB,~]=nt_cca_crossvalidate(x,y,shifts);
0058 
0059 % select reduced number of CCs
0060 if isempty(nccs)
0061     nccs=size(AA{1},2);
0062 else
0063     nccs=min(nccs,size(AA{1},2));
0064     for iTrial=1:ntrials
0065         AA{iTrial}=AA{iTrial}(:,1:nccs);
0066         BB{iTrial}=BB{iTrial}(:,1:nccs);
0067     end
0068     %RR=RR(1:nccs,:,:);
0069 end
0070 
0071 DD_match=[]; % normalized Euclidean distance for matching trials
0072 DD_mismatch=[]; % normalized Euclidean distance for mismatched trials
0073 RR=[];
0074 rms_eeg=[];
0075 rms_stim=[];
0076 
0077 % crossvalidation loop
0078 for iTrial=1:ntrials
0079     
0080     %{
0081     The CCA solution (AA, BB) was calculated on the basis of other trials.     
0082     We apply it to segments of this trial.
0083     %}
0084 
0085     % CCs
0086     cc_x=nt_mmat(x{iTrial},AA{iTrial});
0087     cc_y=nt_mmat(y{iTrial},BB{iTrial});
0088     %cc_x=nt_mmat(y{1+mod(iTrial,ntrials)},BB{iTrial}); % scramble
0089     
0090     % cut CCs into segments
0091     S_x=zeros(ssize,nccs,nsegments);
0092     S_y=zeros(ssize,nccs,nsegments);
0093     for iSegment=1:nsegments
0094         start=(iSegment-1)*ssize;
0095         S_x(:,:,iSegment)=cc_x(start+(1:ssize),:); 
0096         S_y(:,:,iSegment)=cc_y(start+(1:ssize),:);
0097      end
0098 
0099     % RMS of EEG and stim over each segment
0100     a=sqrt(mean(S_x.^2,1)); % average over samples
0101     a=permute(a,[2 3 4 1]); % get rid of singleton
0102     a=a(:,:); % size [nccs, nsegments*ntrials])
0103     a=mean(a); % average over CCs
0104     b=sqrt(mean(S_y.^2,1));
0105     b=permute(b,[2 3 4 1]);
0106     b=b(:,:);
0107     b=mean(b);
0108     rms_eeg=[rms_eeg;a(:)];
0109     rms_stim=[rms_stim;b(:)];
0110 
0111     
0112     % z-score each segment
0113     for iSegment=1:nsegments
0114         if zscore
0115             S_x(:,:,iSegment)=nt_normcol(nt_demean(S_x(:,:,iSegment))); % mean 0 norm 1
0116             S_y(:,:,iSegment)=nt_normcol(nt_demean(S_y(:,:,iSegment)));
0117         end
0118     end
0119     
0120     % For each envelope segment, we calculate the Euclidean distance between this segment and the corresponding
0121     % EEG segment (match) and between this segment and all the envelope segments of other trials (mismatch).
0122 
0123     % matching segments:
0124     
0125     % distance from each segment of audio to corresponding segment of EEG
0126     D_match=sqrt(mean((S_x-S_y).^2, 1));
0127     D_match=permute(D_match,[2 3 4 1]); % get rid of initial singleton
0128     D_match=D_match(:,:)'; % --> segments X comps
0129     
0130         
0131     % mismatched segments:
0132     
0133     % distance from each segment of x to all mismatched segments of y,
0134     % averaged over those segments
0135     S_x=S_x(:,:,:); 
0136     S_y=S_y(:,:,:);
0137     D_mismatch=zeros(size(S_x,3),size(S_x,3)-1, nccs);
0138     for iSegment=1:size(S_x,3)
0139         other_segments=setdiff(1:size(S_x,3),iSegment);
0140         if 1
0141             tmp=bsxfun(@minus,S_y(:,:,other_segments),S_x(:,:,iSegment));
0142         else
0143             % flip: each segment of y with all mismatched segments of x
0144             tmp=bsxfun(@minus,S_x(:,:,other_segments),S_y(:,:,iSegment));
0145         end
0146         d=sqrt(mean(tmp.^2, 1));
0147         D_mismatch(iSegment,:,:)=permute(d,[1 3 2]);
0148     end
0149     D_mismatch=mean(D_mismatch,2); % average over all other segments
0150     D_mismatch=permute(D_mismatch,[1 3 2]); 
0151     
0152     
0153     if ldaflag==1
0154         %{
0155         We want to transform distance scores (one per CC) using LDA. 
0156         
0157         To get the LDA matrix to apply to this trial, we calculate a CCA
0158         solution based on the other trials, and calculate the LDA
0159         solution from that.
0160         %}
0161          
0162         % exclude this trial
0163         other_trials=setdiff(1:ntrials,iTrial);
0164 
0165         % CCs
0166         cc_x2=nt_mmat(x(other_trials),AA{iTrial}); % AA, BB: CCA xforms derived from other trials
0167         cc_y2=nt_mmat(y(other_trials),BB{iTrial});
0168 
0169         % cut CCs into segments
0170         % !!! why not just reshape?
0171         S_x=zeros(ssize,nccs,ntrials-1,nsegments);
0172         S_y=zeros(ssize,nccs,ntrials-1,nsegments);
0173         for iTrial2=1:ntrials-1
0174             for iSegment=1:nsegments
0175                 start=(iSegment-1)*ssize;
0176 
0177                 if zscore
0178                     S_x(:,:,iTrial2,iSegment)=nt_normcol(nt_demean(cc_x2{iTrial2}(start+(1:ssize),:))); % mean 0 norm 1
0179                     S_y(:,:,iTrial2,iSegment)=nt_normcol(nt_demean(cc_y2{iTrial2}(start+(1:ssize),:)));
0180                 else
0181                     S_x(:,:,iTrial2,iSegment)=cc_x2{iTrial2}(start+(1:ssize),:); 
0182                     S_y(:,:,iTrial2,iSegment)=cc_y2{iTrial2}(start+(1:ssize),:);
0183                 end
0184             end
0185         end    
0186         % S_x and S_y are of size [nsamples, nccs, (ntrials-1), nsegments]
0187 
0188         % --> [nsamples, nccs, (ntrials-1)*nsegments]:
0189         S_x=S_x(:,:,:); 
0190         S_y=S_y(:,:,:);
0191 
0192         % For each EEG segment, we calculate the Euclidean distance between this segment and the corresponding
0193         % envelope segment (match) and between this segment and all the envelope segments of other trials (mismatch).
0194 
0195         % match:
0196         % distance from each segment of audio to corresponding segment of EEG
0197         D_match2=sqrt(mean((S_x-S_y).^2, 1));
0198         D_match2=permute(D_match2,[2 3 1]); % gets rid of initial singleton
0199         D_match2=D_match2(:,:)'; % size [nccs, (ntrials-1)*nsegments]
0200 
0201         % mismatch:
0202         % distance from each segment of audio to all mismatched segments of EEG, averaged
0203         D_mismatch2=zeros(size(S_x,3),size(S_x,3)-1, nccs);
0204         for iSegment=1:size(S_x,3)
0205             % for each segment of audio
0206             other_segments=setdiff(1:size(S_x,3),iSegment);
0207             if 0
0208                 tmp=bsxfun(@minus,S_y(:,:,other_segments),S_x(:,:,iSegment)); % sample-to-sample differences
0209             else
0210                 tmp=bsxfun(@minus,S_x(:,:,other_segments),S_y(:,:,iSegment));
0211             end
0212             d=sqrt(mean(tmp.^2, 1)); % sum squares
0213             %disp(size(tmp))
0214             D_mismatch2(iSegment,:,:)=permute(d,[1 3 2]);
0215         end
0216         D_mismatch2=mean(D_mismatch2,2); % average over all other segments
0217         D_mismatch2=permute(D_mismatch2,[1 3 2]); 
0218 
0219         if 0
0220             figure(1); clf
0221             for k=1:4
0222                 subplot (2,2,k);
0223                 histogram(D_mismatch(:,k)-D_match(:,k), -.5:.01:.5); title(mean(D_mismatch(:,k)-D_match(:,k))/std(D_mismatch(:,k)-D_match(:,k)));
0224             end
0225         end
0226 
0227         % Use DSS to find optimal linear combination of distance scores to
0228         % separate match & mismatch (--> LDA)
0229 
0230         c0=nt_cov(D_match2)/size(D_mismatch2,1);
0231         c1=nt_cov(D_mismatch2)/size(D_match2,1);
0232         [todss,pwr0,pwr1]=nt_dss0(c0,c1);
0233         if mean(D_match2*todss(:,1), 1)<0; todss=-todss; end
0234         
0235         lda_xform=todss;
0236         
0237     end % if ldaflag=1
0238 
0239     if ldaflag>0 && ldaflag<1
0240         p=ldaflag; % exponent to apply to CC distances
0241         ldaflag=3;
0242     end
0243     
0244     switch ldaflag  
0245         case 0
0246             D_match=D_match(:,1);
0247             D_mismatch=D_mismatch(:,1);
0248         case 1
0249             D_match=D_match*lda_xform(:,1);
0250             D_mismatch=D_mismatch*lda_xform(:,1);
0251         case 2
0252             D_match=mean(D_match,2);
0253             D_mismatch=mean(D_mismatch,2);
0254         case 3
0255             pp=p.^(0:size(D_match,2)-1);
0256             D_match=mean(D_match.*pp,2);
0257             D_mismatch=mean(D_mismatch.*pp,2);
0258         otherwise
0259             error('!');
0260     end
0261                 
0262     DD_match=[DD_match; D_match(:)];
0263     DD_mismatch=[DD_mismatch; D_mismatch(:)];
0264         
0265     RR(iTrial,:)=diag(corr(cc_x,cc_y));
0266 end
0267 
0268 if 0
0269     figure(100);  clf;
0270     histogram(DD_mismatch-DD_match, -.5:.05:.5); title(mean(DD_mismatch-DD_match)/std(DD_mismatch-DD_match)); 
0271     drawnow;
0272 end
0273 
0274 D=mean(DD_mismatch-DD_match, 1)/std(DD_mismatch-DD_match);
0275 E=mean(DD_mismatch-DD_match < 0, 1);
0276 R=mean(RR, 1);
0277 EXTRA.DD_mismatch=DD_mismatch;
0278 EXTRA.DD_match=DD_match;
0279 EXTRA.rms_eeg=rms_eeg;
0280 EXTRA.rms_stim=rms_stim;
0281 
0282 
0283

Generated on Sat 29-Apr-2023 17:15:46 by m2html © 2005