Browse Source

调整判决步长与buffer匹配(目前为0.5s,以减少抖动)

dk 1 year ago
parent
commit
912bb3e0d1
3 changed files with 22 additions and 13 deletions
  1. 2 2
      backend/free_grasp.psyexp
  2. 6 9
      backend/free_grasp.py
  3. 14 2
      backend/online_sim.py

+ 2 - 2
backend/free_grasp.psyexp

@@ -95,7 +95,7 @@
         <Param val="" valType="extendedCode" updates="constant" name="Begin Experiment"/>
         <Param val="" valType="extendedCode" updates="constant" name="Begin JS Experiment"/>
         <Param val="" valType="extendedCode" updates="constant" name="Begin JS Routine"/>
-        <Param val="# state changed&amp;#10;feedback_bar1.progress = force&amp;#10;if decision != -1:&amp;#10;    feedback_time = 5&amp;#10;    if not decision:&amp;#10;        trigger.send_trigger(0)&amp;#10;        hand_device.extend()&amp;#10;    else:&amp;#10;        trigger.send_trigger(int(decision))&amp;#10;        hand_device.start(model=fingermodel_ids_inverse[decision])&amp;#10;else:&amp;#10;    feedback_time = 0&amp;#10;    " valType="extendedCode" updates="constant" name="Begin Routine"/>
+        <Param val="# state changed&amp;#10;feedback_bar1.progress = force&amp;#10;if decision != -1:&amp;#10;    feedback_time = 3&amp;#10;    if not decision:&amp;#10;        trigger.send_trigger(0)&amp;#10;        hand_device.extend()&amp;#10;    else:&amp;#10;        trigger.send_trigger(int(decision))&amp;#10;        hand_device.start(model=fingermodel_ids_inverse[decision])&amp;#10;else:&amp;#10;    feedback_time = 0&amp;#10;    " valType="extendedCode" updates="constant" name="Begin Routine"/>
         <Param val="Py" valType="str" updates="None" name="Code Type"/>
         <Param val="" valType="extendedCode" updates="constant" name="Each Frame"/>
         <Param val="" valType="extendedCode" updates="constant" name="Each JS Frame"/>
@@ -169,7 +169,7 @@
         <Param val="time (s)" valType="str" updates="None" name="startType"/>
         <Param val="0" valType="code" updates="None" name="startVal"/>
         <Param val="duration (s)" valType="str" updates="None" name="stopType"/>
-        <Param val="0.1" valType="code" updates="constant" name="stopVal"/>
+        <Param val="config_info['buffer_length']" valType="code" updates="constant" name="stopVal"/>
         <Param val="True" valType="bool" updates="None" name="syncScreenRefresh"/>
         <Param val="height" valType="str" updates="None" name="units"/>
       </ProgressComponent>

+ 6 - 9
backend/free_grasp.py

@@ -2,7 +2,7 @@
 # -*- coding: utf-8 -*-
 """
 This experiment was created using PsychoPy3 Experiment Builder (v2023.2.3),
-    on Tue Nov 28 19:17:09 2023
+    on Wed Dec  6 17:54:49 2023
 If you publish work using this script the most relevant publication is:
 
     Peirce J, Gray JR, Simpson S, MacAskill M, Höchenberger R, Sogo H, Kastman E, Lindeløv JK. (2019) 
@@ -600,7 +600,7 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
         
         # --- Run Routine "decision" ---
         routineForceEnded = not continueRoutine
-        while continueRoutine and routineTimer.getTime() < 0.1:
+        while continueRoutine:
             # get current time
             t = routineTimer.getTime()
             tThisFlip = win.getFutureFlipTime(clock=routineTimer)
@@ -631,7 +631,7 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
             # if feedback_bar is stopping this frame...
             if feedback_bar.status == STARTED:
                 # is it time to stop? (based on global clock, using actual start)
-                if tThisFlipGlobal > feedback_bar.tStartRefresh + 0.1-frameTolerance:
+                if tThisFlipGlobal > feedback_bar.tStartRefresh + config_info['buffer_length']-frameTolerance:
                     # keep track of stop time/frame for later
                     feedback_bar.tStop = t  # not accounting for scr refresh
                     feedback_bar.frameNStop = frameN  # exact frame index
@@ -667,11 +667,8 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
             if hasattr(thisComponent, "setAutoDraw"):
                 thisComponent.setAutoDraw(False)
         thisExp.addData('decision.stopped', globalClock.getTime())
-        # using non-slip timing so subtract the expected duration of this Routine (unless ended on request)
-        if routineForceEnded:
-            routineTimer.reset()
-        else:
-            routineTimer.addTime(-0.100000)
+        # the Routine "decision" was not non-slip safe, so reset the non-slip timer
+        routineTimer.reset()
         
         # --- Prepare to start Routine "feedback" ---
         continueRoutine = True
@@ -681,7 +678,7 @@ def run(expInfo, thisExp, win, inputs, globalClock=None, thisSession=None):
         # state changed
         feedback_bar1.progress = force
         if decision != -1:
-            feedback_time = 5
+            feedback_time = 3
             if not decision:
                 trigger.send_trigger(0)
                 hand_device.extend()

+ 14 - 2
backend/online_sim.py

@@ -42,6 +42,14 @@ def parse_args():
         type=float
     )
     parser.add_argument(
+        '--state-trans-prob',
+        '-stp',
+        dest='state_trans_prob',
+        help='Transition probability for HMM state change',
+        default=0.8,
+        type=float
+    )
+    parser.add_argument(
         '--model-filename',
         dest='model_filename',
         help='Model filename',
@@ -79,7 +87,7 @@ def _evaluation_loop(raw, events, model_hmm, step_length, event_trial_length):
     decision_with_hmm = []
     decision_without_hmm = []
     probs = []
-    for time, data in data_gen.loop():
+    for time, data in data_gen.loop(step_length):
         step_p, cls = model_hmm.viterbi(data, return_step_p=True)
         if cls >=0:
             cls = model_hmm.model.classes_[cls]
@@ -117,6 +125,7 @@ def _evaluation_loop(raw, events, model_hmm, step_length, event_trial_length):
 
 
 def simulation(raw_val, event_id, model, 
+               state_trans_prob=0.8,
                state_change_threshold=0.8, 
                step_length=1., 
                event_trial_length=5.):
@@ -144,7 +153,9 @@ def simulation(raw_val, event_id, model,
                                         use_original_label=True)
     
     
-    controller = online.Controller(0, model, state_change_threshold=state_change_threshold)
+    controller = online.Controller(0, model, 
+                                   state_trans_prob=state_trans_prob,
+                                   state_change_threshold=state_change_threshold)
     model_hmm = controller.real_feedback_model
 
     # run with and without hmm
@@ -203,6 +214,7 @@ if __name__ == '__main__':
     metric_hmm, metric_naive, fig_pred = simulation(raw, 
                                              event_id, 
                                              model=model_path, 
+                                             state_trans_prob=args.state_trans_prob,
                                              state_change_threshold=args.state_change_threshold,
                                              step_length=config_info['buffer_length'],
                                              event_trial_length=trial_time)