www.gusucode.com > 生物信号工具箱 > 生物信号工具箱/生物信号工具箱/Biosignal/Biosignal/Statistical_Processing/nsfmp.m

    function [wns_fmp,ns_fmp,r,atrials,average]=nsfmp(tmp,init,tm,param,mode)


[wns_fmp,ns_fmp,r,atrials,average]=nsfmp(data,init,tm,param,mode)

Function for performing recursive averaging under non stationary conditions based on Silva (2009). 
Inputs to the function are:

data    -(NxM) Data to be averaged. Where N is the lenght of a trial (epoch) and  M is 
          the total number of trials. 
init    -(1x1) Parameter to initialize the averaging in order to use the averaging for
         long datasets in which the next set of trials have to be read from file.
tm      -(Nx1) Time vector in seconds wrt stimulus onset.
param   -(na) Structure containing the parameters of the procedure and the following fields:
              frat - (1x1) Parameter for controling the segmentation of the noise sources.
                           Note that 0<= frat <=1. With 0 yielding maximum segmentation and 1
                           yielding minimum segmenation (1 == stationary condition).
              Npts - (1x1) Number of point within a trial to estimate the noise variance (Npts <= tm).
              blcks- (1x1) Minimum number of trials for which to estimate the noise source.
                           Note that under frat=0, the number of independent noise sources estimated
                           will be round(M/blcks). The value of blcks should be, in theory, the minimum
                           duration for which you think the noise can be considered locally stationary.
             Fs    - (1x1) Sampling frequency in Hz.
             art_th- (1x1) Artifact rejection threshold. Any trial whose absolute amplitude is higher
                           than this threshold will be discarded.
mode   -(Lx1) String with eht following options:
         'ave'  -averages the data into a single average
         'sub'  -averages the data into 2 "independent" averages and compute statistics between them
         
    

%Scrip to test if clock & sync are working properly
%Both inputs to the soundcard should be connected to headphone buffer
%Trigger signal -> Left channel (1)
%Data signal -> right channel (2)
%Attenuation is expected of recording if HB7 is not set to 0.
% param:
%         art_th   artifact rejection threshold
%         snr_th   snr threshold to quit
%         cor_th   correlation threshold to quit
%         num_trl  minimum number of trials to estimate signal variance
%         frat     frat level to segment noise
%         mode     mode options are: abrave, oaeave, sim, exp, and chk


noise_segrat=param.frat;
Npts=param.Npts;
blcks=param.blcks;
art_th=param.art_th; %artifact threshold in nano-volts
fc=param.Fs;

%Analyse the recorded data keep out of loop for efficiency....
persistent S Sraw abr nabr a ai M sigX NsigX trial_length st nd nabr1 nabr2 S1 S2 trials acoust_noise

persistent wabr1 wabr2 sigX1 sigX2 NsigX1 NsigX2 C Ccount old_tmp
%Initialize parameters for corresponding level
if(init)
    S=single([]); %segmented noise variance
    Sraw=single([]);%un-segmented noise variance
    S1=[];
    S2=[];
    a=single([]);   %max of each trial
    ai=[];          %rejected trials
    abr=0;
    nabr1=0;
    nabr2=0;
    wabr1=0;
    wabr2=0;
    nabr=0;
    C=[];
    Ccount=0;
    M=0; %absolute number of trials
    trials=0;
    old_tmp=[];
    
    sigX1=param.sigpow;
    sigX2=param.sigpow;
    NsigX1=param.sigpow;
    NsigX2=param.sigpow;
    NsigX=param.sigpow;
    sigX=param.sigpow;
    trial_length=length(tm);
end


%get rid of any dc component
[N,total_trials]=size(tmp);
tmp=tmp-repmat(mean(tmp),[N 1]);
    

% get rid of artifacts
amp=max(abs(tmp(st:end,:)));
if(isempty(a))
    a=amp;
else
    a=[a amp];
end
art_ind=find(amp>art_th);
tmp(:,art_ind)=[];
ai=[ai art_ind+(M/prs)];
M=M+total_trials;
total_trials=total_trials - length(art_ind);

%Pre-append with any previous trials for other blocks/session
if(~isempty(old_tmp))
    tmp=[old_tmp tmp];
    total_trials=total_trials+length(old_tmp(1,:));
end
old_tmp=tmp;
Mid=round(total_trials/2); %Find the mid-point for the sub-averaging

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Estimate variance within blcks of trials
if(blcks==inf)
    blcks=total_trials;
end
%With Collapse of noise regions collapsing within blocks
[vns,tmp,total_trials]=fmp3(tmp,trial_length,total_trials,Npts,blcks,1,0,noise_segrat);

%store unused trial until nextime function is called
unused=length(old_tmp(1,:))-length(tmp(1,:));
old_tmp(:,1:end-unused)=[];

if(total_trials ==0)
    %all trials have been excluded due to artifact rejection level
    atrials=trials;
    ns_fmp=NaN;
    wns_fmp=NaN;
    NvarX=NaN;
    r=NaN;
    data=NaN;
    return
end

