„scenarios/scripts/p300-tactile-accumulator.lua“ ändern

This commit is contained in:
Tobias Baumann 2022-05-29 08:14:09 +00:00
parent 44d07712eb
commit 8ba5957791

View File

@ -1,182 +1,202 @@
function arrayMax(a) function arrayMax(a)
if #a == 0 then return nil, nil end if #a == 0 then return nil, nil end
local maxIdx, maxValue = 0, a[0] local maxIdx, maxValue = 0, a[0]
for i = 1, (#a -1 ) do for i = 1, (#a -1 ) do
if maxValue < a[i] then if maxValue < a[i] then
maxIdx, maxValue = i, a[i] maxIdx, maxValue = i, a[i]
end end
end end
return maxIdx, maxValue return maxIdx, maxValue
end end
-- For handling target fifo -- For handling target fifo
List = {} List = {}
function List.new () function List.new ()
return {first = 0, last = -1} return {first = 0, last = -1}
end end
function List.pushright (list, value) function List.pushright (list, value)
local last = list.last + 1 local last = list.last + 1
list.last = last list.last = last
list[last] = value list[last] = value
end end
function List.popleft (list) function List.popleft (list)
local first = list.first local first = list.first
if first > list.last then if first > list.last then
error("list is empty") error("list is empty")
end end
local value = list[first] local value = list[first]
list[first] = nil -- to allow garbage collection list[first] = nil -- to allow garbage collection
list.first = first + 1 list.first = first + 1
return value return value
end end
function List.isempty (list) function List.isempty (list)
if list.first > list.last then if list.first > list.last then
return true return true
else else
return false return false
end end
end end
-- this function is called when the box is initialized -- this function is called when the box is initialized
function initialize(box) function initialize(box)
dofile(box:get_config("${Path_Data}") .. "/plugins/stimulation/lua-stimulator-stim-codes.lua") dofile(box:get_config("${Path_Data}") .. "/plugins/stimulation/lua-stimulator-stim-codes.lua")
row_base = _G[box:get_setting(2)] row_base = _G[box:get_setting(2)]
n_tactilos = box:get_setting(3) n_tactilos = box:get_setting(3)
segment_start = _G[box:get_setting(4)] segment_start = _G[box:get_setting(4)]
segment_stop = _G[box:get_setting(5)] segment_stop = _G[box:get_setting(5)]
-- 0 inactive, 1 segment started, 2 segment stopped (can vote) col_base = row_base + n_tactilos
segment_status = 0
-- 0 inactive, 1 segment started, 2 segment stopped (can vote)
-- the idea is to push the flash states to the fifo, and when predictions arrive (with some delay), they are matched in oldest-first fashion. segment_status = 0
target_fifo = List.new()
-- the idea is to push the flash states to the fifo, and when predictions arrive (with some delay), they are matched in oldest-first fashion.
-- box:log("Info", string.format("pop %d %d", id[1], id[2])) target_fifo = List.new()
row_votes = {} -- box:log("Info", string.format("pop %d %d", id[1], id[2]))
do_debug = false row_votes = {}
col_votes = {}
end
do_debug = false
-- this function is called when the box is uninitialized
function uninitialize(box) end
end -- this function is called when the box is uninitialized
function uninitialize(box)
function process(box)
-- loops until box is stopped end
while box:keep_processing() do
function process(box)
-- first, parse the timeline stream -- loops until box is stopped
for stimulation = 1, box:get_stimulation_count(2) do while box:keep_processing() do
-- gets the received stimulation
local identifier, date, duration = box:get_stimulation(2, 1) -- first, parse the timeline stream
-- discards it for stimulation = 1, box:get_stimulation_count(2) do
box:remove_stimulation(2, 1) -- gets the received stimulation
local identifier, date, duration = box:get_stimulation(2, 1)
if identifier == segment_start then -- discards it
if do_debug then box:remove_stimulation(2, 1)
box:log("Info", string.format("Trial start"))
box:log("Info", string.format("Clear votes")) if identifier == segment_start then
end if do_debug then
-- zero the votes box:log("Info", string.format("Trial start"))
row_votes = {} box:log("Info", string.format("Clear votes"))
target_fifo = List.new() end
-- fixme fixed 20 -- zero the votes
for i = 0,20 do col_votes = {}
row_votes[i] = 0 row_votes = {}
end target_fifo = List.new()
segment_status = 1 -- fixme fixed 20
end for i = 0,20 do
col_votes[i] = 0
-- Does the identifier code a flash? if so, put into fifo row_votes[i] = 0
if segment_status == 1 and identifier >= row_base and identifier <= OVTK_StimulationId_LabelEnd then end
segment_status = 1
-- assume rows before cols end
if identifier < (row_base + n_tactilos) then
local t = {"row", identifier - row_base} -- Does the identifier code a flash? if so, put into fifo
List.pushright(target_fifo,t) if segment_status == 1 and identifier >= row_base and identifier <= OVTK_StimulationId_LabelEnd then
if do_debug then
box:log("Info", string.format("Push row target %d", identifier - row_base )) -- assume rows before cols
end if identifier < col_base then
end local t = {"row", identifier - row_base}
List.pushright(target_fifo,t)
if do_debug then
end box:log("Info", string.format("Push row target %d", identifier - row_base ))
end
if identifier == segment_stop then else
if do_debug then local t = {"col", identifier - col_base}
box:log("Info", string.format("Trial stop")) List.pushright(target_fifo,t)
end if do_debug then
segment_status = 2 box:log("Info", string.format("Push col target %d", identifier - col_base ))
end end
end
end
-- then parse the classifications end
for stimulation = 1, box:get_stimulation_count(1) do
if identifier == segment_stop then
-- gets the received stimulation if do_debug then
local identifier, date, duration = box:get_stimulation(1, 1) box:log("Info", string.format("Trial stop"))
-- discards it end
box:remove_stimulation(1, 1) segment_status = 2
end
-- Is it an in-class prediction?
if identifier == OVTK_StimulationId_Target then end
local t = List.popleft(target_fifo)
if do_debug then -- then parse the classifications
box:log("Info", string.format("Pred fifo %s %d is target", t[1], t[2])) for stimulation = 1, box:get_stimulation_count(1) do
end
if t[1]=="row" then -- gets the received stimulation
row_votes[t[2]] = row_votes[t[2]] + 1 local identifier, date, duration = box:get_stimulation(1, 1)
end -- discards it
end box:remove_stimulation(1, 1)
if identifier == OVTK_StimulationId_NonTarget then -- Is it an in-class prediction?
local t = List.popleft(target_fifo) if identifier == OVTK_StimulationId_Target then
if do_debug then local t = List.popleft(target_fifo)
box:log("Info", string.format("Pred fifo %s %d is nontarget", t[1], t[2])) if do_debug then
end box:log("Info", string.format("Pred fifo %s %d is target", t[1], t[2]))
end end
if t[1]=="row" then
end row_votes[t[2]] = row_votes[t[2]] + 1
else
if segment_status == 2 and List.isempty(target_fifo) then col_votes[t[2]] = col_votes[t[2]] + 1
-- output the vote after the segment end when we've matched all predictions end
end
local maxRowIdx, maxRowValue = arrayMax(row_votes)
if identifier == OVTK_StimulationId_NonTarget then
if maxRowValue == 0 then local t = List.popleft(target_fifo)
box:log("Warning", string.format("Classifier predicted 'no p300' for all flashes of the trial")); if do_debug then
end box:log("Info", string.format("Pred fifo %s %d is nontarget", t[1], t[2]))
end
if do_debug then end
local rowVotes = 0
for ir, val in pairs(row_votes) do end
rowVotes = rowVotes + val
end if segment_status == 2 and List.isempty(target_fifo) then
-- output the vote after the segment end when we've matched all predictions
box:log("Info", string.format("Vote [%d] wt [%d]", maxRowIdx+row_base, maxRowValue))
end local maxRowIdx, maxRowValue = arrayMax(row_votes)
local maxColIdx, maxColValue = arrayMax(col_votes)
if maxRowValue == 0 and maxColValue == 0 then
local now = box:get_current_time() box:log("Warning", string.format("Classifier predicted 'no p300' for all flashes of the trial"));
end
box:send_stimulation(1, maxRowIdx + row_base, now, 0)
if do_debug then
segment_status = 0 local rowVotes = 0
end local colVotes = 0
for ir, val in pairs(row_votes) do
box:sleep() rowVotes = rowVotes + val
end end
end for ir, val in pairs(col_votes) do
colVotes = colVotes + val
end
box:log("Info", string.format("Vote [%d %d] wt [%d,%d]", maxRowIdx+row_base, maxColIdx+col_base, maxRowValue, maxColValue))
box:log("Info", string.format(" Total [%d %d]", rowVotes, colVotes))
end
local now = box:get_current_time()
box:send_stimulation(1, maxRowIdx + row_base, now, 0)
-- box:send_stimulation(2, maxColIdx + col_base, now, 0)
segment_status = 0
end
box:sleep()
end
end