0001 function out=DIVA_MotorCortex(varargin)
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056 out=[];
0057 global DIVA_MotorCortex_data
0058
0059
0060
0061
0062 somethingtoexecute=0;
0063 for indexargin=1:2:nargin,
0064 switch(varargin{indexargin}),
0065 case 'init',
0066 SessionFolder=strcat(DIVA('SessionFolder'),filesep);
0067 if nargin<indexargin+1 || isempty(varargin{indexargin+1}),
0068 initfile='';
0069 else,
0070 initfile=[SessionFolder,'Session_',varargin{indexargin+1},filesep,mfilename,'.mat'];
0071 end
0072 if isempty(initfile) || isempty(dir(initfile)),
0073 disp([mfilename, ' : Defining new session...']);
0074 DIVA_MotorCortex_data.params = struct(...
0075 'nMotor',2*DIVA('VocalTract','nArtic'),...
0076 'eps_motor',.25,...
0077 'eps_decay',.95,...
0078 'delayToVocalTract',.005,...
0079 'WeightFeedForward',0.9,...
0080 'WeightFeedBack',0.1,...
0081 'WeightFeedBack_sound',0.8,...
0082 'WeightFeedBack_somatosensory',.0,...
0083 'WeightLearn',0.7,...
0084 'WeightLearn_sound',0.6,...
0085 'WeightLearn_somatosensory',0,...
0086 'ErrorNoise_sound', [0 0], ...
0087 'ErrorNoise_somatosensory', [0 0], ...
0088 'ErrorNoise_ffAmplitude', [0 0], ...
0089 'ErrorNoise_ffTiming', [0,0], ...
0090 'WeightsFromTargets',[],...
0091 'InverseParameters',struct(...
0092 'DELTA', 5,...
0093 'ALPHA', 0.5,...
0094 'BETA', 0.05,...
0095 'LAMBDA',0),...
0096 'plotf',0);
0097 else,
0098 data=load(initfile,'-mat');
0099 DIVA_MotorCortex_data.params=data.params;
0100 end
0101
0102 DIVA_MotorCortex_data.params.TimeStep=DIVA('TimeStep');
0103 DIVA_MotorCortex_data.params.default_motorSound = ...
0104 (0.5*ones(DIVA_MotorCortex_data.params.nMotor,1));
0105
0106
0107 DIVA_MotorCortex_data.params.default_motorSilence = ...
0108 (0.5*ones(DIVA_MotorCortex_data.params.nMotor,1));
0109
0110
0111 DIVA_MotorCortex_data.params.motorAmplitude = DIVA('VocalTract','Amplitude');
0112
0113
0114 DIVA_MotorCortex_data.params.MaedaSpread = DIVA('VocalTract','MaedaSpread');
0115 DIVA_MotorCortex_data.params.delayFromSomatosensoryCortex=...
0116 DIVA('SomatosensoryCortex','delayToMotorCortex');
0117 DIVA_MotorCortex_data.params.delayFromAuditoryCortex=...
0118 DIVA('AuditoryCortex','delayToMotorCortex');
0119 DIVA_MotorCortex_data.params.delayToerror_sound=...
0120 DIVA_MotorCortex_data.params.delayToVocalTract+...
0121 DIVA('VocalTract','delayToSoundChannel')+...
0122 0*DIVA('SoundChannel','delayToCochlea')+...
0123 DIVA('Cochlea','delayToAuditoryCortex')+...
0124 DIVA('AuditoryCortex','delayToMotorCortex');
0125 DIVA_MotorCortex_data.params.delayToerror_somatosensory=...
0126 DIVA_MotorCortex_data.params.delayToVocalTract+...
0127 DIVA('VocalTract','delayToSensoryChannel')+...
0128 0*DIVA('SensoryChannel','delayToSensory')+...
0129 DIVA('Sensory','delayToSomatosensoryCortex')+...
0130 DIVA('SomatosensoryCortex','delayToMotorCortex');
0131 DIVA_MotorCortex_data.params.current.motor=...
0132 DIVA_MotorCortex_data.params.default_motorSilence;
0133 DIVA_MotorCortex_data.params.current.error_sound=[];
0134 DIVA_MotorCortex_data.params.current.error_somatosensory=[];
0135 DIVA_MotorCortex_data.params.current.target=[];
0136
0137 DIVA_MotorCortex_data.params.current.motorupdate_a=0;
0138 DIVA_MotorCortex_data.params.current.motorupdate_s=0;
0139
0140
0141 out={'error_sound','error_somatosensory','target'};
0142
0143 case 'save',
0144 SessionFolder=strcat(DIVA('SessionFolder'),filesep);
0145 if nargin<indexargin+1,
0146 initfile=[SessionFolder,'Session_','default',filesep,mfilename,'.mat'];
0147 else,
0148 initfile=[SessionFolder,'Session_',varargin{indexargin+1},filesep,mfilename,'.mat'];
0149 end
0150 params=DIVA_MotorCortex_data.params;
0151 save(initfile,'params');
0152
0153 case 'exit',
0154 clear DIVA_MotorCortex_data
0155
0156 case 'disp',
0157 disp(DIVA_MotorCortex_data.params);
0158 out=fieldnames(DIVA_MotorCortex_data.params);
0159
0160
0161
0162
0163 case 'error_sound'
0164
0165
0166 DIVA_MotorCortex_data.params.current.error_sound = varargin{indexargin+1};
0167 somethingtoexecute=1;
0168 if ~nargout,
0169 DIVA('GUI','other_weights','error_sound');
0170 DIVA('ModelStatePlot','MotorCortex','error_sound');
0171 end
0172
0173 case 'error_somatosensory'
0174
0175 DIVA_MotorCortex_data.params.current.error_somatosensory = varargin{indexargin+1};
0176 somethingtoexecute=1;
0177 if ~nargout,
0178 DIVA('GUI','other_weights','error_somatosensory');
0179 DIVA('ModelStatePlot','MotorCortex','error_somatosensory');
0180 end
0181
0182 case 'target'
0183
0184 DIVA_MotorCortex_data.params.current.target=varargin{indexargin+1};
0185 somethingtoexecute=1;
0186 if ~nargout,
0187 DIVA('ModelStatePlot','MotorCortex','target');
0188 end
0189
0190 otherwise,
0191 if isfield(DIVA_MotorCortex_data.params,varargin{indexargin}),
0192 if indexargin==nargin,
0193 out=DIVA_MotorCortex_data.params.(varargin{indexargin});
0194 else,
0195 if(strmatch('errornoise',lower(varargin{indexargin}))),
0196 if(length(varargin{indexargin+1})==1)
0197 DIVA_MotorCortex_data.params.(varargin{indexargin}) = ...
0198 [0 varargin{indexargin+1}];
0199 else
0200 DIVA_MotorCortex_data.params.(varargin{indexargin}) = ...
0201 varargin{indexargin+1};
0202 end
0203 else
0204 DIVA_MotorCortex_data.params.(varargin{indexargin})=varargin{indexargin+1};
0205 end
0206 end
0207 else,
0208 warning('DIVA_MotorCortex: wrong argument');
0209 end
0210 end
0211 end
0212
0213
0214
0215
0216 if somethingtoexecute,
0217 ntimepoints=DIVA('AuditoryCortexCategorical','ntimepoints');
0218 if(DIVA_MotorCortex_data.params.WeightLearn > 0),
0219
0220 if ~isempty(DIVA_MotorCortex_data.params.current.error_sound) && ...
0221 DIVA_MotorCortex_data.params.WeightFeedBack_sound>0,
0222
0223
0224
0225 originalmotorcommand=DIVA('VocalTract','motor',[],...
0226 -DIVA_MotorCortex_data.params.delayToerror_sound+...
0227 DIVA_MotorCortex_data.params.delayToVocalTract+...
0228 DIVA_MotorCortex_data.params.TimeStep*...
0229 (0:size(DIVA_MotorCortex_data.params.current.error_sound,2)-1));
0230
0231 originaltarget=DIVA('AuditoryCortex','target',[],...
0232 -DIVA_MotorCortex_data.params.delayFromAuditoryCortex+...
0233 DIVA_MotorCortex_data.params.TimeStep*...
0234 (0:size(DIVA_MotorCortex_data.params.current.error_sound,2)-1));
0235
0236 originalsound=DIVA('AuditoryCortex','sound',[],...
0237 -DIVA_MotorCortex_data.params.delayFromAuditoryCortex+...
0238 DIVA_MotorCortex_data.params.TimeStep*...
0239 (0:size(DIVA_MotorCortex_data.params.current.error_sound,2)-1));
0240
0241 errorsound = DIVA_MotorCortex_data.params.current.error_sound;
0242 nMotor = DIVA_MotorCortex_data.params.nMotor;
0243 nArtic = DIVA('VocalTract','nArtic');
0244 nFormants = DIVA('AuditoryCortex','nFormants');
0245
0246 N=size(DIVA_MotorCortex_data.params.current.error_sound,2);
0247
0248 tmp=DIVA('VocalTract','motor',originalmotorcommand);
0249 artic=tmp{2}(1:nArtic,:);
0250
0251
0252 motor = calculateInverse(originalmotorcommand,originalsound,errorsound,nFormants);
0253
0254 motor = motor + (DIVA_MotorCortex_data.params.ErrorNoise_sound(1) + ...
0255 DIVA_MotorCortex_data.params.ErrorNoise_sound(2) * ...
0256 randn(size(motor)));
0257 DIVA_MotorCortex_data.params.current.error_sound = motor;
0258 CommandFeedBack_sound=DIVA_MotorCortex_data.params.current.error_sound;
0259 else
0260 CommandFeedBack_sound = 0;
0261 end
0262
0263
0264
0265
0266 if ~isempty(DIVA_MotorCortex_data.params.current.error_somatosensory) && ...
0267 DIVA_MotorCortex_data.params.WeightFeedBack_somatosensory > 0,
0268
0269 originalmotorcommand = ...
0270 DIVA('VocalTract','motor',[],...
0271 -DIVA_MotorCortex_data.params.delayToerror_somatosensory+...
0272 DIVA_MotorCortex_data.params.delayToVocalTract+...
0273 DIVA_MotorCortex_data.params.TimeStep*...
0274 (0:size(DIVA_MotorCortex_data.params.current.error_somatosensory,2)-1));
0275
0276 originaltarget = ...
0277 DIVA('SomatosensoryCortex','target',[],...
0278 -DIVA_MotorCortex_data.params.delayFromSomatosensoryCortex+...
0279 DIVA_MotorCortex_data.params.TimeStep*...
0280 (0:size(DIVA_MotorCortex_data.params.current.error_somatosensory,2)-1));
0281
0282 originalsomato = ...
0283 DIVA('SomatosensoryCortex','somatosensory',[],...
0284 -DIVA_MotorCortex_data.params.delayFromSomatosensoryCortex+...
0285 DIVA_MotorCortex_data.params.TimeStep*...
0286 (0:size(DIVA_MotorCortex_data.params.current.error_somatosensory,2)-1));
0287
0288 nArtic = DIVA('VocalTract','nArtic');
0289 nMotor = DIVA_MotorCortex_data.params.nMotor;
0290 nSomato = DIVA('Sensory','nSensory');
0291 errorsomato = DIVA_MotorCortex_data.params.current.error_somatosensory;
0292
0293 N = size(DIVA_MotorCortex_data.params.current.error_somatosensory,2);
0294
0295
0296 motor = calculateInverse(originalmotorcommand,originalsomato,errorsomato,nSomato);
0297
0298 motor = motor + (DIVA_MotorCortex_data.params.ErrorNoise_somatosensory(1) + ...
0299 DIVA_MotorCortex_data.params.ErrorNoise_somatosensory(2) * ...
0300 randn(size(motor)));
0301
0302 DIVA_MotorCortex_data.params.current.error_somatosensory=motor;
0303 CommandFeedBack_somatosensory=DIVA_MotorCortex_data.params.current.error_somatosensory;
0304 else
0305 CommandFeedBack_somatosensory = 0;
0306 end
0307
0308
0309
0310
0311 CommandFeedBack = ...
0312 (DIVA_MotorCortex_data.params.WeightFeedBack_sound * CommandFeedBack_sound) + ...
0313 (DIVA_MotorCortex_data.params.WeightFeedBack_somatosensory * ...
0314 CommandFeedBack_somatosensory);
0315
0316 else,
0317 CommandFeedBack=0;
0318 end
0319
0320
0321
0322 if ~isempty(DIVA_MotorCortex_data.params.current.target),
0323
0324 idx=union(floor(DIVA_MotorCortex_data.params.current.target),...
0325 ceil(DIVA_MotorCortex_data.params.current.target));
0326
0327
0328 if max(idx)+ntimepoints>size(DIVA_MotorCortex_data.params.WeightsFromTargets,2),
0329 idxnew=size(DIVA_MotorCortex_data.params.WeightsFromTargets,2)+...
0330 1:max(idx)+ntimepoints;
0331
0332 DIVA_MotorCortex_data.params.WeightsFromTargets(:,idxnew) = ...
0333 DIVA_MotorCortex_data.params.default_motorSound(:,ones(1,length(idxnew)));
0334 end
0335
0336
0337
0338
0339 if length(idx)>1,
0340 DIVA_MotorCortex_data.params.current.targetmotor = ...
0341 fastinterp1(idx,DIVA_MotorCortex_data.params.WeightsFromTargets(:,idx),...
0342 DIVA_MotorCortex_data.params.current.target);
0343 else,
0344 DIVA_MotorCortex_data.params.current.targetmotor = ...
0345 DIVA_MotorCortex_data.params.WeightsFromTargets(:,idx*ones(1,size(DIVA_MotorCortex_data.params.current.target,2)));
0346 end
0347 if nargout>0,
0348 tempcurrentmotor = DIVA_MotorCortex_data.params.current.motor;
0349 DIVA_MotorCortex_data.params.current.motor = ...
0350 DIVA_MotorCortex_data.params.default_motorSilence;
0351 end
0352
0353
0354
0355 for n1=1:size(DIVA_MotorCortex_data.params.current.target,2),
0356
0357 CommandFeedForward = ...
0358 DIVA_MotorCortex_data.params.current.targetmotor(:,n1) - ...
0359 DIVA_MotorCortex_data.params.current.motor;
0360
0361 CommandFeedForward = CommandFeedForward + ...
0362 (DIVA_MotorCortex_data.params.ErrorNoise_ffAmplitude(1) + ...
0363 DIVA_MotorCortex_data.params.ErrorNoise_ffAmplitude(2) * ...
0364 randn(size(CommandFeedForward)));
0365
0366
0367 Command = DIVA_MotorCortex_data.params.WeightFeedBack*...
0368 CommandFeedBack(:,min(n1,size(CommandFeedBack,2))) + ...
0369 DIVA_MotorCortex_data.params.WeightFeedForward*CommandFeedForward;
0370
0371
0372 DIVA_MotorCortex_data.params.current.motor = ...
0373 max(0,min(1,DIVA_MotorCortex_data.params.default_motorSilence + ...
0374 DIVA_MotorCortex_data.params.eps_decay*...
0375 (DIVA_MotorCortex_data.params.current.motor - ...
0376 DIVA_MotorCortex_data.params.default_motorSilence) + ...
0377 DIVA_MotorCortex_data.params.eps_motor * Command));
0378 out(:,n1)=(DIVA_MotorCortex_data.params.current.motor);
0379 end
0380
0381
0382
0383 if ~nargout,
0384 DIVA('VocalTract','motor',out,DIVA_MotorCortex_data.params.delayToVocalTract);
0385 else,
0386 DIVA_MotorCortex_data.params.current.motor=tempcurrentmotor;
0387 end
0388 end
0389
0390
0391
0392
0393
0394 if DIVA_MotorCortex_data.params.WeightLearn > 0,
0395
0396 if ~isempty(DIVA_MotorCortex_data.params.current.error_sound) && ...
0397 DIVA_MotorCortex_data.params.WeightLearn_sound > 0,
0398
0399
0400 targettolearn = DIVA('MotorCortex','target',[],...
0401 -DIVA_MotorCortex_data.params.delayToerror_sound + ...
0402 DIVA_MotorCortex_data.params.TimeStep*...
0403 (0:size(CommandFeedBack_sound,2)));
0404
0405
0406
0407 if(targettolearn(end)<targettolearn(end-1)),
0408 targettolearn(end)=0;
0409 end
0410
0411 if ~all(targettolearn(1:end-1)>0),
0412 disp('DIVA_MotorCortex: warning, receiving sound error signal without a motor cause');
0413 else,
0414 idxvalid = 1:length(targettolearn)-1;
0415 idx = floor(targettolearn(idxvalid(1))):floor(targettolearn(idxvalid(end)));
0416 idx = idx(find(idx>0));
0417
0418
0419
0420
0421
0422
0423
0424
0425 if(~DIVA('BlockMode')),
0426 DIVA_MotorCortex_data.params.current.motorupdate_a=...
0427 DIVA_MotorCortex_data.params.current.motorupdate_a+...
0428 DIVA_MotorCortex_data.params.WeightLearn * ...
0429 DIVA_MotorCortex_data.params.WeightLearn_sound * ...
0430 CommandFeedBack_sound + sqrt(-1);
0431
0432
0433 if diff(floor(targettolearn)),
0434
0435 idx = min(floor(targettolearn(find(targettolearn>0)))):max(ceil(targettolearn(find(targettolearn>0))));
0436 idx = idx(find(idx>0));
0437 if(diff(floor(targettolearn))<0)
0438 idx = idx;
0439 else
0440 idx = idx(find(idx<floor(targettolearn(end))));
0441 end
0442 DIVA_MotorCortex_data.params.WeightsFromTargets(:,idx)=...
0443 DIVA_MotorCortex_data.params.WeightsFromTargets(:,idx)+...
0444 repmat(real(DIVA_MotorCortex_data.params.current.motorupdate_a)./...
0445 imag(DIVA_MotorCortex_data.params.current.motorupdate_a),...
0446 1,length(idx));
0447 DIVA_MotorCortex_data.params.current.motorupdate_a=0;
0448 end
0449 else
0450 idx=unique(floor(targettolearn(find(targettolearn>0))));
0451 blockBound = diff(floor(targettolearn));
0452 for n=1:length(idx),
0453 if(blockBound(max(find(floor(targettolearn)==idx(n))))>0)
0454 targetIdx = ...
0455 idx(n):idx(n)+blockBound(max(find(floor(targettolearn)==idx(n))))-1;
0456 else
0457 targetIdx = idx(n):idx(n)+1;
0458 end
0459 DIVA_MotorCortex_data.params.WeightsFromTargets(:,targetIdx) = ...
0460 DIVA_MotorCortex_data.params.WeightsFromTargets(:,targetIdx) + ...
0461 DIVA_MotorCortex_data.params.WeightLearn * ...
0462 DIVA_MotorCortex_data.params.WeightLearn_sound * ...
0463 repmat(...
0464 sum(CommandFeedBack_sound(:,find(floor(targettolearn)==idx(n))),2) / ...
0465 length(find(floor(targettolearn)==idx(n))),...
0466 1,length(targetIdx));
0467 end
0468 end
0469 end
0470 end
0471
0472
0473
0474
0475 if ~isempty(DIVA_MotorCortex_data.params.current.error_somatosensory) & ...
0476 DIVA_MotorCortex_data.params.WeightLearn_somatosensory,
0477
0478 targettolearn = ...
0479 DIVA('MotorCortex','target',[],...
0480 -DIVA_MotorCortex_data.params.delayToerror_somatosensory + ...
0481 DIVA_MotorCortex_data.params.TimeStep*...
0482 (0:size(CommandFeedBack_somatosensory,2)));
0483
0484
0485
0486 if(targettolearn(end)<targettolearn(end-1)),
0487 targettolearn(end)=0;
0488 end
0489
0490 if ~all(targettolearn(1:end-1)>0),
0491 disp(['DIVA_MotorCortex: warning, receiving somatosensory error '...
0492 'signal without a motor cause']);
0493 else,
0494 idxvalid=1:length(targettolearn)-1;
0495 idx = floor(targettolearn(idxvalid(1))):floor(targettolearn(idxvalid(end)));
0496 idx = idx(find(idx>0));
0497
0498
0499 if(~DIVA('BlockMode')),
0500 DIVA_MotorCortex_data.params.current.motorupdate_s=...
0501 DIVA_MotorCortex_data.params.current.motorupdate_s+...
0502 DIVA_MotorCortex_data.params.WeightLearn * ...
0503 DIVA_MotorCortex_data.params.WeightLearn_somatosensory * ...
0504 CommandFeedBack_somatosensory + sqrt(-1);
0505
0506
0507 if(diff(floor(targettolearn))),
0508 idx = min(floor(targettolearn(find(targettolearn>0)))):max(ceil(targettolearn(find(targettolearn>0))));
0509 idx = idx(find(idx>0));
0510 if(diff(floor(targettolearn))<0)
0511 idx = idx;
0512 else
0513 idx = idx(find(idx<floor(targettolearn(end))));
0514 end
0515 DIVA_MotorCortex_data.params.WeightsFromTargets(:,idx)=...
0516 DIVA_MotorCortex_data.params.WeightsFromTargets(:,idx)+...
0517 repmat(real(DIVA_MotorCortex_data.params.current.motorupdate_s)./...
0518 imag(DIVA_MotorCortex_data.params.current.motorupdate_s),...
0519 1,length(idx));
0520 DIVA_MotorCortex_data.params.current.motorupdate_s=0;
0521 end
0522 else
0523 idx=unique(floor(targettolearn(find(targettolearn>0))));
0524 blockBound = diff(floor(targettolearn));
0525 for n=1:length(idx),
0526 if(blockBound(max(find(floor(targettolearn)==idx(n))))>0)
0527 targetIdx = ...
0528 idx(n):idx(n)+blockBound(max(find(floor(targettolearn)==idx(n))))-1;
0529 else
0530 targetIdx = idx(n):idx(n)+1;
0531 end
0532 DIVA_MotorCortex_data.params.WeightsFromTargets(:,targetIdx) = ...
0533 DIVA_MotorCortex_data.params.WeightsFromTargets(:,targetIdx) + ...
0534 DIVA_MotorCortex_data.params.WeightLearn * ...
0535 DIVA_MotorCortex_data.params.WeightLearn_somatosensory * ...
0536 repmat(...
0537 sum(CommandFeedBack_somatosensory(:,find(floor(targettolearn)==idx(n))),2) / ...
0538 length(find(floor(targettolearn)==idx(n))),...
0539 1,length(targetIdx));
0540 end
0541 end
0542 end
0543 end
0544 end
0545 DIVA_MotorCortex_data.params.current.error_sound=[];
0546 DIVA_MotorCortex_data.params.current.error_somatosensory=[];
0547 DIVA_MotorCortex_data.params.current.target=[];
0548
0549 end
0550