fast-feedback virtual target task code on STM Nucleo

Dependencies:   mbed

Committer:
gwappa
Date:
Sun Jul 22 16:25:25 2018 +0000
Revision:
28:797536a42b9f
Parent:
27:b31ea8d74f9e
Child:
29:1fb060aab1f8
change Pair mode to Condition mode; add scheduler

Who changed what in which revision?

UserRevisionLine numberNew contents of line
gwappa 2:0c241937eabd 1 #include "trial.h"
gwappa 11:897ecd5413e0 2 #include "rig.h"
gwappa 2:0c241937eabd 3 #include "IO.h"
gwappa 2:0c241937eabd 4 #include "random.h"
gwappa 2:0c241937eabd 5
gwappa 11:897ecd5413e0 6 const uint64_t MicrosecondsInSecond = 1000000;
gwappa 11:897ecd5413e0 7
gwappa 20:4c06d3041337 8 inline uint64_t calc_blink_duration(const uint16_t& freq) {
gwappa 20:4c06d3041337 9 return (freq == 0)? 0 : (MicrosecondsInSecond/(freq * 2));
gwappa 20:4c06d3041337 10 }
gwappa 20:4c06d3041337 11
gwappa 20:4c06d3041337 12 void TrialFlag::clear() {
gwappa 19:50663f8815b8 13 cued = false;
gwappa 19:50663f8815b8 14 responded = false;
gwappa 19:50663f8815b8 15 reset = false;
gwappa 19:50663f8815b8 16 }
gwappa 19:50663f8815b8 17
gwappa 20:4c06d3041337 18 void TrialFlag::writeToSerial() {
gwappa 19:50663f8815b8 19 if (reset) {
gwappa 19:50663f8815b8 20 IO::write("reset");
gwappa 19:50663f8815b8 21 } else if (cued) {
gwappa 19:50663f8815b8 22 IO::write(responded? "hit":"miss");
gwappa 19:50663f8815b8 23 } else {
gwappa 19:50663f8815b8 24 IO::write(responded? "catch":"reject");
gwappa 19:50663f8815b8 25 }
gwappa 19:50663f8815b8 26 }
gwappa 19:50663f8815b8 27
gwappa 2:0c241937eabd 28 void Trial::reset(const Task& task){
gwappa 2:0c241937eabd 29 // reset score
gwappa 20:4c06d3041337 30 flag.clear();
gwappa 2:0c241937eabd 31
gwappa 2:0c241937eabd 32 // set delay duration
gwappa 5:849446d19406 33 delay_dur_ms = task.delay_min_ms.value
gwappa 5:849446d19406 34 + random::exponential(task.delay_var_ms.value, task.delay_var_ms.value*3);
gwappa 11:897ecd5413e0 35
gwappa 24:e236faf66935 36 // reset cues
gwappa 20:4c06d3041337 37 audioOut.setEnabled(false);
gwappa 15:20f7f737c256 38 visualOut.setEnabled(false);
gwappa 16:33c17c62840e 39 vis_dur_us = 0;
gwappa 16:33c17c62840e 40 vis_onset_us = 0;
gwappa 15:20f7f737c256 41
gwappa 24:e236faf66935 42 // configure reward
gwappa 24:e236faf66935 43 rewardOut.setOnset(0);
gwappa 24:e236faf66935 44 rewardOut.setDuration(ms_to_us(task.reward_dur_ms.value));
gwappa 24:e236faf66935 45
gwappa 24:e236faf66935 46 // configure cued state duration + visual stimulus position (if any)
gwappa 15:20f7f737c256 47 switch (task.mode.value) {
gwappa 28:797536a42b9f 48 case Condition:
gwappa 28:797536a42b9f 49 visualOut.setBlinkDuration( calc_blink_duration(task.vis_blink_hz.value) );
gwappa 28:797536a42b9f 50 assignCues(task, true, false);
gwappa 28:797536a42b9f 51 break;
gwappa 15:20f7f737c256 52 case Report:
gwappa 15:20f7f737c256 53 case Associate:
gwappa 24:e236faf66935 54 visualOut.setBlinkDuration( calc_blink_duration(task.vis_blink_hz.value) );
gwappa 24:e236faf66935 55 assignCues(task, true);
gwappa 24:e236faf66935 56 break;
gwappa 16:33c17c62840e 57 case Motion:
gwappa 16:33c17c62840e 58 case MotionAlt:
gwappa 24:e236faf66935 59 assignCues(task, false);
gwappa 24:e236faf66935 60 break;
gwappa 24:e236faf66935 61 }
gwappa 24:e236faf66935 62
gwappa 24:e236faf66935 63 // assign Auditory cues (if any)
gwappa 24:e236faf66935 64 switch (task.mode.value) {
gwappa 28:797536a42b9f 65 case Condition:
gwappa 24:e236faf66935 66 case Report:
gwappa 24:e236faf66935 67 break;
gwappa 24:e236faf66935 68 case Associate:
gwappa 24:e236faf66935 69 case Motion:
gwappa 24:e236faf66935 70 case MotionAlt:
gwappa 24:e236faf66935 71 audioOut.setEnabled(true);
gwappa 24:e236faf66935 72 audioOut.setOnset(0);
gwappa 24:e236faf66935 73 audioOut.setDuration(cued_dur_us);
gwappa 24:e236faf66935 74 audioOut.setBlinkDuration( calc_blink_duration(task.aud_tick_hz.value) );
gwappa 15:20f7f737c256 75 break;
gwappa 13:8ea85a33e37a 76 }
gwappa 2:0c241937eabd 77
gwappa 3:991c6d5ce19d 78 // reset interrupt events
gwappa 26:b4421d1ee57a 79 lickIn.reset(task.lick_debounce_ms.value, true);
gwappa 26:b4421d1ee57a 80 whiskIn.reset(task.whisk_debounce_ms.value, true);
gwappa 26:b4421d1ee57a 81 gateIn.reset(-1, true);
gwappa 2:0c241937eabd 82 }
gwappa 2:0c241937eabd 83
gwappa 28:797536a42b9f 84 #include "IO.h"
gwappa 28:797536a42b9f 85
gwappa 28:797536a42b9f 86 void Trial::assignCues(const Task& task, const bool& assignVisual, const bool& canfail)
gwappa 13:8ea85a33e37a 87 {
gwappa 24:e236faf66935 88 if (!assignVisual) {
gwappa 24:e236faf66935 89 visualOut.setEnabled(false);
gwappa 27:b31ea8d74f9e 90 visualOut.direct(true);
gwappa 24:e236faf66935 91 vis_dur_us = 0;
gwappa 24:e236faf66935 92 vis_onset_us = 0;
gwappa 24:e236faf66935 93
gwappa 24:e236faf66935 94 cued_dur_us = ms_to_us(task.aud_dur_ms.value);
gwappa 24:e236faf66935 95 return;
gwappa 24:e236faf66935 96 }
gwappa 24:e236faf66935 97
gwappa 28:797536a42b9f 98 const bool _canfail = canfail && (task.vis_fail_perc.value > 0);
gwappa 28:797536a42b9f 99
gwappa 13:8ea85a33e37a 100 const uint32_t phasedur_us = ms_to_us(task.aud_dur_ms.value);
gwappa 15:20f7f737c256 101 const uint32_t minonset_us = ms_to_us(task.pre_min_ms.value);
gwappa 13:8ea85a33e37a 102 const uint32_t respdur_us = ms_to_us(task.resp_dur_ms.value);
gwappa 14:af3adf5d5ddf 103 const uint32_t avgdur_us = ms_to_us(task.vis_avg_ms.value);
gwappa 13:8ea85a33e37a 104 const uint32_t mindur_us = ms_to_us(task.vis_min_ms.value);
gwappa 28:797536a42b9f 105 const double failure_perc = _canfail? ((double)(task.vis_fail_perc.value)):1e-6;
gwappa 13:8ea85a33e37a 106
gwappa 20:4c06d3041337 107 const double onset_vrng = (double)(phasedur_us - minonset_us - respdur_us - mindur_us);
gwappa 20:4c06d3041337 108 const double logdecay = ::log(100.0) - ::log(failure_perc);
gwappa 20:4c06d3041337 109 const double ftau = onset_vrng/logdecay;
gwappa 14:af3adf5d5ddf 110 const uint32_t tau = (uint32_t)(ftau + 0.5);
gwappa 20:4c06d3041337 111 const uint32_t onset_us = random::exponential(tau, onset_vrng+10) + minonset_us;
gwappa 20:4c06d3041337 112 const uint32_t maxonset_us = onset_vrng + minonset_us;
gwappa 13:8ea85a33e37a 113
gwappa 20:4c06d3041337 114 if ((onset_us > 0) && (onset_us < maxonset_us)) {
gwappa 13:8ea85a33e37a 115 // generate duration
gwappa 20:4c06d3041337 116 const uint32_t dur_vrng = maxonset_us - onset_us;
gwappa 20:4c06d3041337 117 const uint32_t dur_us = random::exponential(avgdur_us - mindur_us, dur_vrng) + mindur_us;
gwappa 13:8ea85a33e37a 118
gwappa 15:20f7f737c256 119 visualOut.setEnabled(true);
gwappa 17:0b241aa1f5b6 120 visualOut.setDuration(dur_us);
gwappa 17:0b241aa1f5b6 121 visualOut.setOnset(onset_us);
gwappa 13:8ea85a33e37a 122
gwappa 17:0b241aa1f5b6 123 vis_dur_us = dur_us;
gwappa 17:0b241aa1f5b6 124 vis_onset_us = onset_us;
gwappa 24:e236faf66935 125
gwappa 24:e236faf66935 126 cued_dur_us = onset_us + dur_us + respdur_us;
gwappa 24:e236faf66935 127
gwappa 13:8ea85a33e37a 128 } else {
gwappa 15:20f7f737c256 129 // no pulse
gwappa 15:20f7f737c256 130 visualOut.setEnabled(false);
gwappa 16:33c17c62840e 131 vis_dur_us = 0;
gwappa 16:33c17c62840e 132 vis_onset_us = 0;
gwappa 24:e236faf66935 133
gwappa 24:e236faf66935 134 cued_dur_us = phasedur_us;
gwappa 13:8ea85a33e37a 135 }
gwappa 13:8ea85a33e37a 136 }
gwappa 13:8ea85a33e37a 137
gwappa 11:897ecd5413e0 138 void Trial::markTrialStart() {
gwappa 26:b4421d1ee57a 139 starting = TrialTimer.read_ms();
gwappa 12:06ea96546af1 140 trialStart.run();
gwappa 26:b4421d1ee57a 141 TrialTimer.start();
gwappa 11:897ecd5413e0 142 }
gwappa 11:897ecd5413e0 143
gwappa 11:897ecd5413e0 144 void Trial::markEndOfWait() {
gwappa 26:b4421d1ee57a 145 cuestarting = TrialTimer.read_ms();
gwappa 11:897ecd5413e0 146 waiting = cuestarting - starting;
gwappa 11:897ecd5413e0 147 }
gwappa 11:897ecd5413e0 148
gwappa 11:897ecd5413e0 149 void Trial::markTrialEnd() {
gwappa 12:06ea96546af1 150 trialEnd.run();
gwappa 11:897ecd5413e0 151 trialEnd.wait();
gwappa 11:897ecd5413e0 152 writeToSerial();
gwappa 26:b4421d1ee57a 153 TrialTimer.stop();
gwappa 26:b4421d1ee57a 154 TrialTimer.reset();
gwappa 27:b31ea8d74f9e 155 visualOut.direct(false); // if any
gwappa 11:897ecd5413e0 156 }
gwappa 11:897ecd5413e0 157
gwappa 2:0c241937eabd 158 void Trial::writeToSerial() {
gwappa 19:50663f8815b8 159 IO::write("%c",IO::RESULT_HEADER);
gwappa 19:50663f8815b8 160 flag.writeToSerial();
gwappa 2:0c241937eabd 161
gwappa 19:50663f8815b8 162 IO::write(";wait%u", waiting);
gwappa 13:8ea85a33e37a 163
gwappa 20:4c06d3041337 164 if (visualOut.isEnabled() && (!flag.reset)) {
gwappa 23:61af0317e404 165 IO::write(";visual(onset%s,duration%s)",
gwappa 23:61af0317e404 166 uint64_to_str(vis_onset_us).c_str(),
gwappa 23:61af0317e404 167 uint64_to_str(vis_dur_us).c_str());
gwappa 13:8ea85a33e37a 168 }
gwappa 13:8ea85a33e37a 169
gwappa 19:50663f8815b8 170 trialtime_t zero = (flag.reset)? starting : cuestarting;
gwappa 3:991c6d5ce19d 171 IO::write(";whisk");
gwappa 26:b4421d1ee57a 172 whiskIn.writeToSerial(zero);
gwappa 26:b4421d1ee57a 173 IO::write(";gate");
gwappa 26:b4421d1ee57a 174 gateIn.writeToSerial(zero);
gwappa 3:991c6d5ce19d 175 IO::write(";lick");
gwappa 26:b4421d1ee57a 176 lickIn.writeToSerial(zero);
gwappa 4:fcf597f82632 177 IO::write(";\r\n");
gwappa 2:0c241937eabd 178 }