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