fast-feedback virtual target task code on STM Nucleo

Dependencies:   mbed

Committer:
gwappa
Date:
Mon Jul 02 09:04:45 2018 +0000
Revision:
20:4c06d3041337
Parent:
19:50663f8815b8
Child:
22:41163fb3fdc6
try extending Pulse to allow tickering output

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 14:af3adf5d5ddf 5 #include "events.h"
gwappa 2:0c241937eabd 6
gwappa 11:897ecd5413e0 7 const uint64_t MicrosecondsInSecond = 1000000;
gwappa 11:897ecd5413e0 8
gwappa 20:4c06d3041337 9 inline uint64_t calc_blink_duration(const uint16_t& freq) {
gwappa 20:4c06d3041337 10 return (freq == 0)? 0 : (MicrosecondsInSecond/(freq * 2));
gwappa 20:4c06d3041337 11 }
gwappa 20:4c06d3041337 12
gwappa 20:4c06d3041337 13 void TrialFlag::clear() {
gwappa 19:50663f8815b8 14 cued = false;
gwappa 19:50663f8815b8 15 responded = false;
gwappa 19:50663f8815b8 16 reset = false;
gwappa 19:50663f8815b8 17 }
gwappa 19:50663f8815b8 18
gwappa 20:4c06d3041337 19 void TrialFlag::writeToSerial() {
gwappa 19:50663f8815b8 20 if (reset) {
gwappa 19:50663f8815b8 21 IO::write("reset");
gwappa 19:50663f8815b8 22 } else if (cued) {
gwappa 19:50663f8815b8 23 IO::write(responded? "hit":"miss");
gwappa 19:50663f8815b8 24 } else {
gwappa 19:50663f8815b8 25 IO::write(responded? "catch":"reject");
gwappa 19:50663f8815b8 26 }
gwappa 19:50663f8815b8 27 }
gwappa 19:50663f8815b8 28
gwappa 2:0c241937eabd 29 void Trial::reset(const Task& task){
gwappa 2:0c241937eabd 30 // reset score
gwappa 20:4c06d3041337 31 flag.clear();
gwappa 2:0c241937eabd 32
gwappa 2:0c241937eabd 33 // set delay duration
gwappa 5:849446d19406 34 delay_dur_ms = task.delay_min_ms.value
gwappa 5:849446d19406 35 + random::exponential(task.delay_var_ms.value, task.delay_var_ms.value*3);
gwappa 11:897ecd5413e0 36
gwappa 20:4c06d3041337 37 // generate stimuli
gwappa 20:4c06d3041337 38 audioOut.setEnabled(false);
gwappa 15:20f7f737c256 39 visualOut.setEnabled(false);
gwappa 16:33c17c62840e 40 vis_dur_us = 0;
gwappa 16:33c17c62840e 41 vis_onset_us = 0;
gwappa 15:20f7f737c256 42
gwappa 15:20f7f737c256 43 switch (task.mode.value) {
gwappa 15:20f7f737c256 44 case Pair:
gwappa 20:4c06d3041337 45 visualOut.setBlinkDuration( calc_blink_duration(task.vis_blink_hz.value) );
gwappa 20:4c06d3041337 46 assignRandomStim(task);
gwappa 16:33c17c62840e 47 rewardOut.setDuration(ms_to_us(task.reward_dur_ms.value));
gwappa 15:20f7f737c256 48 break;
gwappa 15:20f7f737c256 49 case Report:
gwappa 15:20f7f737c256 50 case Associate:
gwappa 16:33c17c62840e 51 assignRandomStim(task);
gwappa 16:33c17c62840e 52 // fallthrough
gwappa 16:33c17c62840e 53 case Motion:
gwappa 16:33c17c62840e 54 case MotionAlt:
gwappa 16:33c17c62840e 55 rewardOut.setOnset(0);
gwappa 16:33c17c62840e 56 rewardOut.setDuration(ms_to_us(task.reward_dur_ms.value));
gwappa 20:4c06d3041337 57 if (task.mode.value != Report) {
gwappa 20:4c06d3041337 58 audioOut.setEnabled(true);
gwappa 20:4c06d3041337 59 audioOut.setOnset(0);
gwappa 20:4c06d3041337 60 audioOut.setDuration(ms_to_us(task.aud_dur_ms.value));
gwappa 20:4c06d3041337 61 audioOut.setBlinkDuration( calc_blink_duration(task.aud_tick_hz.value) );
gwappa 20:4c06d3041337 62 }
gwappa 15:20f7f737c256 63 break;
gwappa 13:8ea85a33e37a 64 }
gwappa 2:0c241937eabd 65
gwappa 3:991c6d5ce19d 66 // reset interrupt events
gwappa 3:991c6d5ce19d 67 licking_events.clear();
gwappa 3:991c6d5ce19d 68 whisking_events.clear();
gwappa 2:0c241937eabd 69 }
gwappa 2:0c241937eabd 70
gwappa 13:8ea85a33e37a 71 void Trial::assignRandomStim(const Task& task)
gwappa 13:8ea85a33e37a 72 {
gwappa 13:8ea85a33e37a 73 const uint32_t phasedur_us = ms_to_us(task.aud_dur_ms.value);
gwappa 15:20f7f737c256 74 const uint32_t minonset_us = ms_to_us(task.pre_min_ms.value);
gwappa 13:8ea85a33e37a 75 const uint32_t respdur_us = ms_to_us(task.resp_dur_ms.value);
gwappa 14:af3adf5d5ddf 76 const uint32_t avgdur_us = ms_to_us(task.vis_avg_ms.value);
gwappa 13:8ea85a33e37a 77 const uint32_t mindur_us = ms_to_us(task.vis_min_ms.value);
gwappa 15:20f7f737c256 78 const double failure_perc = (task.vis_fail_perc.value > 0)? ((double)(task.vis_fail_perc.value)):1e-6;
gwappa 13:8ea85a33e37a 79
gwappa 20:4c06d3041337 80 const double onset_vrng = (double)(phasedur_us - minonset_us - respdur_us - mindur_us);
gwappa 20:4c06d3041337 81 const double logdecay = ::log(100.0) - ::log(failure_perc);
gwappa 20:4c06d3041337 82 const double ftau = onset_vrng/logdecay;
gwappa 14:af3adf5d5ddf 83 const uint32_t tau = (uint32_t)(ftau + 0.5);
gwappa 20:4c06d3041337 84 const uint32_t onset_us = random::exponential(tau, onset_vrng+10) + minonset_us;
gwappa 20:4c06d3041337 85 const uint32_t maxonset_us = onset_vrng + minonset_us;
gwappa 13:8ea85a33e37a 86
gwappa 20:4c06d3041337 87 if ((onset_us > 0) && (onset_us < maxonset_us)) {
gwappa 13:8ea85a33e37a 88 // generate duration
gwappa 20:4c06d3041337 89 const uint32_t dur_vrng = maxonset_us - onset_us;
gwappa 20:4c06d3041337 90 const uint32_t dur_us = random::exponential(avgdur_us - mindur_us, dur_vrng) + mindur_us;
gwappa 13:8ea85a33e37a 91
gwappa 15:20f7f737c256 92 visualOut.setEnabled(true);
gwappa 17:0b241aa1f5b6 93 visualOut.setDuration(dur_us);
gwappa 17:0b241aa1f5b6 94 visualOut.setOnset(onset_us);
gwappa 13:8ea85a33e37a 95
gwappa 17:0b241aa1f5b6 96 vis_dur_us = dur_us;
gwappa 17:0b241aa1f5b6 97 vis_onset_us = onset_us;
gwappa 20:4c06d3041337 98 IO::debug("visual(onset=%u,dur=%u)",vis_onset_us,vis_dur_us);
gwappa 13:8ea85a33e37a 99 } else {
gwappa 15:20f7f737c256 100 // no pulse
gwappa 15:20f7f737c256 101 visualOut.setEnabled(false);
gwappa 16:33c17c62840e 102 vis_dur_us = 0;
gwappa 16:33c17c62840e 103 vis_onset_us = 0;
gwappa 20:4c06d3041337 104 IO::debug("visual(disabled)");
gwappa 13:8ea85a33e37a 105 }
gwappa 13:8ea85a33e37a 106 }
gwappa 13:8ea85a33e37a 107
gwappa 11:897ecd5413e0 108 void Trial::markTrialStart() {
gwappa 11:897ecd5413e0 109 starting = timer.read_ms();
gwappa 12:06ea96546af1 110 trialStart.run();
gwappa 11:897ecd5413e0 111 timer.start();
gwappa 11:897ecd5413e0 112 }
gwappa 11:897ecd5413e0 113
gwappa 11:897ecd5413e0 114 void Trial::markEndOfWait() {
gwappa 11:897ecd5413e0 115 cuestarting = timer.read_ms();
gwappa 11:897ecd5413e0 116 waiting = cuestarting - starting;
gwappa 11:897ecd5413e0 117 }
gwappa 11:897ecd5413e0 118
gwappa 11:897ecd5413e0 119 void Trial::markTrialEnd() {
gwappa 12:06ea96546af1 120 trialEnd.run();
gwappa 11:897ecd5413e0 121 trialEnd.wait();
gwappa 11:897ecd5413e0 122 writeToSerial();
gwappa 11:897ecd5413e0 123 timer.stop();
gwappa 11:897ecd5413e0 124 timer.reset();
gwappa 11:897ecd5413e0 125 }
gwappa 11:897ecd5413e0 126
gwappa 2:0c241937eabd 127 void Trial::writeToSerial() {
gwappa 19:50663f8815b8 128 IO::write("%c",IO::RESULT_HEADER);
gwappa 19:50663f8815b8 129 flag.writeToSerial();
gwappa 2:0c241937eabd 130
gwappa 19:50663f8815b8 131 IO::write(";wait%u", waiting);
gwappa 13:8ea85a33e37a 132
gwappa 20:4c06d3041337 133 if (visualOut.isEnabled() && (!flag.reset)) {
gwappa 16:33c17c62840e 134 IO::write(";visual(onset%u,duration%u)",vis_onset_us,vis_dur_us);
gwappa 13:8ea85a33e37a 135 }
gwappa 13:8ea85a33e37a 136
gwappa 19:50663f8815b8 137 trialtime_t zero = (flag.reset)? starting : cuestarting;
gwappa 3:991c6d5ce19d 138 IO::write(";whisk");
gwappa 3:991c6d5ce19d 139 whisking_events.writeToSerial(zero);
gwappa 3:991c6d5ce19d 140 IO::write(";lick");
gwappa 3:991c6d5ce19d 141 licking_events.writeToSerial(zero);
gwappa 4:fcf597f82632 142 IO::write(";\r\n");
gwappa 2:0c241937eabd 143 }