Matlab is special. Scientists and researchers love it. Programmers hate it, and not just because it uses 1-based arrays. I've worked on a number of projects where the task was "take this Matlab code and convert it to C so we can run it on an embedded CPU". Somehow, in that process, I've avoided learning much about Matlab.

Andre works on a team that uses Matlab to manage experimental scenarios. They wanted to do a simple task: generate a set of participant-specific images, store them in a database, and reference them later. Somewhere in the intersection of the database product they were using, the Matlab license they had, and other constraints, they discovered that there simply was no good way to do this.

Enter "Jude". Jude said, "Don't worry about it, I can hack something together."

I present the code in its entirety, but don't ask me to explain it. Instead, read the comments.

nMk = 1;%counting non-response triggers, this cycles with each trial
nPress = 0;%counting button presses, noting the position in the log

for v = 1:height(resVmrk)%read each trigger
	switch nMk
		%it's kinda roundabout, but the only recognisable part is the response
		%yet I refer to it only by elision
		%and instead count the stimuli to reconstruct the pattern
		case 1%an almost reliable stimulus
			nPress = nPress+1;%trial start
			if strcmp(resVmrk.TriggerCode{v},'S1')%it must be a non-response
				resVmrk.TriggerCode{v} = 'cross';%name it properly
				nMk = 2;%and expect the next one
			else%except when it is not
				resLog.miss(nPress) = 1;%then note it down as missed
				nMk = 0;%and skip to response
			end
			
		case 2%usually reliable
			if strcmp(resVmrk.TriggerCode{v},'S1')%if the face loaded successfully
				resVmrk.TriggerCode{v} = 'face';%note it
				nMk = 3;%and proceed accordingly
				if nPress<=height(resLog)%trailing triggers at the end should be ignored
					resLog.facePos(nPress) = v;%note the position
				end
			else%if it failed to load it is a response
				resVmrk.Dur(v-1:v+1) = 0;%mark the whole trial for deletion
				resLog.miss(nPress) = 1;%and note it down as missing the face
				nMk = 0;%and skip to response
			end
			
		case 3%this one is not reliable, and sometimes is duplicated instead of missing
			if strcmp(resVmrk.TriggerCode{v},'S1')%if it is present at all
				resVmrk.TriggerCode{v} = 'empty';%first name it
				if v<height(resVmrk)%if it is not a trailing trigger, since it'll break the check otherwise
					if ~strcmp(resVmrk.TriggerCode{v+1},'S1')%if the next trigger is a response
						nMk = 0;%all is fine and it didn't freak out, proceed to response
					else%otherwise
						nMk = 3;%just treat as a double
						%and then count how many excess triggers are actually here
						nExcess = 1;%definitely one here already
						while strcmp(resVmrk.TriggerCode{v+nExcess+1},'S1')
							nExcess = nExcess+1;%and everything until the response
						end
						resVmrk.Dur(v-2:v+nExcess+2) = 0;%then mark the whole trial for deletion
						%this overwrites the same positions several time, but the important part is to get the preceding two, because I don't know which one of them is correct one, so I delete the whole trial
						if nPress<=height(resLog)
							resLog.bad(nPress) = 1;%also note it down as borked
						end
					end
				end
			else
				nMk = 0;%if it didn't happen at all simply proceed to response
			end
			
		case 0%this one reliably follows the response, so I address the response by elision
			if strcmp(resVmrk.TriggerCode{v},'S1')%skip response itself
				resVmrk.TriggerCode{v} = 'blink';%note the only reliable non-response (always following the response)
				nMk = 1;%start the trial anew
				if nPress<=height(resLog)%if it is not a trailing trigger
					resLog.respPos(nPress) = v-1;%note down the response position
					if resLog.miss(nPress)==1%and if it's a response without a stimulus
						resVmrk.Dur(v-1:v) = 0;%mark it for deletion as well
					end
				end
			end
	end
end

Ah, the classic "for-case" antipattern. That's gross enough, but what the heck is happening inside each of those cases?

My personal favorite comment is this one: "%this overwrites the same positions several time, but the important part is to get the preceding two, because I don't know which one of them is correct one, so I delete the whole trial"

Now, you may suspect comments like "usually reliable" are about what we see in the dataset, but I'm not so certain. Andre writes:

After reverting the last discovered way for his creation to corrupt the data I was able to figure out that 20% of the logs provided corresponded to different (unknown) experiments altogether.

[Advertisement] Keep the plebs out of prod. Restrict NuGet feed privileges with ProGet. Learn more.