'this script removes stimulus artifacts from data channels. it starts from offset seconds after the trigger times ' and removes points% number of points, and replaces them with a straight line so it all lines up WindowVisible(3); var dataChan%; var trigChan%; var offset:=0; var points%:=4; var ret%; var time; 'var origin[85]; var bin; var v1%, v2%; v2%:=View(); var r,rr; var negate:=-1; var dcremovChannel,DCremtime; DCremtime:=0.01; var trigmem%:=-1; var evint:=0.008; var test1,test2; ToolbarClear(); ToolbarSet(1, "trigger", trigger%); ToolbarSet(2, "Stop", stop%); ToolbarSet(3, "artifact", artifact%); repeat Toolbar("",1023); until 0; Halt; func stop%() halt; end; func artifact%() 'PrintLog(View(v1%).[], " ", v2%); 'XRange(0,Maxtime()); 'Optimise(-1); FrontView(v2%); DlgCreate("Artifact removal"); DlgChan(1,"Select waveform data channel",1); DlgChan(2,"Select trigger channel",2+4+8); 'DlgReal(3,"Enter time (in sec) before trigger to start removing artifact", -1000, 1000); 'DlgInteger(4,"Enter number of points to remove",1,1000000); CursorDelete(-1); CursorNew(XLow()+1); 'macht neuen Cursor an Stelle links im Fenster + 1 sec CursorNew(Xhigh()-1); Interact("set Cursors for region to average ",1023); r:=Cursor(1); rr:=Cursor(2); ret%:=DlgShow(dataChan%, trigChan%); if ret%>0 then AVERAGE(); else return; endif; if ret%>0 then FrontView(v2%); DelArt%(dataChan%,trigChan%,0,Maxtime(),offset,points%); endif; end; func DelArt%(dataCh%, trigCh%, locSTime, locETime, offset, points%) var mem%; var arr[points%]; var list%[33]; var title$,newtitle$; var yesno$; bin:=Binsize(dataCh%); title$:=ChanTitle$(dataCh%); newtitle$:=title$+"_KILL"; mem%:=MemChan(0,dataCh%); Memimport(mem%,dataCh%,0,maxtime()); 'copy old channel to memchan ChanScale(mem%,ChanScale(dataCh%)); ChanTitle$(mem%, newtitle$); repeat time:=NextTime(trigCh%, time); 'PrintLog(time); if time>0 and timelocETime; ChanList(list%[], 128); if list%[0]>0 then yesno$:=input$("Would you like to copy filtered datums to a permanent channel (y/n)","n",1,"y-n"); if yesno$="y" then MemSave(mem%, list%[1]); ChanDelete(mem%); ChanShow(list%[1]); optimise(list%[1]); else ChanShow(mem%); optimise(mem%); endif; ChanColour(mem%,1,16); endif; 'draw(test1,test2-test1); draw(); end; func MakeSlope%(arr[], sVal, eVal); 'subtract AVERAGE from Original var len%; var inc; var curs; var k; var value; var origin[points%]; len%:=Len(arr[]); inc:=(eVal-sVal)/len%; ChanData(dataChan%, origin[], time-offset, time-offset+points%*bin); ArrSubR(origin[],View(v1%).[]); ArrConst(arr[],origin[]); ArrMul(arr[],negate); return 1; end; func AVERAGE() var start,keepstart,ok%; bin:=Binsize(dataChan%); 'get BINsize of the waveform channel start:=nexttime(trigChan%,r); 'find the first trigger keepstart:=start; 'just to keep start value ' now define the position of the left Cursor so that it is place immediately to the left of the first artifact if lasttime(trigchan%,r)>0 then 'if there are events before the current event start:=start-(start-lasttime(trigchan%,r))/2; else 'if there is no event before the current event start:=start*0.97; endif; draw(start,(keepstart-start)*2); 'draw window, twice the size of the difference between start and keepstart. Should center event CursorDelete(-1); 'delete all Cursors CursorNew(start+(keepstart-start)*0.5); 'place new cursors CursorNew(keepstart+0.02); Cursorrenumber(); interact("set Cursors to begin and end of the artifact immediately to the right of Cursor1", 1023); offset:=keepstart-Cursor(1); points%:=(Cursor(2)-Cursor(1))/bin; PrintLog(offset, " ", bin, " ", points%); dcremovChannel:=Memchan(0,datachan%); MemImport(dcremovChannel,dataChan%,0,maxtime()); ChanShow(dcremovChannel); ChanProcessAdd(dcremovChannel,2,DCremtime); Optimise(dcremovChannel); ChanColour(dcremovChannel,1,16); Repeat Interact("inspect the DC removed channel and change time value if necessary",1023); DlgCreate("Correct"); DlgButton(0,"keep value"); DlgButton(1,"Change"); DlgReal(1, "Time for DCRemove", 0,1000); ok% := DlgShow(DCremtime); ChanProcessClear(dcremovChannel,-1); ChanProcessAdd(dcremovChannel,2,DCremtime); Optimise(dcremovChannel); until ok%=0; ChanHide(dcremovChannel); 'v1%:=SetAverage(dataChan%,points%,offset,trigChan%,1); v1%:=SetAverage(dcremovChannel,points%,offset,trigChan%,1); Process(r,rr); 'v1% := FileOpen("",4); WindowVisible(1); end; func trigger%() '--------------------------------------- var risefall,ok%; evint:=evint*1000; 'to have minimum interval im ms 'select data channel from which trigger will be get DlgCreate("Set Trigger Channel"); DlgChan(1,"Select waveform data channel",1); Dlgreal(2,"Minimum delay to next triggerpoint in ms?",0,5000); Dlglist(3,"rising or falling waveform?","rising|falling"); ok%:=DlgShow(dataChan%,evint,risefall); if ok%<=0 then return; endif; 'evint:=Input("Minimum delay to next triggerpoint in ms?", evint, 0, 5000); evint:=evint/1000; 'to get it back to sec trigmem%:=MemChan(3,0); 'make trigchannel CursorDelete(-1); 'delete all Cursors CursorNew(XLow()+1); 'make new cursor at left window edge + 1 sec CursorNew(Xhigh()-1); 'make new cursor at right window edge - 1 sec Interact("Place the cursors around the region to be analysed...", 1023); 'select range CursorRenumber(); 'renumbered cursor -> left cursor becomes cursor 1 HCursorDelete(1);HCursorNew(dataChan%); 'make new horizontal cursor Interact("place Hcursor", 1023); var newmem,firstnewmem,pre,post,countit,mini,maxi,minitime,maxitime; 'define a couple of new variable newmem:=MemChan(2); 'make new memchannel 'we will not show this channel. It is just temporary if risefall=0 then MemImport(newmem, dataChan%, Cursor(1), Cursor(2), 2, evint, HCursor(1)); 'write all spike / artifact events to memchannel, rising waveforn else MemImport(newmem, dataChan%, Cursor(1), Cursor(2), 3, evint, HCursor(1)); 'write all spike / artifact events to memchannel, falling waveform endif; test1:=Cursor(1); '2 variable which remember the cursor times test2:=Cursor(2); 'now lets find the maximum/minima of each spike / artifact and make new memory channel firstnewmem:=nexttime(newmem,0); 'find first spike / artifact event CursorNew(); 'make new cursor draw(firstnewmem-0.02,0.04); 'draw window around first event 'place cursors around first spike/artifact Cursor(1,firstnewmem-0.01); Cursor(2,firstnewmem); Cursor(3,firstnewmem+0.01); interact("set Cursor1 to start of spike/artifact Cursor2 to maximum/minimum and Cursor3 to end",1023); 'let user set the beginning, maximum and end of spike/artifact pre:=Cursor(2)-Cursor(1); 'pre has the time between beginning and maximum of spike/artifact post:=Cursor(3)-Cursor(2); 'post has the time between maximum and end of spike/artifact countit:=firstnewmem; ' now walk along the memchannel with the spike events and find maxima While countit>=0 do minmax(dataChan%,countit-pre,countit+post,mini,maxi,minitime,maxitime); 'maxitime hat zeit des maximums if risefall=0 then Memsetitem(trigmem%, 0, maxitime); 'schreib in Memchan, rising waveforn else Memsetitem(trigmem%, 0, minitime); 'schreib in Memchan, falling waveforn endif; countit:=nexttime(newmem,countit); wend; Chandelete(newmem,0); 'delete the temporary memory channel chantitle$(trigmem%,"trigger"); 'give it a name Chanshow(trigmem%); ' and show the trigger channel Draw(test1,test2-test1); 'draw the selected range return; end;