%Record # of accepted trials
trials=trials + total_trials*prs;
atrials=trials;

[vns_raw,trash,trash]=fmp3(tmp,trial_length,total_trials,Npts,blcks,0,0,[]);
temp_vns=repmat(vns(:)',[blcks 1]);
temp_vns=temp_vns(:);
temp_vns_raw=repmat(vns_raw(:)',[blcks 1]);
S=[S; temp_vns];
Sraw=[Sraw; temp_vns_raw(:)];

%Collapsing noise estimates across blocks
if(length(unique(S))>1)
    [S]=noise_sgmt2(S,length(S),Npts*blcks,noise_segrat);
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Perform recursive weighted averaging of response
[abr,w]=rw_average2(abr,tmp,total_trials,S);
%normal unweighted
[nabr,trash]=Nullrw_average(nabr,tmp,total_trials,S);

%Estimate SNR
[snr_curve,Nsnr_curve,ns_fmp,wns_fmp,sigX,NsigX,NS,sigN,NsigN]=snr(abr,nabr,S,prs,sigX,NsigX,st,nd);

%Break block to estimate two sub-averages
S1=[S1; temp_vns(1:Mid)];
S2=[S2; temp_vns(Mid+1:end)];


if(strcmp(mode,'ave') )
    
    %In average mode there is only one signal available and that is either
    %OAE or ABR. In either case, the signal is stored under the ABR
    %variable name in this function workspace
    
    %Normal recursive sub-averaging
    [nabr1,trash]=Nullrw_average(nabr1,tmp(:,1:Mid),Mid,S1);
    [nabr2,trash]=Nullrw_average(nabr2,tmp(:,Mid+1:end),total_trials-Mid,S2);
    
    
    %Weighted recursive sub-averaging
    [wabr1,w1]=rw_average2(wabr1,tmp(:,1:Mid),Mid,S1);
    [wabr2,w2]=rw_average2(wabr2,tmp(:,Mid+1:end),total_trials-Mid,S2);
    
    %Estimate SNRs
    [snr_crv1,Nsnr_crv1,ns_fmp1,wns_fmp1,sigX1,NsigX1,NS1,resW1,resN1]=snr(wabr1,nabr1,S1,prs,sigX1,NsigX1,st,nd);
    [snr_crv2,Nsnr_crv2,ns_fmp2,wns_fmp2,sigX2,NsigX2,NS2,resW2,resN2]=snr(wabr2,nabr2,S2,prs,sigX2,NsigX2,st,nd);
    
    data.sig=abr;
    data.nsig=nabr;
    data.w=w;
    data.C=[];
    data.ns_fmp=ns_fmp;
    data.wns_fmp=wns_fmp;
    data.nsig1=nabr1;
    data.nsig2=nabr2;
    data.w1=w1;
    data.w2=w2;
    data.wsig1=wabr1;
    data.wsig2=wabr2;
    data.tm=tm;
    data.wns_fmp2=ns_fmp2;
    data.wns_fmp1=ns_fmp1;
    data.st=st;
    data.nd=nd;
    data.resW=sigN;
    data.resN=NsigN;
    data.resW1=resW1;
    data.resN1=resN1;
    data.resW2=resW2;
    data.resN2=resN2;
    r=corrcoef(nabr1,nabr2);
    r=r(2);
else
    %Estimate two independent sub-averages and their x-correlation
    [nabr1,trash]=rw_average2(abr,tmp(:,1:Mid),Mid,S1);
    [nabr2,trash]=rw_average2(abr,tmp(:,Mid+1:end),total_trials-Mid,S2);
    r=corrcoef(nabr1,nabr2);
    r=r(2);
    data=sigX(end);
end





%%%%%% END OF MAIN %%%%%%%%



function [snr_curve,Nsnr_curve,ns_fmp,wns_fmp,sigX,NsigX,NS,sigN,NsigN]=snr(abr,nabr,S,prs,sigX,NsigX,st,nd)

%Generating the indeces that indicate where respective noise sources end
NS=length(S);
S_ind=find(diff(S) ~= 0);
if(isempty(S_ind) || S_ind(end)~= NS)
    S_ind(end+1)= NS;
end

%Estimat residual background noise
sigN=repmat(S(:)',[1 prs]);
sigN=1./cumsum(1./sigN(:)); %residual noise from weighted average
NsigN=ns_snrestm5(0,S(S_ind),S_ind.*prs); %residual noise from normal average

%Estimate Signal and Noise Variance

%Weighted average
%sigX(end+1)=min(var(abr(st:nd)-mean(abr(st:nd))),sigX(end));%delay and window to avoid stimulus artifact
sigX(end+1)=var(abr(st:nd));%delay and window to avoid stimulus artifact
snr_curve=sigX(end)./sigN;
%Normal average
%NsigX(end+1)=min(var(nabr(st:nd)-mean(nabr(st:nd))),NsigX(end));%delay and window to avoid stimulus artifact
NsigX(end+1)=var(nabr(st:nd));%delay and window to avoid stimulus artifact
Nsnr_curve=NsigX(end)./NsigN;

ns_fmp=max(Nsnr_curve(end));
wns_fmp=max(snr_curve(end));

if(isempty(ns_fmp))
    ns_fmp=NaN; %in case not enough trials have not been collected yet
    wns_fmp=NaN;
end




function [ave,w]=rw_average2(ave_old,new_data,M,S)

nS=length(S);
n_old=nS-M;

%estimate weights for weighted averaging recusively
W=1./S(:);
if(nS>M)
    alpha_old=1./sum(W(1:n_old));
else
    alpha_old=inf;
end
alpha=1./sum(W);
w=alpha.*W;

ave= (alpha/alpha_old)*ave_old + new_data*w(n_old+1:end);


function [ave,w]=Nullrw_average(ave_old,new_data,M,S)

nS=length(S);
n_old=nS-M;

%estimate weights for weighted averaging recusively
W=1./S;
W=W.*0 + 1; %normal averaging, used for debuging...
%display('***using normal averaging')
w_ave0=new_data*W(n_old+1:end);

alpha_old=sum(W(1:n_old));
alpha=1./sum(W);
ave=alpha.*( alpha_old.*ave_old + w_ave0);
w=W(:)./sum(W(:));





function [vns]=noise_sgmt2(vns,Mend,V,noise_segrat)

%Segment noise sections dynamically according to F-test of variance
ind_unique=find([0;diff(vns)] ~= 0)-1; 
if(isempty(ind_unique))
    return
end
if(noise_segrat==0 || noise_segrat==1)
    %extreme cases
    if(noise_segrat==0)
        %no merging possible
        return
    else
        %merge all trials
        vns=repmat(mean(vns),[1 Mend]);
        return
    end
end
    
ind_width=[ind_unique(1);diff(ind_unique)];
if(ind_unique(end) ~= Mend)
    ind_unique(end+1)=Mend;
    ind_width(end+1)= Mend-ind_unique(end-1);
end
    
Mend=length(ind_unique);
leak=inf;

if(Mend>1)
    %Collapse noise regions by F-test of variance
    for m=[2:Mend]
        v1=ind_width(m-1)*V;
        v2=ind_width(m)*V;
        d1=min([v1 leak]); %add a leak factor to forget far values
        d2=min([v2 leak]); %add a leak factor to forget far values
        F05=finv(noise_segrat,d1,d2);
        F95=finv(1-noise_segrat,d1,d2);
        F=vns(ind_unique(m-1))/vns(ind_unique(m));

        %Hypothesis Test
        if(F05 <= F & F <= F95)
            %variances are equal, collapse blocks and
            %generate better estimate of noise variance
            st=ind_unique(m-1)-ind_width(m-1)+1;
            nd=ind_unique(m);
            val=(v1*vns(ind_unique(m-1))+ v2*vns(ind_unique(m)))/(v1+v2);
            vns(st:nd)=vns(st:nd).*0 + val;
            
            %Update current index vector # of samples due to merger
            ind_width(m)=ind_width(m-1)+ind_width(m);
%             hold on
%             plot(vns,'-o')
%             pause
        end
    end

end




function [vns,data,M]=fmp3(data,N,M,Npts,blcks,collapse,draw,noise_segrat)
% [vns]=fmp(data,Npts,blcks)
%estimate variance across muliple trials over fixed
%time points

stp=ceil(N/Npts);
tmp_Npts=ceil(N/stp);

if(tmp_Npts ~= Npts)
    Npts=tmp_Npts;
    warning(['Using :',num2str(Npts),' pts per block.'])
end

Mend=floor(M/blcks);
V=Npts*blcks;

if(Mend*blcks < M)
    data(:,Mend*blcks+1:end)=[];
    M=Mend*blcks;
end

if(M >= blcks)
    ns=data(1:stp:end,:);
    Nend=Npts*blcks*Mend;
    ns=reshape(ns(1:Nend),[Npts blcks Mend]);
    if(Npts>1)
        if(blcks>1)
            Mns=mean(ns,2);
            MNS=repmat(Mns,[1 blcks 1]);
            ns=ns-MNS; %subtract mean from samples
            vns=squeeze(mean(var(ns,[],2))); %estimate across a block
        else
            ns=squeeze(ns)-repmat(mean(squeeze(ns)),[Npts 1]);
            vns=squeeze(var(ns))'; %estimate within a block used for simulation only
        end
    else
        Mns=mean(ns,2);
        MNS=repmat(Mns,[1 blcks 1]);
        ns=ns-MNS; %subtract mean from samples
        vns=squeeze(var(ns,[],2)); %estimate across a block
    end
    if(collapse)
        if(draw)
            vns_ind=vns;
            [vns]=noise_sgmt2(vns,Mend,V,noise_segrat);
            plot(vns_ind,'-or'); hold on
            plot(vns)
        else
            [vns]=noise_sgmt2(vns,Mend,V,noise_segrat);
        end

    end %of collapse
else
    vns=[];
    fprintf(['\t Not enougth blocks to predic noise...\n'])
end %of number of trials condition & running average loop