From: Thomas Pietrzak Date: Wed, 15 Jun 2011 21:19:28 +0000 (+0000) Subject: JND exp functionnal X-Git-Url: https://git.thomaspietrzak.com/?a=commitdiff_plain;h=43bfe4466abdd10fe354cca26a465fc3cd54413d;p=tactonexperiment.git JND exp functionnal git-svn-id: svn+ssh://thomaspietrzak.com/var/svn/rep@34 47cf9a05-e0a8-4ed5-9e9b-101a649bc004 --- diff --git a/Tactons Experiment.sln b/Tactons Experiment.sln index 4f417b4..2f5c058 100644 --- a/Tactons Experiment.sln +++ b/Tactons Experiment.sln @@ -5,8 +5,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tactons Experiment", "Tacto EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tactons JND", "Tactons JND\Tactons JND.vcxproj", "{454A6651-24D2-4DBA-A579-FDACD5CAC68C}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TactonPlayer", "TactonPlayer\TactonPlayer.vcxproj", "{6D5C62C0-562D-4B2A-9AAC-806372810CBF}" -EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -21,10 +19,6 @@ Global {454A6651-24D2-4DBA-A579-FDACD5CAC68C}.Debug|Win32.Build.0 = Debug|Win32 {454A6651-24D2-4DBA-A579-FDACD5CAC68C}.Release|Win32.ActiveCfg = Release|Win32 {454A6651-24D2-4DBA-A579-FDACD5CAC68C}.Release|Win32.Build.0 = Release|Win32 - {6D5C62C0-562D-4B2A-9AAC-806372810CBF}.Debug|Win32.ActiveCfg = Debug|Win32 - {6D5C62C0-562D-4B2A-9AAC-806372810CBF}.Debug|Win32.Build.0 = Debug|Win32 - {6D5C62C0-562D-4B2A-9AAC-806372810CBF}.Release|Win32.ActiveCfg = Release|Win32 - {6D5C62C0-562D-4B2A-9AAC-806372810CBF}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Tactons Experiment.suo b/Tactons Experiment.suo index a4343e8..3e7a781 100644 Binary files a/Tactons Experiment.suo and b/Tactons Experiment.suo differ diff --git a/Tactons JND/Tactons JND.vcxproj b/Tactons JND/Tactons JND.vcxproj index 83c587d..8fb9f8c 100644 --- a/Tactons JND/Tactons JND.vcxproj +++ b/Tactons JND/Tactons JND.vcxproj @@ -50,6 +50,7 @@ ProgramDatabase MultiThreadedDebugDLL false + Level3 Windows diff --git a/Tactons JND/answer3AFC.cpp b/Tactons JND/answer3AFC.cpp index 58ea3b1..34cbc13 100644 --- a/Tactons JND/answer3AFC.cpp +++ b/Tactons JND/answer3AFC.cpp @@ -1,58 +1,249 @@ #include "answer3AFC.h" #include - #include +#include +#include + +#define RESETVAL (3) Answer3AFC::Answer3AFC(QWidget *parent, Qt::WFlags flags) - : QDialog(parent, flags), _logfile(NULL), _tactonPlayer("COM3"), _current(0) +:QDialog(parent, flags), +_logfile(NULL), _tactonPlayer("COM3"), _defaulttacton(0x0f, 50, 205, 100), +_currenttest(0.0), _goodanswer(-1), _block(0) { //init the window setupUi(this); - this->layout()->setSizeConstraint(QLayout::SetFixedSize); +// this->layout()->setSizeConstraint(QLayout::SetFixedSize); + + for (int i = 0 ; i < 3 ; i++) + _tplayed[i] = 0; //init buttons - QObject::connect(play1, SIGNAL(clicked()), this, SLOT(play(1))); - QObject::connect(play2, SIGNAL(clicked()), this, SLOT(play(2))); - QObject::connect(play3, SIGNAL(clicked()), this, SLOT(play(3))); - QObject::connect(answer1, SIGNAL(clicked()), this, SLOT(answer(1))); - QObject::connect(answer2, SIGNAL(clicked()), this, SLOT(answer(2))); - QObject::connect(answer3, SIGNAL(clicked()), this, SLOT(answer(3))); + QObject::connect(play1, SIGNAL(clicked()), this, SLOT(play())); + QObject::connect(play2, SIGNAL(clicked()), this, SLOT(play())); + QObject::connect(play3, SIGNAL(clicked()), this, SLOT(play())); + QObject::connect(answer1, SIGNAL(clicked()), this, SLOT(answer())); + QObject::connect(answer2, SIGNAL(clicked()), this, SLOT(answer())); + QObject::connect(answer3, SIGNAL(clicked()), this, SLOT(answer())); +} + +Answer3AFC::~Answer3AFC() +{ + if (_logfile) + fclose(_logfile); + //reset the wristband + _tactonPlayer.stop(); +} + +void Answer3AFC::init(QString user, int repetitions, int reversals, double tinc, double finc, int tseries, int fseries, QString experiment, QString gesture) +{ + _user = user; + _repetitions = repetitions; + _reversals = reversals; + _tinc = tinc; + _finc = finc; + _tseries = tseries; + _fseries = fseries; + _experiment = experiment; + _gesture = gesture; + + //create log file + QString logfilename = user + "-" + experiment + "-" + gesture + "-"; + _logfile = fopen(logfilename.toStdString().c_str(), "w"); + + //load icons + FILE *f = fopen((experiment + ".txt").toAscii().data(), "r"); + if (f) + { + char buffer[256]; + while ((fgets(buffer, 256, f)) != NULL) + { + unsigned int val = atoi(buffer); + _values.push_back(val); + for (int i = 0 ; i < _repetitions ; i++) + _trials.push_back(val); + } + fclose(f); + //shuffle + for (int i = 0; i < _trials.count(); i++) + _trials.swap(i, (rand() % (_trials.count() - i)) + i); + _jnd.resize(_trials.count()); +/* _jnd = new double[_trials.count()]; + memset(_jnd, 0, _trials.count() * sizeof(double));*/ + } + + //init the wristband + //_tactonPlayer.start(); + + runBlock(); } void Answer3AFC::toggleButtons() { bool ok = _tplayed[0] && _tplayed[1] && _tplayed[2]; - play1->setEnabled(ok); - play2->setEnabled(ok); - play3->setEnabled(ok); + answer1->setEnabled(ok); + answer2->setEnabled(ok); + answer3->setEnabled(ok); } -void Answer3AFC::play(int tacton) +void Answer3AFC::play() { + QPushButton *button = (QPushButton *)sender(); + int tacton; + if (button->objectName() == "play1") + tacton = 0; + else if (button->objectName() == "play2") + tacton = 1; + else if (button->objectName() == "play3") + tacton = 2; + + unsigned int value = 0; if (tacton == _goodanswer) - _tactonPlayer.play(Tacton( - - (...[tacton]); + value = _trials[_block]; + else + value = testValue(_trials[_block], _currenttest); + + Tacton t(_defaulttacton); + if (_experiment == "Frequencies") + t.setFrequency(value); + else if (_experiment == "Amplitudes") + t.setAmplitude(value); + else if (_experiment == "Duration") + t.setDuration(value); + _tactonPlayer.play(t); + _tplayed[tacton]++; toggleButtons(); } -void Answer3AFC::answer(int rep) +void Answer3AFC::answer() { + QPushButton *button = (QPushButton *)sender(); + int rep; + if (button->objectName() == "answer1") + rep = 0; + else if (button->objectName() == "answer2") + rep = 1; + else if (button->objectName() == "answer3") + rep = 2; + log(rep); _tplayed[0] = _tplayed[1] = _tplayed[2] = 0; toggleButtons(); + static int nb = 0, rev = 0; + + static bool newblock = true; + static bool lastval; + bool val = rep == _goodanswer; + + //reversal + if (!newblock && val != lastval) + { + nb = 1; + rev++; + _jnd[_block] += _currenttest / _reversals; + //if enough reversals we switch to a new block + if (rev >= _reversals) + { + log2(); + _block++; + nb = 0; + rev = 0; + newblock = true; + runBlock(); + } + else + { + if (val) + { + if (_tseries == 1 && _currenttest >= _tinc) + { + //change + _currenttest -= _tinc; + nb = 0; + } + } + //wrong answer: increase the gap + else + { + if (_fseries == 1)// && _currenttest < RESETVAL) + { + //change + _currenttest += _finc; + nb = 0; + } + } + } + } + //series + else + { + newblock = false; + nb++; + //good answer: reduce the gap + if (val) + { + if (nb >= _tseries && _currenttest >= _tinc) + { + //change + _currenttest -= _tinc; + nb = 0; + } + } + //wrong answer: increase the gap + else + { + if (nb >= _fseries)// && _currenttest < RESETVAL) + { + //change + _currenttest += _finc; + nb = 0; + } + } + } + lastval = val; + runTrial(); } -void Answer3AFC::log(bool answer) +void Answer3AFC::log(int answer) const +{ + if (_logfile == NULL) + return; + fprintf(_logfile, "ANSWER,%d,%d,%0.2f,%d,%d,%d,%d,%d\n", _block, _trials[_block], _currenttest, _goodanswer, answer, _tplayed[0], _tplayed[1], _tplayed[2]); +} + +void Answer3AFC::log2() const { if (_logfile == NULL) return; - fprintf(_logfile, "%d,%d,%d,%d,%d,%d,%d\n", _currentval, _currenttest, _goodanswer, answer, _tplayed[0], _tplayed[1], _tplayed[2]); + fprintf(_logfile, "JND,%d,%d,%0.2f\n", _block, _trials[_block], _jnd[_block]); +} + +void Answer3AFC::runBlock() +{ + if (_block >= _trials.count()) + { + play1->setEnabled(false); + play2->setEnabled(false); + play3->setEnabled(false); + answer1->setEnabled(false); + answer2->setEnabled(false); + answer3->setEnabled(false); + label->setText("Finished!"); + } + + _currenttest = RESETVAL; + runTrial(); } - + void Answer3AFC::runTrial() { + _goodanswer = rand() % 3; +} + +unsigned int Answer3AFC::testValue(unsigned int value, double db) const +{ + return static_cast(value / pow(10.0, db / 10.0)); } \ No newline at end of file diff --git a/Tactons JND/answer3AFC.h b/Tactons JND/answer3AFC.h index 58ffd2a..a7c711f 100644 --- a/Tactons JND/answer3AFC.h +++ b/Tactons JND/answer3AFC.h @@ -1,6 +1,7 @@ #ifndef _ANSWER3AFC_ #define _ANSWER3AFC_ +#include #include #include @@ -15,30 +16,44 @@ public: Answer3AFC(QWidget *parent = 0, Qt::WFlags flags = 0); ~Answer3AFC(); - void init(QString user, int repetitions, QString experiment, QString gesture); + void init(QString user, int repetitions, int reversals, double tinc, double finc, int tseries, int fseries, QString experiment, QString gesture); void setAnswer(bool same); private: - void log(bool answer); + void log(int answer) const; + void log2() const; void runTrial(); + void runBlock(); + unsigned int testValue(unsigned int value, double db) const; FILE *_logfile; TactonPlayer _tactonPlayer; + Tacton _defaulttacton; + + //exp parameters QString _user; - int _reversals, tseries, _fseries; + int _repetitions, _reversals, _tseries, _fseries; double _tinc, _finc; QString _experiment; QString _gesture; - int _currentval, _currenttest, _goodanswer; - + //exp data + QList _values; + QList _trials; + + //exp status + int _goodanswer, _block; + double _currenttest; + + //results + QVector _jnd; int _tplayed[3]; private slots: void toggleButtons(); - void play(int tacton); - void answer(int rep); + void play(); + void answer(); }; #endif diff --git a/Tactons JND/main.cpp b/Tactons JND/main.cpp index d0c1492..d014216 100644 --- a/Tactons JND/main.cpp +++ b/Tactons JND/main.cpp @@ -1,8 +1,10 @@ #include "tactonsjnd.h" #include +#include int main(int argc, char *argv[]) { + srand(time(NULL)); QApplication a(argc, argv); TactonsJND w; w.show(); diff --git a/Tactons JND/tactonsjnd.cpp b/Tactons JND/tactonsjnd.cpp index 6fedb8c..7274998 100644 --- a/Tactons JND/tactonsjnd.cpp +++ b/Tactons JND/tactonsjnd.cpp @@ -1,5 +1,7 @@ #include "tactonsjnd.h" +#include + TactonsJND::TactonsJND(QWidget *parent, Qt::WFlags flags) : QMainWindow(parent, flags) { @@ -40,3 +42,12 @@ TactonsJND::~TactonsJND() { } + +void TactonsJND::runBlock(void) +{ + this->hide(); + w.init(username->text(), repetitions->value(), + reversals->value(), tinc->value(), finc->value(), tseries->value(), fseries->value(), + experiment->currentText(), gesture->currentText()); + w.show(); +} diff --git a/Tactons JND/tactonsjnd.ui b/Tactons JND/tactonsjnd.ui index 35226d9..7b97944 100644 --- a/Tactons JND/tactonsjnd.ui +++ b/Tactons JND/tactonsjnd.ui @@ -6,8 +6,8 @@ 0 0 - 461 - 270 + 231 + 279 @@ -20,8 +20,8 @@ - - + + @@ -32,14 +32,34 @@ + + + + 1 + + + 50 + + + 1 + + + + + Repetitions: + + + + + Reversals: - + 2 @@ -52,55 +72,78 @@ - - + + - Experiment: + T Inc - - - - - - - Gesture: + + + + 10.000000000000000 - - - - - - - - - T Inc + + 0.250000000000000 + + + 1.000000000000000 - + F Inc - + + + + 0.000000000000000 + + + 10.000000000000000 + + + 0.250000000000000 + + + 1.000000000000000 + + + + T Series - + F Series - + + + + Experiment: + + + + + + + Gesture: + + + + 1 @@ -110,7 +153,7 @@ - + 1 @@ -120,49 +163,26 @@ - - - - 10.000000000000000 - - - 0.250000000000000 - - - 1.000000000000000 - - + + - - - - 0.000000000000000 - - - 10.000000000000000 - - - 0.250000000000000 - - - 1.000000000000000 - - + + - - - - - - - Start experiment - - - + + + + + + + Start experiment + + +