Home > functions > internal > dsCalcPower.m

dsCalcPower

PURPOSE ^

CALCPOWER - Compute spectral analysis of DynaSim data

SYNOPSIS ^

function data = dsCalcPower(data, varargin)

DESCRIPTION ^

CALCPOWER - Compute spectral analysis of DynaSim data

 Usage:
   data = dsCalcPower(data,'option',value)

 Inputs:
   - data: DynaSim data structure (see dsCheckData)
   - options:
     'variable'              : name of field containing data on which to
                               calculate firing rates (default: *_spikes or
                               first variable in data.labels)
     'time_limits'           : [beg,end] (units of data.time)
     'smooth_factor'         : number of samples for smoothing the spectrum (default: 5)
                               - tip: set to 1 to avoid smoothing
   - options for peak detection:
     'min_peak_frequency'    : Hz, min frequency for peak detection (default: 2)
     'max_peak_frequency'    : Hz, max frequency for peak detection (default: 150)
     'peak_threshold_prctile': percentile for setting power threshold for peak
                               detection (default: 95)
     'peak_area_width'       : Hz, size of frequency bin (centered on peak)
                               over which to calculate area under spectrum (default: 5)
     'exclude_data_flag'     : whether to remove simulated data from result
                               structure (default: 0)

 Outputs:
   - data structure organization:
     data.VARIABLE_Power_SUA.frequency: TODO
     data.VARIABLE_Power_SUA.PeakArea: area under spectrum around peak (one value per cell)
     data.VARIABLE_Power_SUA.PeakFreq: frequency of spectral power (one value per cell)
     data.VARIABLE_Power_SUA.Pxx: spectral power
   - if populations present, data also includes:
     data.VARIABLE_Power_MUA.frequency: TODO
     data.VARIABLE_Power_MUA.PeakArea: TODO
     data.VARIABLE_Power_MUA.PeakFreq: TODO
     data.VARIABLE_Power_MUA.Pxx: spectrum of the mean waveform
       - population mean spectrum of the individual waveforms can be
           calculated using "mean(data.VARIABLE_Power_MUA.Pxx,2)".
   - Note:
     - "VARIABLE" can be specified as the name of a variable listed in
         data.labels, a cell array of string listing variable names, or as a
         regular expression pattern for identifying variables to process. See
         dsSelectVariables for more info on supported specifications.

 Examples:
   s=[];
   s.populations(1).name='E';
   s.populations(1).equations='dv[2]/dt=@current+10; {iNa,iK}; v(0)=-65';
   s.populations(2).name='I';
   s.populations(2).equations='dv/dt=@current+10; {iNa,iK}; v(0)=-65';
   data=dsSimulate(s,'tspan',[0 1000]);
   data=dsCalcPower(data,'variable','v');
   % Plot the spectrum of the E-cell average population voltage
   figure; plot(data.E_v_Power_MUA.frequency,data.E_v_Power_MUA.Pxx);
   xlabel('frequency (Hz)'); ylabel('power'); xlim([0 200]);

 See also: PlotPower, dsAnalyzeStudy, dsSimulate, dsCheckData, dsSelectVariables

 Author: Jason Sherfey, PhD <jssherfey@gmail.com>
 Copyright (C) 2016 Jason Sherfey, Boston University, USA

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SOURCE CODE ^

