Keisuke Sehara
/
STM32_Whisking
fast-feedback virtual target task code on STM Nucleo
trial.cpp
- Committer:
- gwappa
- Date:
- 2018-07-03
- Revision:
- 23:61af0317e404
- Parent:
- 22:41163fb3fdc6
- Child:
- 24:e236faf66935
File content as of revision 23:61af0317e404:
#include "trial.h" #include "rig.h" #include "IO.h" #include "random.h" #include "events.h" const uint64_t MicrosecondsInSecond = 1000000; inline uint64_t calc_blink_duration(const uint16_t& freq) { return (freq == 0)? 0 : (MicrosecondsInSecond/(freq * 2)); } void TrialFlag::clear() { cued = false; responded = false; reset = false; } void TrialFlag::writeToSerial() { if (reset) { IO::write("reset"); } else if (cued) { IO::write(responded? "hit":"miss"); } else { IO::write(responded? "catch":"reject"); } } void Trial::reset(const Task& task){ // reset score flag.clear(); // set delay duration delay_dur_ms = task.delay_min_ms.value + random::exponential(task.delay_var_ms.value, task.delay_var_ms.value*3); // generate stimuli audioOut.setEnabled(false); visualOut.setEnabled(false); vis_dur_us = 0; vis_onset_us = 0; switch (task.mode.value) { case Pair: visualOut.setBlinkDuration( calc_blink_duration(task.vis_blink_hz.value) ); assignRandomStim(task); rewardOut.setDuration(ms_to_us(task.reward_dur_ms.value)); break; case Report: case Associate: assignRandomStim(task); // fallthrough case Motion: case MotionAlt: rewardOut.setOnset(0); rewardOut.setDuration(ms_to_us(task.reward_dur_ms.value)); if (task.mode.value != Report) { audioOut.setEnabled(true); audioOut.setOnset(0); audioOut.setDuration(ms_to_us(task.aud_dur_ms.value)); audioOut.setBlinkDuration( calc_blink_duration(task.aud_tick_hz.value) ); } break; } // reset interrupt events licking_events.clear(); whisking_events.clear(); } void Trial::assignRandomStim(const Task& task) { const uint32_t phasedur_us = ms_to_us(task.aud_dur_ms.value); const uint32_t minonset_us = ms_to_us(task.pre_min_ms.value); const uint32_t respdur_us = ms_to_us(task.resp_dur_ms.value); const uint32_t avgdur_us = ms_to_us(task.vis_avg_ms.value); const uint32_t mindur_us = ms_to_us(task.vis_min_ms.value); const double failure_perc = (task.vis_fail_perc.value > 0)? ((double)(task.vis_fail_perc.value)):1e-6; const double onset_vrng = (double)(phasedur_us - minonset_us - respdur_us - mindur_us); const double logdecay = ::log(100.0) - ::log(failure_perc); const double ftau = onset_vrng/logdecay; const uint32_t tau = (uint32_t)(ftau + 0.5); const uint32_t onset_us = random::exponential(tau, onset_vrng+10) + minonset_us; const uint32_t maxonset_us = onset_vrng + minonset_us; if ((onset_us > 0) && (onset_us < maxonset_us)) { // generate duration const uint32_t dur_vrng = maxonset_us - onset_us; const uint32_t dur_us = random::exponential(avgdur_us - mindur_us, dur_vrng) + mindur_us; visualOut.setEnabled(true); visualOut.setDuration(dur_us); visualOut.setOnset(onset_us); vis_dur_us = dur_us; vis_onset_us = onset_us; } else { // no pulse visualOut.setEnabled(false); vis_dur_us = 0; vis_onset_us = 0; } } void Trial::markTrialStart() { starting = timer.read_ms(); trialStart.run(); timer.start(); } void Trial::markEndOfWait() { cuestarting = timer.read_ms(); waiting = cuestarting - starting; } void Trial::markTrialEnd() { trialEnd.run(); trialEnd.wait(); writeToSerial(); timer.stop(); timer.reset(); } void Trial::writeToSerial() { IO::write("%c",IO::RESULT_HEADER); flag.writeToSerial(); IO::write(";wait%u", waiting); if (visualOut.isEnabled() && (!flag.reset)) { IO::write(";visual(onset%s,duration%s)", uint64_to_str(vis_onset_us).c_str(), uint64_to_str(vis_dur_us).c_str()); } trialtime_t zero = (flag.reset)? starting : cuestarting; IO::write(";whisk"); whisking_events.writeToSerial(zero); IO::write(";lick"); licking_events.writeToSerial(zero); IO::write(";\r\n"); }