mk_stim_patterns

PURPOSE ^

MK_STIM_PATTERNS: create an EIDORS stimulation pattern structure

SYNOPSIS ^

function [stim, meas_sel]= mk_stim_patterns(n_elec, n_rings, inj, meas, options, amplitude)

DESCRIPTION ^

MK_STIM_PATTERNS: create an EIDORS stimulation pattern structure
                to form part of a fwd_model object
 [stim, meas_sel] = mk_stim_patterns( n_elec, n_rings, ...
                                      inj, meas, options, amplitude)

 where
 stim(#).stimulation = 'Amp'
     (#).stim_pattern= [vector n_elec*n_rings x 1 ]
     (#).meas_pattern= [matrix n_elec*n_rings x n_meas_patterns]

 for example, for an adjacent pattern for 4 electrodes, with 0.5 Amp
   if all electrodes are used for measurement
 stim(1).stim_pattern= [0.5;-0.5;0;0]
 stim(1).meas_pattern= [1,-1, 0, 0 
                        0, 1,-1, 0 
                        0, 0, 1,-1 
                       -1, 0, 0, 1]

 meas_sel: when not using data from current injection electrodes,
           it is common to be given a full measurement set.
           For example 16 electrodes gives 208 measures, but 256
           measure sets are common. 'meas_sel' indicates which
           electrodes are used

 PARAMETERS:
   n_elec:   number of electrodes per ring
   n_rings:  number of electrode rings (1 for 2D)

   inj: injection pattern
      '{ad}'        -> adjacent drive: equivalent to [0 1]
      '{op}'        -> opposite drive: equivalent to [0, n_elec/2]
      '{trig}'      -> trigonometric drive [cos,sin,cos,sin ...]
                       '{trig}' implies the 'meas_current' option.
      '{trigcscs}'  -> trigonometric drive [cos,sin,cos,sin ...]
      '{trigccss}'  -> trigonometric drive [cos,cos, ... sin,sin, ...]
      '{mono}'      -> Drive via each elec, current leaves by ground
      Bi-polar injection patterns:
        [x y]: First pattern is [x,y] next is [x+1,y+1] 
      Mono-polar injection patterns:
        [x]:   First pattern is [x]   next is [x+1] 

   meas: measurement pattern
      '{ad}'        -> adjacent measurement
      '{op}'        -> opposite drive: equivalent to [0, n_elec/2]
      '{trig}'      -> trigonometric drive [sin,cos,sin,cos ...]
      '{mono}'      -> Meas at each elec (Reminder, you may want to set meas_current);
      Bi-polar measurement patterns:
        [x y]: First pattern is [x,y] next is [x+1,y+1] 
      Mono-polar measurement patterns:
        [x]:   First pattern is [x]   next is [x+1] 

   options: cell array of options, eg {'no_meas_current'}
     if contradictory options are specified, only the last applies
      'no_meas_current' / 'meas_current'
         -> do / don't make mesurements on current carrying electrodes
         -> to not make measurements on the electrodes next to the current carrying,
            use 'no_meas_current_next1'
      'rotate_meas' / 'no_rotate_meas'
         -> do / don't rotate measurements with stimulation pattern
      'do_redundant' / 'no_redundant'
         -> do / don't make reciprocally redundant measures
      'balance_inj' / 'no_balance_inj'
         -> do / don't draw current from all electrodes so total
            injection is zero (useful for mono patterns)
      'balance_meas' / 'no_balance_meas'
         -> do / don't subtrant measurement from all electrodes so total
            average measurement is zero (useful for mono patterns)

   amplitude: drive current levels, DEFAULT = 0.010 Amp

CROSS-REFERENCE INFORMATION ^

This function calls: This function is called by:

SUBFUNCTIONS ^

SOURCE CODE ^

0001 function [stim, meas_sel]= mk_stim_patterns( ...
0002             n_elec, n_rings, inj, meas, options, amplitude)
0003 %MK_STIM_PATTERNS: create an EIDORS stimulation pattern structure
0004 %                to form part of a fwd_model object
0005 % [stim, meas_sel] = mk_stim_patterns( n_elec, n_rings, ...
0006 %                                      inj, meas, options, amplitude)
0007 %
0008 % where
0009 % stim(#).stimulation = 'Amp'
0010 %     (#).stim_pattern= [vector n_elec*n_rings x 1 ]
0011 %     (#).meas_pattern= [matrix n_elec*n_rings x n_meas_patterns]
0012 %
0013 % for example, for an adjacent pattern for 4 electrodes, with 0.5 Amp
0014 %   if all electrodes are used for measurement
0015 % stim(1).stim_pattern= [0.5;-0.5;0;0]
0016 % stim(1).meas_pattern= [1,-1, 0, 0
0017 %                        0, 1,-1, 0
0018 %                        0, 0, 1,-1
0019 %                       -1, 0, 0, 1]
0020 %
0021 % meas_sel: when not using data from current injection electrodes,
0022 %           it is common to be given a full measurement set.
0023 %           For example 16 electrodes gives 208 measures, but 256
0024 %           measure sets are common. 'meas_sel' indicates which
0025 %           electrodes are used
0026 %
0027 % PARAMETERS:
0028 %   n_elec:   number of electrodes per ring
0029 %   n_rings:  number of electrode rings (1 for 2D)
0030 %
0031 %   inj: injection pattern
0032 %      '{ad}'        -> adjacent drive: equivalent to [0 1]
0033 %      '{op}'        -> opposite drive: equivalent to [0, n_elec/2]
0034 %      '{trig}'      -> trigonometric drive [cos,sin,cos,sin ...]
0035 %                       '{trig}' implies the 'meas_current' option.
0036 %      '{trigcscs}'  -> trigonometric drive [cos,sin,cos,sin ...]
0037 %      '{trigccss}'  -> trigonometric drive [cos,cos, ... sin,sin, ...]
0038 %      '{mono}'      -> Drive via each elec, current leaves by ground
0039 %      Bi-polar injection patterns:
0040 %        [x y]: First pattern is [x,y] next is [x+1,y+1]
0041 %      Mono-polar injection patterns:
0042 %        [x]:   First pattern is [x]   next is [x+1]
0043 %
0044 %   meas: measurement pattern
0045 %      '{ad}'        -> adjacent measurement
0046 %      '{op}'        -> opposite drive: equivalent to [0, n_elec/2]
0047 %      '{trig}'      -> trigonometric drive [sin,cos,sin,cos ...]
0048 %      '{mono}'      -> Meas at each elec (Reminder, you may want to set meas_current);
0049 %      Bi-polar measurement patterns:
0050 %        [x y]: First pattern is [x,y] next is [x+1,y+1]
0051 %      Mono-polar measurement patterns:
0052 %        [x]:   First pattern is [x]   next is [x+1]
0053 %
0054 %   options: cell array of options, eg {'no_meas_current'}
0055 %     if contradictory options are specified, only the last applies
0056 %      'no_meas_current' / 'meas_current'
0057 %         -> do / don't make mesurements on current carrying electrodes
0058 %         -> to not make measurements on the electrodes next to the current carrying,
0059 %            use 'no_meas_current_next1'
0060 %      'rotate_meas' / 'no_rotate_meas'
0061 %         -> do / don't rotate measurements with stimulation pattern
0062 %      'do_redundant' / 'no_redundant'
0063 %         -> do / don't make reciprocally redundant measures
0064 %      'balance_inj' / 'no_balance_inj'
0065 %         -> do / don't draw current from all electrodes so total
0066 %            injection is zero (useful for mono patterns)
0067 %      'balance_meas' / 'no_balance_meas'
0068 %         -> do / don't subtrant measurement from all electrodes so total
0069 %            average measurement is zero (useful for mono patterns)
0070 %
0071 %   amplitude: drive current levels, DEFAULT = 0.010 Amp
0072 
0073 % (C) 2005 Andy Adler. License: GPL version 2 or version 3
0074 % $Id: mk_stim_patterns.m 5291 2016-11-02 08:48:23Z fab-b $
0075 
0076 if ischar(n_elec) && strcmp(n_elec,'UNIT_TEST'); do_unit_test; return; end
0077 
0078 if nargin<6; amplitude= .01; end
0079 if nargin<5; options= {};  end
0080 v = process_args(n_elec, n_rings, inj, meas, options, amplitude );
0081 
0082 [stim,mpat ] = calc_stim(v, n_elec, n_rings);
0083 
0084 % Meas_sel selects meas which would exist if we measured all of them
0085 v.do_redundant = 1; v.use_meas_current = 1; 
0086 [jnk ,mpat0] = calc_stim(v, n_elec, n_rings);
0087 
0088 %meas_sel= meas_select_old( n_elec, v.inj, v);
0089  meas_sel= meas_select( mpat, mpat0);
0090 
0091 function [stim,mpat] = calc_stim(v, n_elec, n_rings)
0092    curr_pat = v.inj(:) * ones(1,n_elec);
0093    meas_pat = v.meas(:) * ones(1,n_elec);
0094    offset   = [1;1]*(0:n_elec-1);
0095 
0096    stim= struct([]);
0097    mpat= struct([]);
0098    i=1; j=1;
0099    for ring = 0:v.n_rings-1
0100       seen_patterns= struct;
0101       for elec= 0:v.n_elec-1
0102           if v.trig_inj && elec == v.n_elec-1 ; continue; end % No indep patterns
0103           s_pat= mk_stim_pat(v, elec, ring );
0104           m_pat= mk_meas_pat(v, elec, ring );
0105 
0106           if v.do_redundant == 0 % elim redudant
0107              [m_pat, seen_patterns] = elim_redundant(m_pat, s_pat, seen_patterns);
0108           end
0109 
0110           if ~isempty(m_pat) 
0111               stim(i).stimulation = 'Amp';
0112               stim(i).stim_pattern= sparse(s_pat);
0113               stim(i).meas_pattern= sparse(m_pat);
0114               i=i+1;
0115           end
0116               mpat(j).meas_pattern= sparse(m_pat);
0117               j=j+1;
0118       end
0119    end
0120 
0121 % when not using data from current injection electrodes,
0122 % it is common to be given a full measurement set.
0123 % For example 16 electrodes gives 208 measures, but 256
0124 % measure sets are common.
0125 % This function calculates a selector matrix to remove the extra
0126 %
0127 % reshape(meas_select( 6, [0,1], v),6,6) 0 0 1 1 1 0
0128 %                                        0 0 0 1 1 1
0129 %                                        1 0 0 0 1 1
0130 %                                        1 1 0 0 0 1
0131 %                                        1 1 1 0 0 0
0132 %                                        0 1 1 1 0 0
0133 %
0134 % reshape(meas_select( 6, [0,2], v),6,6) 0 0 1 1 0 0
0135 %                                        0 0 0 1 1 0
0136 %                                        0 0 0 0 1 1
0137 %                                        1 0 0 0 0 1
0138 %                                        1 1 0 0 0 0
0139 %                                        0 1 1 0 0 0
0140 %
0141 % reshape(meas_select( 6, [0,3], v),6,6) 0 0 1 0 0 1
0142 %                                        1 0 0 1 0 0
0143 %                                        0 1 0 0 1 0
0144 %                                        0 0 1 0 0 1
0145 %                                        1 0 0 1 0 0
0146 %                                        0 1 0 0 1 0
0147 function meas_sel= meas_select( mpat, mpat0);
0148    meas_sel = [];
0149    for i=1:length(mpat);
0150       [mset,  err ] = mk_meas_set( mpat(i).meas_pattern );
0151       [mset0, err0] = mk_meas_set( mpat0(i).meas_pattern );
0152       if err || err0; msel_i = 1 + 0*mset; % Set to 1 for error
0153       else            msel_i = ismember(mset0,mset);
0154       end
0155       meas_sel = [meas_sel; msel_i];
0156    end
0157 
0158    meas_sel = logical(meas_sel(:));
0159 
0160 function [mset,err] = mk_meas_set( meas_pat )
0161    mpats= size(~meas_pat,1);
0162    mset = zeros(mpats,1);
0163    err=0;
0164    for i=1:size(meas_pat,1);
0165       mpat = meas_pat(i,:);
0166       fp = find(mpat>0); if length(fp)==0; fp = 0; end
0167       fn = find(mpat<0); if length(fn)==0; fn = 0; end
0168       if length(fp)>1 || length(fn)>1 ; err=1; return; end
0169       mset(i) =  fp*1e7 + fn;
0170    end
0171 
0172 function stim_pat = mk_stim_pat(v, elec, ring );
0173    stim_pat = sparse(v.tn_elec, 1);
0174    if v.balance_inj
0175       stim_pat= stim_pat - sum(v.i_factor)/ (v.tn_elec-1);
0176    elseif v.trig_inj
0177       stim_pat = trig_pat( elec, v.tn_elec, v.trig_inj) * v.amplitude;
0178       return;
0179    end
0180 
0181    stim_idx = rem( v.inj + elec, v.n_elec) + 1 + v.n_elec*ring;
0182    stim_pat( stim_idx ) = v.amplitude*v.i_factor;
0183 
0184 % Measurement config can stay static, or can rotate with
0185 % the stim pattern. This code keeps measurements static
0186 function meas = mk_meas_pat(v, elec, ring );
0187    meas= sparse(v.tn_elec, v.tn_elec);
0188    if v.balance_meas
0189       meas= meas - sum(v.m_factor)/ (v.tn_elec-1);
0190    elseif v.trig_meas
0191       meas= trig_pat( 1:v.tn_elec, v.tn_elec)';
0192       return;
0193    end
0194 
0195    if v.rotate_meas
0196       ofs = elec;
0197    else
0198       ofs = 0;
0199    end 
0200 
0201    mseq= 0:v.tn_elec-1;
0202    within_ring = rem(v.n_elec +  mseq , v.n_elec);
0203    ouside_ring = floor( mseq / v.n_elec) * v.n_elec;
0204    meas_seq    = mseq *v.tn_elec + 1;
0205 
0206    for i=1:length(v.meas)
0207       meas_pat = rem( v.meas(i) + within_ring + ofs, v.n_elec ) + ...
0208                        ouside_ring + meas_seq;
0209       meas(meas_pat) = v.m_factor(i);
0210    end
0211 
0212    if v.use_meas_current == 0
0213    % each column of meas is a measurement pattern
0214    % Test whether each col has contribution from stim
0215        stim_idx = rem( v.inj + elec, v.n_elec) + 1 + v.n_elec*ring;
0216 
0217        if v.use_meas_current_next
0218    % If we want to eliminate the ones next to the stimulation electrodes
0219    %  ie. Swisstom device, then use this
0220      
0221           for ni= -v.use_meas_current_next:v.use_meas_current_next;
0222             stim_idx = [stim_idx, ...
0223                         rem( v.inj + elec + ni, v.n_elec) + 1 + v.n_elec*ring];
0224           end
0225           stim_idx = unique(stim_idx);
0226           stim_idx(stim_idx<=0) = stim_idx(stim_idx<=0) + v.n_elec;
0227        end
0228        elim= any(meas(stim_idx,:),1);
0229        meas(:,elim) = [];
0230    end
0231 
0232    meas= meas';
0233 
0234 
0235 function v = process_args(n_elec, n_rings, inj, meas, options, amplitude )
0236 
0237 % SET DEFAULTS
0238    v.trig_meas= 0;
0239    v.trig_inj = 0;
0240 
0241    v.use_meas_current = 0;
0242    v.use_meas_current_next = 0;
0243    v.rotate_meas = 0;
0244    v.do_redundant = 1;
0245    v.balance_inj = 0;
0246    v.balance_meas= 0;
0247 
0248 % Stimulation (injection) pattern
0249 % This currently does not handle complicated injection patterns
0250 if ischar(inj)
0251    if      strcmp(inj,'{ad}')
0252       inj= [0, 1];
0253       rel_ampl= [-1;1];
0254    elseif  strcmp(inj,'{op}')
0255       inj= [0, floor(n_elec/2)];
0256       rel_ampl= [-1;1];
0257    elseif  strcmp(inj,'{trig}')
0258       v.trig_inj = 1;
0259       v.use_meas_current = 1; % We need to measure on the electrodes
0260       rel_ampl= [];
0261    elseif  strcmp(inj,'{trigcscs}')
0262       v.trig_inj = 1;
0263       v.use_meas_current = 1; % We need to measure on the electrodes
0264       rel_ampl= [];
0265    elseif  strcmp(inj,'{trigccss}')
0266       v.trig_inj = 2;
0267       v.use_meas_current = 1; % We need to measure on the electrodes
0268       rel_ampl= [];
0269    elseif  strcmp(inj,'{mono}')
0270       inj= [0];
0271       rel_ampl= [1];
0272    else
0273       error(['parameter inj=',inj,' not understood']);
0274    end
0275 elseif prod(size(inj))==1
0276       rel_ampl= [1];
0277 elseif prod(size(inj))==2
0278       rel_ampl= [-1;1];
0279 else
0280       error(['parameter inj not understood']);
0281 end
0282 
0283 v.inj= inj;
0284 v.i_factor=      rel_ampl;
0285 
0286 % Measurement configuration.
0287 % All systems I know of use adjacent measurement,
0288 % are there actually any others?
0289 if ischar(meas)
0290    if      strcmp(meas,'{ad}')
0291       meas=     [0, 1];
0292       rel_ampl= [ 1;-1];
0293    elseif  strcmp(meas,'{op}')
0294       meas= [0, floor(n_elec/2)];
0295       rel_ampl= [ 1;-1];
0296    elseif  strcmp(meas,'{trig}')
0297       v.trig_meas= 1;
0298       rel_ampl= [ 1;-1];
0299    elseif  strcmp(meas,'{mono}')
0300       meas= [0];
0301       rel_ampl= [1];
0302    else
0303       error(['parameter meas=',meas,' not understood']);
0304    end
0305 elseif prod(size(meas))==1
0306       rel_ampl= [1];
0307 elseif prod(size(meas))==2
0308       rel_ampl= [ 1;-1];
0309 else
0310       error(['parameter meas not understood']);
0311 end
0312 
0313 v.meas=          meas;
0314 v.m_factor=      rel_ampl;
0315 
0316 v.n_elec = n_elec;
0317 v.n_rings= n_rings;
0318 v.tn_elec= n_rings * n_elec;
0319 v.amplitude = amplitude;
0320 
0321 v= parse_options(v, options);
0322 
0323 function v= parse_options(v, options);
0324 % iterate through the options cell array
0325 for opt = options
0326    if     strcmp(opt, 'no_meas_current')
0327       v.use_meas_current = 0;
0328       v.use_meas_current_next = 0;
0329    elseif strcmp(opt, 'no_meas_current_next1')
0330       v.use_meas_current = 0;
0331       v.use_meas_current_next = 1;
0332    elseif strcmp(opt, 'no_meas_current_next2')
0333       v.use_meas_current = 0;
0334       v.use_meas_current_next = 2;
0335    elseif strcmp(opt, 'meas_current')
0336       v.use_meas_current = 1;
0337    elseif strcmp(opt, 'rotate_meas')
0338       v.rotate_meas = 1;
0339    elseif strcmp(opt, 'no_rotate_meas')
0340       v.rotate_meas = 0;
0341    elseif strcmp(opt, 'do_redundant')
0342       v.do_redundant = 1;
0343    elseif strcmp(opt, 'no_redundant')
0344       v.do_redundant = 0;
0345    elseif strcmp(opt, 'balance_inj')
0346       v.balance_inj = 1;
0347    elseif strcmp(opt, 'no_balance_inj')
0348       v.balance_inj = 0;
0349    elseif strcmp(opt, 'balance_meas')
0350       v.balance_meas= 1;
0351    elseif strcmp(opt, 'no_balance_meas')
0352       v.balance_meas= 0;
0353    else
0354       error(['option parameter opt=',opt,' not understood']);
0355    end
0356 end
0357 
0358 function [m_pat, seen_patterns] = elim_redundant(m_pat, s_pat, seen_patterns);
0359    m_pat_new= sparse([]);
0360    s_pat_str= ['s',sprintf('%d_', find(s_pat) ),'m'];
0361    for j=1:size(m_pat,1);
0362       this_m_pat= m_pat(j,:);
0363       pat_str= [s_pat_str, sprintf('%d_', find(this_m_pat))];
0364       if ~isfield(seen_patterns,pat_str);
0365          m_pat_new= [m_pat_new;this_m_pat];
0366          % we've seen this pattern
0367          seen_patterns.(pat_str)= 1;
0368          % and it's dual by reciprocity
0369          pat_str= ['s',sprintf('%d_', find(this_m_pat) ), ...
0370                    'm',sprintf('%d_', find(s_pat))];
0371          seen_patterns.(pat_str)= 1;
0372       end
0373    end
0374    m_pat= m_pat_new;
0375 
0376 % create trig patterns.
0377 %
0378 % n_elecs is total number of electrodes
0379 % elec    is the electrodes selected (can be multiple)
0380 %         (elec goes from 0 to n_elecs-1
0381 % if sel = 1 -> cos|sin|cos|sin (default)
0382 % if sel = 2 -> cos|cos|sin|sin
0383 %
0384 function pat= trig_pat( elec_sel, n_elecs, sel);
0385     if nargin<3; sel=1; end
0386     idx= linspace(0,2*pi,n_elecs+1)'; idx(end)= [];
0387     omega= idx*[1:n_elecs/2];
0388     meas_pat= [cos(omega), sin(omega) ];
0389     if sel==1;
0390        % reorder so we get cos|sin|cos|sin
0391        order = reshape(1:n_elecs,[],2)';
0392        meas_pat= meas_pat(:,order(:));
0393     end
0394     meas_pat= meas_pat(:,1:end-1); % only n_elecs-1 independent patterns
0395     pat  = meas_pat(:, elec_sel+1);
0396 
0397 function trig_tests;
0398    stim = mk_stim_patterns(8,1,'{trig}',[0,1],{},2);
0399    t= linspace(0,2*pi,8+1)'; t(end)= [];
0400    unit_test_cmp('trig: t1',[stim(1:4).stim_pattern], ...
0401          2*[cos(t),sin(t),cos(2*t),sin(2*t)], 1e-10);
0402 
0403    stim = mk_stim_patterns(8,1,'{trigcscs}',[0,1],{},2);
0404    unit_test_cmp('trig: t2',[stim(1:4).stim_pattern], ...
0405          2*[cos(t),sin(t),cos(2*t),sin(2*t)], 1e-10);
0406 
0407    stim = mk_stim_patterns(8,1,'{trigccss}',[0,1],{},2);
0408    test = 2*[cos(t),cos(2*t),cos(3*t), cos(4*t), sin(t),sin(2*t),sin(3*t)];
0409    unit_test_cmp('trig: t2',[stim(:).stim_pattern], test, 1e-10);
0410 
0411 function do_unit_test
0412    trig_tests;
0413    stim = mk_stim_patterns(4,1,[0,1],[0,1],{},1);
0414    unit_test_cmp('t1',stim(1).stim_pattern, [-1;1;0;0]);
0415    unit_test_cmp('t2',stim(4).stim_pattern, [1;0;0;-1]);
0416    unit_test_cmp('t3',stim(1).meas_pattern, [0,0,1,-1]);
0417    unit_test_cmp('t4',stim(4).meas_pattern, [0,1,-1,0]);
0418 
0419 %      'no_meas_current' / 'meas_current'
0420 %         -> do / don't make mesurements on current carrying electrodes
0421    stim = mk_stim_patterns(4,1,[0,1],[0,1],{'meas_current'},1);
0422    unit_test_cmp('meas_current: t1',stim(1).meas_pattern,  ...
0423          [1,-1,0,0; 0,1,-1,0; 0,0,1,-1; -1,0,0,1]);
0424    unit_test_cmp('meas_current: t2',stim(4).stim_pattern, [1;0;0;-1]);
0425    stim = mk_stim_patterns(4,1,[0,1],[0,1],{'no_meas_current'},1);
0426    unit_test_cmp('meas_current: t3',stim(1).meas_pattern,  [0,0,1,-1]);
0427    unit_test_cmp('meas_current: t2',stim(4).stim_pattern, [1;0;0;-1]);
0428 
0429 %      'rotate_meas' / 'no_rotate_meas'
0430 %         -> do / don't rotate measurements with stimulation pattern
0431 
0432    stim = mk_stim_patterns(6,1,[0,1],[0,1],{'no_rotate_meas'},1);
0433    unit_test_cmp('no_rotate_meas: t1',stim(2).stim_pattern, [0;-1;1;0;0;0]);
0434    unit_test_cmp('no_rotate_meas: t2',stim(2).meas_pattern, ...
0435          [0,0,0,1,-1,0; 0,0,0,0,1,-1; -1,0,0,0,0,1]);
0436    unit_test_cmp('no_rotate_meas: t3',stim(3).stim_pattern, [0;0;-1;1;0;0]);
0437    unit_test_cmp('no_rotate_meas: t4',stim(3).meas_pattern, ...
0438          [1,-1,0,0,0,0;0,0,0,0,1,-1; -1,0,0,0,0,1]);
0439 
0440    stim = mk_stim_patterns(6,1,[0,1],[0,1],{'rotate_meas'},1);
0441    unit_test_cmp('rotate_meas: t1',stim(2).stim_pattern, [0;-1;1;0;0;0]);
0442    unit_test_cmp('rotate_meas: t2',stim(2).meas_pattern, ...
0443          [0,0,0,1,-1,0; 0,0,0,0,1,-1; -1,0,0,0,0,1]);
0444    unit_test_cmp('rotate_meas: t3',stim(3).stim_pattern, [0;0;-1;1;0;0]);
0445    unit_test_cmp('rotate_meas: t4',stim(3).meas_pattern, ...
0446          [0,0,0,0,1,-1; -1,0,0,0,0,1; 1,-1,0,0,0,0]);
0447 
0448 %      'do_redundant' / 'no_redundant'
0449 %         -> do / don't make reciprocally redundant measures
0450    stim = mk_stim_patterns(6,1,[0,1],[0,1],{'do_redundant'},1);
0451 
0452    unit_test_cmp('do_redundant: t0',length(stim), 6);
0453    unit_test_cmp('do_redundant: t1',stim(2).stim_pattern, [0;-1;1;0;0;0]);
0454    unit_test_cmp('do_redundant: t2',stim(2).meas_pattern, ...
0455          [0,0,0,1,-1,0; 0,0,0,0,1,-1; -1,0,0,0,0,1]);
0456    unit_test_cmp('do_redundant: t3',stim(3).stim_pattern, [0;0;-1;1;0;0]);
0457    unit_test_cmp('do_redundant: t4',stim(3).meas_pattern, ...
0458          [1,-1,0,0,0,0;0,0,0,0,1,-1; -1,0,0,0,0,1]);
0459 
0460    stim = mk_stim_patterns(6,1,[0,1],[0,1],{'no_redundant'},1);
0461    unit_test_cmp('no_redundant: t0',length(stim), 4);
0462    unit_test_cmp('no_redundant: t1',stim(2).stim_pattern, [0;-1;1;0;0;0]);
0463    unit_test_cmp('no_redundant: t2',stim(2).meas_pattern, ...
0464          [0,0,0,1,-1,0; 0,0,0,0,1,-1; -1,0,0,0,0,1]);
0465    unit_test_cmp('no_redundant: t3',stim(3).stim_pattern, [0;0;-1;1;0;0]);
0466    unit_test_cmp('no_redundant: t4',stim(3).meas_pattern, ...
0467          [0,0,0,0,1,-1;-1,0,0,0,0,1]);
0468    unit_test_cmp('no_redundant: t5',stim(4).meas_pattern, ...
0469          [-1,0,0,0,0,1]);
0470 
0471 %      'balance_inj' / 'no_balance_inj'
0472 %         -> do / don't draw current from all electrodes so total
0473 %            injection is zero (useful for mono patterns)
0474    stim = mk_stim_patterns(4,1,'{mono}',[0,1],{'balance_inj','meas_current'},1);
0475    unit_test_cmp('balance_inj: t0',length(stim), 4,1);
0476    unit_test_cmp('balance_inj: t1',stim(2).stim_pattern, -[1;-3;1;1]/3);
0477    unit_test_cmp('balance_inj: t2',stim(2).meas_pattern, ...
0478          [1,-1,0,0;0,1,-1,0;0,0,1,-1;-1,0,0,1]);
0479 
0480    stim = mk_stim_patterns(4,1,'{mono}',[0,1],{'no_balance_inj','no_meas_current'},1);
0481    unit_test_cmp('no_balance_inj: t0',length(stim), 4,1);
0482    unit_test_cmp('no_balance_inj: t1',stim(2).stim_pattern, [0;1;0;0]);
0483    unit_test_cmp('no_balance_inj: t2',stim(2).meas_pattern, ...
0484          [0,0,1,-1;-1,0,0,1]);
0485 
0486    stim = mk_stim_patterns(4,1,'{mono}',[0,1],{},1);
0487    unit_test_cmp('no_balance_inj: t0',length(stim), 4,1);
0488    unit_test_cmp('no_balance_inj: t1',stim(2).stim_pattern, [0;1;0;0]);
0489 
0490 %      'balance_meas' / 'no_balance_meas'
0491 %         -> do / don't subtrant measurement from all electrodes so total
0492 %            average measurement is zero (useful for mono patterns)
0493    stim = mk_stim_patterns(4,1,[0,1],'{mono}',{'no_balance_meas','meas_current'},1);
0494    unit_test_cmp('no_balance_meas: t0',length(stim), 4,1);
0495    unit_test_cmp('no_balance_meas: t1',stim(2).stim_pattern, [0;-1;1;0]);
0496    unit_test_cmp('no_balance_meas: t1',stim(2).meas_pattern, eye(4));
0497 
0498    stim = mk_stim_patterns(4,1,[0,1],'{mono}',{'meas_current'},1);
0499    unit_test_cmp('no_balance_meas: t0',length(stim), 4,1);
0500    unit_test_cmp('no_balance_meas: t1',stim(2).stim_pattern, [0;-1;1;0]);
0501    unit_test_cmp('no_balance_meas: t1',stim(2).meas_pattern, eye(4));
0502 
0503    stim = mk_stim_patterns(4,1,[0,1],'{mono}',{'no_meas_current'},1);
0504    unit_test_cmp('no_balance_meas: t0',length(stim), 4,1);
0505    unit_test_cmp('no_balance_meas: t1',stim(2).stim_pattern, [0;-1;1;0]);
0506    unit_test_cmp('no_balance_meas: t1',stim(2).meas_pattern, [1,0,0,0;0,0,0,1]);
0507 
0508    stim = mk_stim_patterns(4,1,[0,1],'{mono}',{},1); % DO WE WANT THIS AS DEFAULT??
0509    unit_test_cmp('no_balance_meas: t0',length(stim), 4,1);
0510    unit_test_cmp('no_balance_meas: t1',stim(2).stim_pattern, [0;-1;1;0]);
0511    unit_test_cmp('no_balance_meas: t1',stim(2).meas_pattern, [1,0,0,0;0,0,0,1]);
0512 
0513    stim = mk_stim_patterns(4,1,[0,1],'{mono}',{'balance_meas','meas_current'},1);
0514    unit_test_cmp('balance_meas: t0',length(stim), 4);
0515    unit_test_cmp('balance_meas: t1',stim(2).stim_pattern, [0;-1;1;0]);
0516    unit_test_cmp('balance_meas: t1',stim(2).meas_pattern, (4*eye(4)-ones(4))/3);
0517 
0518    stim = mk_stim_patterns(4,1,[0,1],[0,1],{},2);
0519    unit_test_cmp('amplitude: t1',stim(2).stim_pattern, [0;-2;2;0]);
0520    stim = mk_stim_patterns(4,1,'{ad}',[0,1],{},2);
0521    unit_test_cmp('amplitude: t2',stim(2).stim_pattern, [0;-2;2;0]);
0522    stim = mk_stim_patterns(4,1,'{mono}',[0,1],{'no_balance_inj'},2);
0523    unit_test_cmp('amplitude: t3',stim(2).stim_pattern, [0;2;0;0]);
0524    stim = mk_stim_patterns(4,1,'{mono}',[0,1],{},2);
0525    unit_test_cmp('amplitude: t4',stim(2).stim_pattern, [0;2;0;0]);
0526   
0527    [stim,msel] = mk_stim_patterns(6,1,[0,2],[0,1],{'meas_current','no_rotate_meas'},2);
0528    msel = reshape(msel, 6, 6);
0529    unit_test_cmp('meas_sel: t1',msel(:,6), [1;1;1;1;1;1]);
0530 
0531    [stim,msel] = mk_stim_patterns(6,1,[0,2],[0,1],{'meas_current','rotate_meas'},2);
0532    msel = reshape(msel, 6, 6);
0533    unit_test_cmp('meas_sel: t1',msel(:,6), [1;1;1;1;1;1]);
0534 
0535    [stim,msel] = mk_stim_patterns(6,1,[0,1],[0,1],{'no_meas_current','no_rotate_meas'},2);
0536    msel = reshape(msel, 6, 6);
0537    unit_test_cmp('meas_sel: t1',msel(:,6), [0;1;1;1;0;0]);
0538 
0539    [stim,msel] = mk_stim_patterns(6,1,[0,2],[0,1],{'meas_current','no_rotate_meas'},2);
0540    msel = reshape(msel, 6, 6);
0541    unit_test_cmp('meas_sel: t1',msel(:,6), [1;1;1;1;1;1]);
0542 
0543    [stim,msel] = mk_stim_patterns(6,1,[0,1],[0,1],{'no_meas_current','no_rotate_meas'},2);
0544    msel = reshape(msel, 6, 6);
0545    unit_test_cmp('meas_sel: nnp01',msel(:,[4,5]), [1,1;1,1;0,1;0,0;0,0;1,0]);
0546 
0547    [stim,msel] = mk_stim_patterns(6,1,[0,2],[0,1],{'no_meas_current','no_rotate_meas'},2);
0548    msel = reshape(msel, 6, 6);
0549    unit_test_cmp('meas_sel: nnp02',msel(:,[4,5]), [1,0;1,1;0,1;0,0;0,0;0,0]);
0550 
0551    [stim,msel] = mk_stim_patterns(6,1,[0,3],[0,1],{'no_meas_current','no_rotate_meas'},2);
0552    msel = reshape(msel, 6, 6);
0553    unit_test_cmp('meas_sel: nnp03',msel(:,[4,5]), [0,0;1,0;0,1;0,0;1,0;0,1]);
0554 
0555    [stim,msel] = mk_stim_patterns(6,1,[1,2],[0,1],{'no_meas_current','no_rotate_meas'},2);
0556    msel = reshape(msel, 6, 6);
0557    unit_test_cmp('meas_sel: nnp12',msel(:,[4,5]), [1,0;1,1;1,1;0,1;0,0;0,0]);
0558 
0559    [stim,msel] = mk_stim_patterns(6,1,[2,4],[0,1],{'no_meas_current','no_rotate_meas'},2);
0560    msel = reshape(msel, 6, 6);
0561    unit_test_cmp('meas_sel: nnp24',msel(:,[4,5]), [0,0;0,0;1,0;1,1;0,1;0,0]);
0562 
0563    [stim,msel] = mk_stim_patterns(6,1,[2,4],[3,6],{'no_meas_current','no_rotate_meas'},2);
0564    msel = reshape(msel, 6, 6);
0565    unit_test_cmp('meas_sel: nnp2436',msel(:,[4,5]), [1,0;0,1;0,0;1,0;0,1;0,0]);
0566 
0567    [stim,msel] = mk_stim_patterns(6,1,[0,1],[0,1],{'no_meas_current','rotate_meas'},2);
0568    msel = reshape(msel, 6, 6);
0569    unit_test_cmp('meas_sel: nrp01',msel(:,6), [0;0;1;1;1;0]);
0570 
0571    [stim,msel] = mk_stim_patterns(6,1,[0,2],[0,1],{'no_meas_current','rotate_meas'},2);
0572    msel = reshape(msel, 6, 6);
0573    unit_test_cmp('meas_sel: nrp02',msel(:,6), [0;0;0;1;1;0]);
0574 
0575    [stim,msel] = mk_stim_patterns(6,1,[0,2],[3,4],{'no_meas_current','rotate_meas'},2);
0576    msel = reshape(msel, 6, 6);
0577    unit_test_cmp('meas_sel: nrp0234',msel(:,6), [1;1;0;0;0;0]);
0578 
0579    [stim,msel] = mk_stim_patterns(6,1,[0,1],[0,1],{'no_meas_current','no_rotate_meas','no_redundant'},2);
0580    msel = reshape(msel, 6, 6);
0581    unit_test_cmp('meas_sel: nnp01',msel(:,[2,5]), [0,0;0,0;0,0;1,0;1,0;1,0]);
0582 
0583    [stim,msel] = mk_stim_patterns(6,1,[0,2],'{mono}',{'no_meas_current','no_rotate_meas'},2);
0584    msel = reshape(msel, 6, 6);
0585    unit_test_cmp('meas_sel: nnp2436',msel(:,[4,5]), [1,0;1,1;1,1;0,1;1,0;0,1]);
0586 
0587    [stim,msel] = mk_stim_patterns(16,1,[0,1],[0,1],{'no_meas_current_next1','no_rotate_meas'},1);
0588    unit_test_cmp('meas_sel: next1a',msel(48+(1:16)), [1;0;0;0;0;0;1;1;1;1;1;1;1;1;1;1]);
0589    [stim,msel] = mk_stim_patterns(16,1,[0,5],[0,5],{'no_meas_current_next1','no_rotate_meas'},1);
0590    unit_test_cmp('meas_sel: next1b',msel(48+(1:16)), [1;1;0;0;0;1;1;0;0;0;1;1;1;0;0;0]);
0591    [stim,msel] = mk_stim_patterns(16,1,[0,5],[0,5],{'no_meas_current_next1','rotate_meas'},1);
0592    unit_test_cmp('meas_sel: next1c',msel(48+(1:16)), [0;0;1;1;0;0;0;1;1;1;0;0;0;1;1;0]);
0593 
0594 
0595 % TESTS FROM OLD mk_stim_patterns_test CODE
0596    pat= mk_stim_patterns(16,1,'{ad}','{ad}',{}, 1);
0597    test_adj(pat);
0598 
0599    options= {'no_rotate_meas'};
0600    pat= mk_stim_patterns(16,1,'{ad}','{ad}', options,1);
0601    test_adj(pat);
0602 
0603    options= {'no_rotate_meas', 'no_meas_current'};
0604    pat= mk_stim_patterns(16,1,'{ad}','{ad}', options,1);
0605    test_adj(pat);
0606 
0607    options= {'no_rotate_meas', 'meas_current'};
0608    pat= mk_stim_patterns(16,1,'{ad}','{ad}', options,1);
0609    test_adj_full(pat);
0610 
0611    options= {'meas_current'};
0612    pat= mk_stim_patterns(16,1,'{ad}','{ad}', options,1);
0613    test_adj_full(pat);
0614 
0615    options= {'rotate_meas'};
0616    pat= mk_stim_patterns(16,1,'{ad}','{ad}', options,1);
0617    test_adj_rotate(pat);
0618 
0619    options= {'rotate_meas', 'no_meas_current'};
0620    pat= mk_stim_patterns(16,1,'{ad}','{ad}', options,1);
0621    test_adj_rotate(pat);
0622 
0623    options= {'rotate_meas','no_redundant', 'no_meas_current'};
0624    pat= mk_stim_patterns(16,1,'{ad}','{ad}', options,1);
0625    test_adj_no_redund(pat);
0626 
0627 function ok= test_adj(pat)
0628    %%%  test adjacent current pattern
0629 
0630    unit_test_cmp('pt#01', length(pat), 16);
0631    unit_test_cmp('pt#02', pat(1).stimulation, 'Amp');
0632    unit_test_cmp('pt#03', pat(1).stim_pattern, [-1;1;zeros(14,1)]); % Stim pattern # 1
0633 
0634    meas= pat(1).meas_pattern;
0635    unit_test_cmp('pt#04', size(meas), [13 16] );
0636    unit_test_cmp('pt#05', meas(1,:), [0,0,1,-1,zeros(1,12)] );
0637    unit_test_cmp('pt#06', meas(13,:), [zeros(1,14),1,-1] );
0638    unit_test_cmp('pt#07', pat(10).stim_pattern , [zeros(9,1);-1;1;zeros(5,1)] );
0639 
0640    meas= pat(10).meas_pattern;
0641    unit_test_cmp('pt#08', size(meas), [13 16] );
0642    unit_test_cmp('pt#09', meas(1,:), [1,-1,zeros(1,14)] );
0643    unit_test_cmp('pt#10', meas(13,:), [-1,zeros(1,14),1] );
0644 
0645 function ok= test_adj_full(pat)
0646    %%% test adjacent current pattern (full)
0647 
0648    unit_test_cmp('pt#11', length(pat), 16);
0649    unit_test_cmp('pt#12', pat(1).stimulation, 'Amp');
0650    unit_test_cmp('pt#13', pat(1).stim_pattern, [-1;1;zeros(14,1)]);
0651 
0652    meas= pat(1).meas_pattern;
0653    unit_test_cmp('pt#14', size(meas), [16 16] );
0654    unit_test_cmp('pt#15', meas(1,:), [1,-1,zeros(1,14)] );
0655    unit_test_cmp('pt#16', meas(13,:), [zeros(1,12),1,-1,0,0] );
0656    unit_test_cmp('pt#17', pat(10).stim_pattern, [zeros(9,1);-1;1;zeros(5,1)] );
0657 
0658    meas= pat(10).meas_pattern;
0659    unit_test_cmp('pt#18', size(meas), [16 16] );
0660    unit_test_cmp('pt#19', meas(1,:), [1,-1,zeros(1,14)] );
0661    unit_test_cmp('pt#20', meas(13,:), [zeros(1,12),1,-1,0,0] );
0662 
0663 
0664 function ok= test_adj_rotate(pat)
0665    %%%% test adjacent current pattern (rotate)
0666 
0667    unit_test_cmp('pt#21', length(pat), 16);
0668    unit_test_cmp('pt#22', pat(1).stimulation, 'Amp');
0669    unit_test_cmp('pt#23', pat(1).stim_pattern, [-1;1;zeros(14,1)]);
0670 
0671    meas= pat(1).meas_pattern;
0672    unit_test_cmp('pt#24', size(meas), [13 16] );
0673    unit_test_cmp('pt#25', meas(1,:), [0,0,1,-1,zeros(1,12)] );
0674    unit_test_cmp('pt#26', meas(13,:), [zeros(1,14),1,-1] );
0675    unit_test_cmp('pt#27', pat(10).stim_pattern, [zeros(9,1);-1;1;zeros(5,1)] );
0676 
0677    meas= pat(10).meas_pattern;
0678    unit_test_cmp('pt#28', size(meas), [13 16] );
0679    unit_test_cmp('pt#29', meas(1,:), [zeros(1,11),1,-1,zeros(1,3)] );
0680    unit_test_cmp('pt#30', meas(13,:), [zeros(1,7),1,-1,zeros(1,7)] );
0681 
0682 function ok= test_adj_no_redund(pat)
0683    %%% test adjacent current pattern (rotate)
0684 
0685    unit_test_cmp('pt#31', length(pat), 14);
0686    unit_test_cmp('pt#32', pat(1).stimulation, 'Amp');
0687    unit_test_cmp('pt#33', pat(1).stim_pattern, [-1;1;zeros(14,1)]);
0688 
0689    meas= pat(1).meas_pattern;
0690    unit_test_cmp('pt#34', size(meas), [13 16] );
0691    unit_test_cmp('pt#35', meas(1,:), [0,0,1,-1,zeros(1,12)] );
0692    unit_test_cmp('pt#36', meas(13,:), [zeros(1,14),1,-1] );
0693    unit_test_cmp('pt#37', pat(10).stim_pattern, [zeros(9,1);-1;1;zeros(5,1)] );
0694 
0695    meas= pat(10).meas_pattern;
0696    unit_test_cmp('pt#38', size(meas), [5 16] );
0697    unit_test_cmp('pt#39', meas(1,:), [zeros(1,11),1,-1,zeros(1,3)] );
0698    unit_test_cmp('pt#40', meas(5,:), [-1,zeros(1,14),1] );
0699

Generated on Wed 21-Jun-2017 09:29:07 by m2html © 2005