0001 function data = dsCalcPower(data, varargin)
0002 %CALCPOWER - Compute spectral analysis of DynaSim data
0003 %
0004 % Usage:
0005 %   data = dsCalcPower(data,'option',value)
0006 %
0007 % Inputs:
0008 %   - data: DynaSim data structure (see dsCheckData)
0009 %   - options:
0010 %     'variable'              : name of field containing data on which to
0011 %                               calculate firing rates (default: *_spikes or
0012 %                               first variable in data.labels)
0013 %     'time_limits'           : [beg,end] (units of data.time)
0014 %     'smooth_factor'         : number of samples for smoothing the spectrum (default: 5)
0015 %                               - tip: set to 1 to avoid smoothing
0016 %   - options for peak detection:
0017 %     'min_peak_frequency'    : Hz, min frequency for peak detection (default: 2)
0018 %     'max_peak_frequency'    : Hz, max frequency for peak detection (default: 150)
0019 %     'peak_threshold_prctile': percentile for setting power threshold for peak
0020 %                               detection (default: 95)
0021 %     'peak_area_width'       : Hz, size of frequency bin (centered on peak)
0022 %                               over which to calculate area under spectrum (default: 5)
0023 %     'exclude_data_flag'     : whether to remove simulated data from result
0024 %                               structure (default: 0)
0025 %
0026 % Outputs:
0027 %   - data structure organization:
0028 %     data.VARIABLE_Power_SUA.frequency: TODO
0029 %     data.VARIABLE_Power_SUA.PeakArea: area under spectrum around peak (one value per cell)
0030 %     data.VARIABLE_Power_SUA.PeakFreq: frequency of spectral power (one value per cell)
0031 %     data.VARIABLE_Power_SUA.Pxx: spectral power
0032 %   - if populations present, data also includes:
0033 %     data.VARIABLE_Power_MUA.frequency: TODO
0034 %     data.VARIABLE_Power_MUA.PeakArea: TODO
0035 %     data.VARIABLE_Power_MUA.PeakFreq: TODO
0036 %     data.VARIABLE_Power_MUA.Pxx: spectrum of the mean waveform
0037 %       - population mean spectrum of the individual waveforms can be
0038 %           calculated using "mean(data.VARIABLE_Power_MUA.Pxx,2)".
0039 %   - Note:
0040 %     - "VARIABLE" can be specified as the name of a variable listed in
0041 %         data.labels, a cell array of string listing variable names, or as a
0042 %         regular expression pattern for identifying variables to process. See
0043 %         dsSelectVariables for more info on supported specifications.
0044 %
0045 % Examples:
0046 %   s=[];
0047 %   s.populations(1).name='E';
0048 %   s.populations(1).equations='dv[2]/dt=@current+10; {iNa,iK}; v(0)=-65';
0049 %   s.populations(2).name='I';
0050 %   s.populations(2).equations='dv/dt=@current+10; {iNa,iK}; v(0)=-65';
0051 %   data=dsSimulate(s,'tspan',[0 1000]);
0052 %   data=dsCalcPower(data,'variable','v');
0053 %   % Plot the spectrum of the E-cell average population voltage
0054 %   figure; plot(data.E_v_Power_MUA.frequency,data.E_v_Power_MUA.Pxx);
0055 %   xlabel('frequency (Hz)'); ylabel('power'); xlim([0 200]);
0056 %
0057 % See also: PlotPower, dsAnalyzeStudy, dsSimulate, dsCheckData, dsSelectVariables
0058 %
0059 % Author: Jason Sherfey, PhD <jssherfey@gmail.com>
0060 % Copyright (C) 2016 Jason Sherfey, Boston University, USA
0061 
0062 %% 1.0 Check inputs
0063 options=dsCheckOptions(varargin,{...
0064   'variable',[],[],...
0065   'time_limits',[-inf inf],[],...
0066   'smooth_factor',5,[],... % number of samples for smoothing the spectrum
0067   'min_peak_frequency',1,[],... % Hz, min frequency for peak detection
0068   'max_peak_frequency',200,[],... % Hz, max frequency for peak detection
0069   'peak_threshold_prctile',95,[],... % percentile for setting power threshold for peak detection
0070   'peak_area_width',5,[],... % Hz, size of frequency bin (centered on peak) over which to calculate area under spectrum
0071   'exclude_data_flag',0,{0,1},...
0072   'timeBandwidthProduct',[],[],... % time-bandwidth product for multi-taper method
0073   'output_suffix','',[],...
0074   'auto_gen_test_data_flag',0,{0,1},...
0075   },false);
0076 
0077 %% auto_gen_test_data_flag argin
0078 if options.auto_gen_test_data_flag
0079   varargs = varargin;
0080   varargs{find(strcmp(varargs, 'auto_gen_test_data_flag'))+1} = 0;
0081   varargs(end+1:end+2) = {'unit_test_flag',1};
0082   argin = [{data}, varargs]; % specific to this function
0083 end
0084 
0085 data = dsCheckData(data, varargin{:});
0086 % note: calling dsCheckData() at beginning enables analysis function to
0087 % accept data matrix [time x cells] in addition to DynaSim data structure.
0088 
0089 if numel(data)>1
0090   % use dsAnalyzeStudy to recursively call dsCalcPower on each data set
0091   data=dsAnalyzeStudy(data,@dsCalcPower,varargin{:});
0092   return;
0093 end
0094 
0095 % time parameters
0096 time = data.time; % time vector
0097 dt = time(2)-time(1); % time step
0098 % ntime=length(time); % number of time points in full data set
0099 t1=nearest(time,options.time_limits(1)); % index to first sample
0100 t2=nearest(time,options.time_limits(2)); % index to last sample
0101 nsamp=t2-t1+1; % number of samples for spectral estimate
0102 
0103 % frequency parameters
0104 Fs = fix(1/(dt/1000)); % effective sampling frequency
0105 Fmin=options.min_peak_frequency; % min frequency for peak detection
0106 Fmax=options.max_peak_frequency; % max frequency for peak detection
0107 thresh_prctile=options.peak_threshold_prctile; % percentile for setting power threshold for peak detection
0108 smooth_factor=options.smooth_factor; % number of samples to smooth spectrum
0109 Fwin=options.peak_area_width; % size of frequency bin (centered on peak) for calculating area under spectrum
0110 FreqRange=[max(Fmin,2/time(end)) Fmax]; % range to look for spectral peaks
0111 NFFT=2^(nextpow2(nsamp-1)-1);%2); % <-- use higher resolution to capture STO freq variation
0112 % WINDOW=2^(nextpow2(NFFT-1)-3);
0113 % NOVERLAP=[]; % spectral parameters
0114 NW = options.timeBandwidthProduct;
0115 
0116 %% 2.0 set list of variables to process as cell array of strings
0117 options.variable=dsSelectVariables(data(1).labels,options.variable, varargin{:});
0118 
0119 %% 3.0 calculate power spectrum for each variable
0120 if ~isfield(data,'results')
0121   data.results={};
0122 end
0123 
0124 warning off
0125 for v=1:length(options.variable)
0126   % extract this data set
0127   var=options.variable{v};
0128   dat=data.(var);
0129 
0130   % determine how many cells are in this data set
0131   ncells=size(dat,2);
0132 
0133   % preallocation
0134   PeakFreq=nan(1,ncells);
0135   PeakArea=nan(1,ncells);
0136 
0137   % SUA spectra: loop over cells
0138   for i=1:ncells
0139     % select data
0140     X=detrend(dat(t1:t2,i)); % detrend the data
0141     % calculate spectral estimate
0142     if strcmp(reportUI,'matlab')
0143       [tmpPxx,f] = pmtm(X, NW, NFFT, Fs); % calculate power
0144     elseif exist('pwelch') == 2 % 'pwelch is in Octave's path
0145       [tmpPxx,f] = pwelch(X,NFFT,[],NFFT,Fs); % calculate power in octave (pmtm is not implemented yet)
0146     elseif exist('pwelch') ~= 2 % 'pwelch is not in Octave's path
0147       try
0148         pkg load signal; % trying to load octave forge 'signal' package before using pwelch function
0149         fprintf('''pmtm'' function for spectral analysis not available in Octave, using pwelch.\n')
0150         [tmpPxx,f] = pwelch(X,NFFT,[],NFFT,Fs); % calculate power in octave (pmtm is not implemented yet)
0151       catch
0152         error('pwelch function is needed for spectral analysis in Octave, please install the signal package from Octave Forge');
0153       end
0154     end
0155 
0156     if i==1
0157       % get size of spectrum and preallocate result matrix
0158       nfreq=length(f);
0159       Pxx=nan(nfreq,ncells);
0160     end
0161 
0162     if all(isnan(tmpPxx(:)))
0163       tmpPxx=zeros(size(tmpPxx));
0164     end
0165 
0166     if ~isa(tmpPxx,'double')
0167       % convert to double precision
0168       tmpPxx=double(tmpPxx);
0169     end
0170 
0171     % smooth the spectrum
0172     if smooth_factor>1 && strcmp(reportUI,'matlab')
0173       tmpPxx=smooth(tmpPxx,smooth_factor);
0174     else
0175       tmpPxx=lsmooth(tmpPxx,smooth_factor);
0176     end
0177 
0178     % Peak Detection:
0179     % select range of frequencies over which to look for peaks
0180     sel = find(FreqRange(1)<=f & f<=FreqRange(end));
0181 
0182     % set threshold for peak detection
0183     ht=prctile(tmpPxx(sel),thresh_prctile); % ht=prctile(log10(tmpPxx(sel)),thresh_prctile);
0184 
0185     if ~isnan(ht)
0186       % get index of peaks in range over threshold
0187       if strcmp(reportUI,'matlab')
0188         [linPeakPower,PPind]=findpeaks(tmpPxx(sel),'MinPeakHeight',ht,'NPeaks',3); % [PeakPower,PPind]=findpeaks(log10(tmpPxx(sel)),'MinPeakHeight',ht,'NPeaks',3);
0189       else
0190         [linPeakPower,PPind]=findpeaks(tmpPxx(sel),'MinPeakHeight',ht,'MinPeakDistance',0,'MinPeakWidth',0);
0191       end
0192       PeakPower = log10(linPeakPower);
0193     else
0194       PPind=[];
0195     end
0196 
0197     if ~isempty(PPind)
0198       % if multiple peaks, only consider the largest
0199       if numel(PPind)>1
0200         PPind=PPind(max(PeakPower)==PeakPower); %PPind=PPind(1);
0201       end
0202 
0203       % get frequency at that index
0204       PeakFreq(i) = f(sel(PPind));
0205 
0206       % set limits for calculating area under spectrum around peak
0207       flo=PeakFreq(i)-Fwin/2;
0208       fhi=PeakFreq(i)+Fwin/2;
0209       sel2=(flo<=f & f<=fhi);
0210       % calculate area under spectrum around peak
0211       PeakArea(i) = sum(tmpPxx(sel2))*(f(2)-f(1));
0212     else
0213       PeakFreq(i)=nan;
0214       PeakArea(i)=nan;
0215     end
0216     % Store results
0217     Pxx(:,i)=tmpPxx;
0218   end
0219   % -----------------------------------------------------
0220   % Repeat spectral estimate for MUA:
0221   if ncells==1
0222     % same as SUA
0223     Pxx_mean=Pxx;
0224     Pxx_mean_PeakFreq=PeakFreq;
0225     Pxx_mean_PeakArea=PeakArea;
0226   else
0227     if ~strcmp(reportUI,'matlab') && exist('nanmean') ~= 2 % 'nanmean is not in Octave's path
0228       try
0229         pkg load statistics; % trying to load octave forge 'statistics' package before using nanmean function
0230       catch
0231         error('nanmean function is needed, please install the statistics package from Octave Forge');
0232       end
0233     end
0234     % calculate MUA
0235     X=detrend(nanmean(dat(t1:t2,:),2)); % detrend the data
0236 
0237     % calculate spectral estimate
0238     if ~strcmp(reportUI,'matlab') && exist('pwelch') ~= 2 % 'pwelch is not in Octave's path
0239       try
0240         pkg load signal; % trying to load octave forge 'signal' package before using pwelch function
0241       catch
0242         error('pwelch function is needed for spectral analysis in Octave, please install the signal package from Octave Forge');
0243       end
0244     end
0245     [tmpPxx,f] = pwelch(X,NFFT,[],NFFT,Fs); % calculate power
0246     if all(isnan(tmpPxx(:)))
0247       tmpPxx=zeros(size(tmpPxx));
0248     end
0249 
0250     if ~isa(tmpPxx,'double')
0251       % convert to double precision
0252       tmpPxx=double(tmpPxx);
0253     end
0254 
0255     % smooth the spectrum
0256     if smooth_factor>1 && strcmp(reportUI,'matlab')
0257       tmpPxx=smooth(tmpPxx,smooth_factor);
0258     else
0259       tmpPxx=lsmooth(tmpPxx,smooth_factor);
0260     end
0261 
0262     % Peak Detection:
0263     % select range of frequencies over which to look for peaks
0264     sel = find(FreqRange(1)<=f & f<=FreqRange(end));
0265 
0266     % set threshold for peak detection
0267     ht=prctile(tmpPxx(sel),thresh_prctile); % ht=prctile(log10(tmpPxx(sel)),thresh_prctile);
0268     if ~isnan(ht)
0269       % get index of peaks in range over threshold
0270       if strcmp(reportUI,'matlab')
0271         [linPeakPower,PPind]=findpeaks(tmpPxx(sel),'MinPeakHeight',ht,'NPeaks',3); % [PeakPower,PPind]=findpeaks(log10(tmpPxx(sel)),'MinPeakHeight',ht,'NPeaks',3);
0272       else
0273         [linPeakPower,PPind]=findpeaks(tmpPxx(sel),'MinPeakHeight',ht,'MinPeakDistance',0,'MinPeakWidth',0);
0274       end
0275       PeakPower = log10(linPeakPower);
0276     else
0277       PPind=[];
0278     end
0279 
0280     if ~isempty(PPind)
0281       % if multiple peaks, only consider the largest
0282       if numel(PPind)>1
0283         PPind=PPind(max(PeakPower)==PeakPower); %PPind=PPind(1);
0284       end
0285 
0286       % get frequency at that index
0287       Pxx_mean_PeakFreq = f(sel(PPind));
0288 
0289       % set limits for calculating area under spectrum around peak
0290       flo=Pxx_mean_PeakFreq-Fwin/2;
0291       fhi=Pxx_mean_PeakFreq+Fwin/2;
0292       sel2=(flo<=f & f<=fhi);
0293 
0294       % calculate area under spectrum around peak
0295       Pxx_mean_PeakArea = sum(tmpPxx(sel2))*(f(2)-f(1));
0296     else
0297       Pxx_mean_PeakFreq=nan;
0298       Pxx_mean_PeakArea=nan;
0299     end
0300     Pxx_mean=tmpPxx;
0301   end
0302 
0303   %% Add resulting power spectra to data structure
0304   % organization scheme:
0305   % data.VARIABLE_Power_SUA.(Pxx,PeakFreq,PeakArea,frequency)
0306   % data.VARIABLE_Power_MUA.(Pxx,PeakFreq,PeakArea,frequency)
0307   data.([var '_Power_SUA' options.output_suffix]).Pxx=Pxx;
0308   data.([var '_Power_SUA' options.output_suffix]).PeakFreq=PeakFreq;
0309   data.([var '_Power_SUA' options.output_suffix]).PeakArea=PeakArea;
0310   data.([var '_Power_SUA' options.output_suffix]).frequency=f;
0311   data.([var '_Power_MUA' options.output_suffix]).Pxx=Pxx_mean;
0312   data.([var '_Power_MUA' options.output_suffix]).PeakFreq=Pxx_mean_PeakFreq;
0313   data.([var '_Power_MUA' options.output_suffix]).PeakArea=Pxx_mean_PeakArea;
0314   data.([var '_Power_MUA' options.output_suffix]).frequency=f;
0315 
0316   if ~ismember([var '_Power_SUA' options.output_suffix],data.results)
0317     data.results{end+1}=[var '_Power_SUA' options.output_suffix];
0318   end
0319 
0320   if ~ismember([var '_Power_MUA' options.output_suffix],data.results)
0321     data.results{end+1}=[var '_Power_MUA' options.output_suffix];
0322   end
0323 
0324   if options.exclude_data_flag
0325     for l=1:length(data.labels)
0326       data=rmfield(data,data.labels{l});
0327     end
0328   end
0329 %   % alternate organization scheme:
0330 %   data.([var '_Pxx'])=Pxx;
0331 %   data.([var '_Pxx_PeakFreq'])=PeakFreq;
0332 %   data.([var '_Pxx_PeakArea'])=PeakArea;
0333 %   data.([var '_Pxx_mean'])=Pxx_mean;
0334 %   data.([var '_Pxx_mean_PeakFreq'])=Pxx_mean_PeakFreq;
0335 %   data.([var '_Pxx_mean_PeakArea'])=Pxx_mean_PeakArea;
0336 %   if ~ismember([var '_Pxx'],data.results)
0337 %     data.results{end+1}=[var '_Pxx'];
0338 %     data.results{end+1}=[var '_Pxx_PeakFreq'];
0339 %     data.results{end+1}=[var '_Pxx_PeakArea'];
0340 %     data.results{end+1}=[var '_Pxx_mean'];
0341 %     data.results{end+1}=[var '_Pxx_mean_Pxx_PeakFreq'];
0342 %     data.results{end+1}=[var '_Pxx_mean_Pxx_PeakArea'];
0343 %   end
0344 
0345 end
0346 
0347 %% auto_gen_test_data_flag argout
0348 if options.auto_gen_test_data_flag
0349   argout = {data}; % specific to this function
0350 
0351   dsUnitSaveAutoGenTestData(argin, argout);
0352 end

Generated on Tue 12-Dec-2017 11:32:10 by m2html © 2005