Almost finished main static MT logic
This commit is contained in:
+47
-26
@@ -6,12 +6,14 @@ from pysndfile import PySndfile, sndio
|
||||
from random import randint, shuffle
|
||||
from shutil import copyfile
|
||||
from natsort import natsorted
|
||||
import numpy as np
|
||||
|
||||
from matrix_test.signalops import play_wav
|
||||
from scipy.special import logit
|
||||
from config import socketio
|
||||
import csv
|
||||
import pdb
|
||||
import dill
|
||||
|
||||
def roll_independant(A, r):
|
||||
rows, column_indices = np.ogrid[:A.shape[0], :A.shape[1]]
|
||||
@@ -62,6 +64,8 @@ class EEGTestThread(Thread):
|
||||
self.question = []
|
||||
|
||||
self.socketio.on_event('eeg_page_loaded', self.setPageLoaded, namespace='/main')
|
||||
self.socketio.on_event('submit_eeg_response', self.submitTestResponse, namespace='/main')
|
||||
self.socketio.on_event('finish_eeg_test', self.finishTestEarly, namespace='/main')
|
||||
# Percent speech inteligibility (estimated using behavioural measure)
|
||||
# to present stimuli at
|
||||
self.si = np.array([20.0, 35.0, 50.0, 65.0, 80.0, 90.0, 100.0])
|
||||
@@ -70,6 +74,9 @@ class EEGTestThread(Thread):
|
||||
self.clinPageLoaded = False
|
||||
self.partPageLoaded = False
|
||||
self.newResp = False
|
||||
self.finishTest = True
|
||||
|
||||
self.trial_ind = 0
|
||||
|
||||
self._stopevent = Event()
|
||||
# Attach messages from gui to class methods
|
||||
@@ -100,16 +107,13 @@ class EEGTestThread(Thread):
|
||||
self.waitForPageLoad()
|
||||
self.socketio.emit('eeg_test_ready', namespace='/main')
|
||||
# For each stimulus
|
||||
for wav, q in zip(self.wav_files, self.question):
|
||||
for ind, (wav, q) in enumerate(zip(self.wav_files, self.question)):
|
||||
self.trial_ind = ind
|
||||
if self._stopevent.isSet():
|
||||
break
|
||||
# Play concatenated matrix sentences at set SNR
|
||||
self.playStimulus(wav)
|
||||
self.setMatrix(q)
|
||||
self.waitForResponse()
|
||||
if self._stopevent.isSet():
|
||||
return
|
||||
self.saveState(out=self.backupFilepath)
|
||||
self.saveState(out=self.backupFilepath)
|
||||
if not self._stopevent.isSet():
|
||||
self.unsetPageLoaded()
|
||||
@@ -119,14 +123,35 @@ class EEGTestThread(Thread):
|
||||
def setMatrix(self, questions):
|
||||
'''
|
||||
'''
|
||||
for q in questions:
|
||||
self.socketio.emit('set_matrix', {'data': q}, namespace='/main')
|
||||
set_trace()
|
||||
for self.q_ind, q in enumerate(questions):
|
||||
self.answer = q[1]
|
||||
question = q[0]
|
||||
self.socketio.emit('set_matrix', {'data': question}, namespace='/main')
|
||||
self.waitForResponse()
|
||||
if self._stopevent.isSet():
|
||||
return
|
||||
self.processResponse()
|
||||
self.saveState(out=self.backupFilepath)
|
||||
|
||||
def processResponse(self):
|
||||
'''
|
||||
'''
|
||||
self.newResp = False
|
||||
symb_dict = {
|
||||
True: 10003,
|
||||
False: 10007
|
||||
}
|
||||
try:
|
||||
self.answers[self.trial_ind, self.q_ind] = self.answer in self.response
|
||||
symb = symb_dict[self.answers[self.trial_ind, self.q_ind]]
|
||||
except:
|
||||
set_trace()
|
||||
self.socketio.emit('eeg_test_resp', {'q_ind': self.q_ind, 'trial_ind': self.trial_ind, "ans": symb}, namespace='/main')
|
||||
|
||||
def finishTestEarly(self):
|
||||
'''
|
||||
'''
|
||||
self._stopevent.set()
|
||||
|
||||
|
||||
def join(self, timeout=None):
|
||||
@@ -154,22 +179,18 @@ class EEGTestThread(Thread):
|
||||
|
||||
|
||||
def finaliseResults(self):
|
||||
toSave = ['snrTrack', 'trialN', 'wordsCorrect', 'presentedWords', 'responses']
|
||||
toSave = ['marker_files', 'clinPageLoaded', 'wav_files', 'participant',
|
||||
'response', 'pageLoaded', 'backupFilepath', 'noise_path',
|
||||
'question_files', 'partPageLoaded', 'si', 'question', 'answers']
|
||||
saveDict = {k:self.__dict__[k] for k in toSave}
|
||||
if self.participant:
|
||||
self.participant['adaptive_matrix_data'].update(saveDict)
|
||||
self.participant.save("adaptive_matrix_data")
|
||||
backup_path = os.path.join(self.participant.data_paths['adaptive_matrix_data'],
|
||||
'finalised_backup.pkl')
|
||||
copy2(self.backupFilepath, backup_path)
|
||||
else:
|
||||
copy2(self.backupFilepath, './finalised_backup.pkl')
|
||||
with open('./Matrix_test_results.pkl', 'wb') as f:
|
||||
dill.dump(saveDict, f)
|
||||
self.participant['eeg_test_data'].update(saveDict)
|
||||
self.participant.save("eeg_test_data")
|
||||
backup_path = os.path.join(self.participant.data_paths['eeg_test_data'],
|
||||
'finalised_backup.pkl')
|
||||
copy2(self.backupFilepath, backup_path)
|
||||
self.finalised = True
|
||||
|
||||
|
||||
|
||||
@staticmethod
|
||||
def logisticFunction(L, L_50, s_50):
|
||||
'''
|
||||
@@ -253,6 +274,8 @@ class EEGTestThread(Thread):
|
||||
c = list(zip(self.wav_files, self.marker_files))
|
||||
shuffle(c)
|
||||
self.wav_files, self.marker_files = zip(*c)
|
||||
self.answers = np.empty(np.shape(self.question)[:2])
|
||||
self.answers[:] = np.nan
|
||||
|
||||
|
||||
def loadNoise(self, noiseFilepath):
|
||||
@@ -285,12 +308,10 @@ class EEGTestThread(Thread):
|
||||
self.newResp = True
|
||||
|
||||
|
||||
def saveState(self, out="mat_state.pkl"):
|
||||
toSave = ['listsRMS', 'y', 'currentList', 'slope', 'snr', 'snrTrack',
|
||||
'direction', 'noise_rms', 'i', 'currentWords', 'usedLists',
|
||||
'availableSentenceInds', 'trialN', 'listsString', 'noise',
|
||||
'fs', 'nCorrect', 'loadedLists', 'lists', 'listN',
|
||||
'wordsCorrect', 'responses', 'presentedWords']
|
||||
def saveState(self, out="eeg_test_state.pkl"):
|
||||
toSave = ['marker_files', 'clinPageLoaded', 'wav_files', 'participant',
|
||||
'response', 'pageLoaded', 'backupFilepath', 'noise_path',
|
||||
'question_files', 'partPageLoaded', 'si', 'question', 'answers']
|
||||
saveDict = {k:self.__dict__[k] for k in toSave}
|
||||
with open(out, 'wb') as f:
|
||||
dill.dump(saveDict, f)
|
||||
|
||||
@@ -48,9 +48,23 @@
|
||||
height: calc(90% - 56px);
|
||||
}
|
||||
|
||||
.eeg_submit > button {
|
||||
display: block;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
align-items: stretch;
|
||||
border-radius: 0px;
|
||||
width: 100%;
|
||||
height: 10%;
|
||||
}
|
||||
|
||||
.center {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
height:100%;
|
||||
}
|
||||
|
||||
#eeg_test_table td {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
@@ -1,11 +1,47 @@
|
||||
{% extends 'index.html' %}
|
||||
{% block content %}
|
||||
<div id="main-div">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div id="progress-div" class="progress">
|
||||
<div id="progress" class="progress-bar progress-bar-striped progress-bar-animated" role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" style="width: 0%"></div>
|
||||
</div>
|
||||
<link rel=stylesheet type=text/css href="{{ url_for('static', filename='style.css') }}">
|
||||
<div class="card">
|
||||
<div id="main-div" class="card-body">
|
||||
<table id="eeg_test_table" class="table table-sm table">
|
||||
<thead class="thead-dark">
|
||||
<tr>
|
||||
<th scope="col">Trial #</th>
|
||||
<th scope="col">1</th>
|
||||
<th scope="col">2</th>
|
||||
<th scope="col">3</th>
|
||||
<th scope="col">4</th>
|
||||
<th scope="col">5</th>
|
||||
<th scope="col">6</th>
|
||||
<th scope="col">7</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr id="Q1">
|
||||
<th scope="row">Q1</th>
|
||||
<td class="T1">-</td>
|
||||
<td class="T2">-</td>
|
||||
<td class="T3">-</td>
|
||||
<td class="T4">-</td>
|
||||
<td class="T5">-</td>
|
||||
<td class="T6">-</td>
|
||||
<td class="T7">-</td>
|
||||
</tr>
|
||||
<tr id="Q2">
|
||||
<th scope="row">Q2</th>
|
||||
<td class="T1">-</td>
|
||||
<td class="T2">-</td>
|
||||
<td class="T3">-</td>
|
||||
<td class="T4">-</td>
|
||||
<td class="T5">-</td>
|
||||
<td class="T6">-</td>
|
||||
<td class="T7">-</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="d-flex justify-content-center mt-2" role="group">
|
||||
<button type="button" id="eeg_test_save" class="btn btn-primary mx-3">Save test state</button>
|
||||
<button type="button" id="eeg_test_finish" class="btn btn-primary mx-3">Finish test</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -16,6 +52,13 @@
|
||||
// Check if matrix stimulus is currently being processed
|
||||
waitingDialog.show('Generating stimulus');
|
||||
|
||||
|
||||
socket.on('eeg_test_resp', function(msg) {
|
||||
var t_ind = msg['trial_ind'];
|
||||
var q_ind = msg['q_ind'];
|
||||
$(`#Q${q_ind+1} > .T${t_ind+1}`).text(String.fromCharCode(msg['ans']));
|
||||
});
|
||||
|
||||
socket.on('eeg_test_ready', function(msg) {
|
||||
waitingDialog.hide();
|
||||
});
|
||||
@@ -23,6 +66,16 @@
|
||||
socket.on('check-loaded', function(msg) {
|
||||
socket.emit('eeg_page_loaded', {data: "clinician"});
|
||||
});
|
||||
|
||||
$('#eeg_test_finish').click(function(event) {
|
||||
socket.emit("finish_eeg_test")
|
||||
});
|
||||
|
||||
// Catch message when asynchronous process is complete
|
||||
socket.on('processing-complete', function(msg) {
|
||||
alert("Matrix stimulus processing complete!")
|
||||
window.location.href = '/eeg/test/clinician/complete';
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -63,8 +63,8 @@
|
||||
<button type="button" href="#" data-toggle="button" aria-pressed="false" disabled id="mat-3" class="Btn Btn-outline-secondary mat-button">big</button>
|
||||
<button type="button" href="#" data-toggle="button" aria-pressed="false" disabled id="mat-4" class="Btn Btn-outline-secondary mat-button">beds</button>
|
||||
</div>
|
||||
<div class="mat_submit">
|
||||
<button type="button" href="#" disabled id="mat-submit" class="Btn Btn-primary">Submit</button>
|
||||
<div class="eeg_submit">
|
||||
<button type="button" href="#" disabled id="eeg-submit" class="Btn Btn-primary">Submit</button>
|
||||
</div>
|
||||
<div id="overlay">
|
||||
<span id="overlay_crosshair">✚</span>
|
||||
@@ -99,13 +99,13 @@
|
||||
});
|
||||
|
||||
socket.on('eeg_stim_done', function(msg) {
|
||||
$('.eeg_submit').find('input, textarea, button, select').removeAttr('disabled');
|
||||
off()
|
||||
});
|
||||
|
||||
socket.on('set_matrix', function(msg) {
|
||||
var q = msg['data'][0];
|
||||
var q = msg['data'];
|
||||
q = q.split(" ")
|
||||
var ans = msg['data'][1];
|
||||
for(i = 0; i < q.length; i++) {
|
||||
entry = q[i]
|
||||
var buttons = $(`.mat-button#mat-${i}`)
|
||||
@@ -119,8 +119,10 @@
|
||||
buttons.not(`:contains(${entry})`).attr('disabled','disabled');
|
||||
$(`.mat-button:contains(${entry})`).addClass("active");
|
||||
$(`.mat-button:contains(${entry})`).attr("aria-pressed", "true");
|
||||
choice[i] = entry.toUpperCase();
|
||||
}
|
||||
}
|
||||
$('#eeg-submit').prop("disabled", false);
|
||||
});
|
||||
|
||||
function on() {
|
||||
@@ -134,21 +136,28 @@
|
||||
$("#overlay").fadeOut();
|
||||
}
|
||||
|
||||
$('#mat-submit').click(function(event) {
|
||||
$('#mat-submit').prop("disabled", true);
|
||||
$('#eeg-submit').click(function(event) {
|
||||
$('#eeg-submit').prop("disabled", true);
|
||||
if(choice.includes('')) {
|
||||
alert("Please select a word from each column");
|
||||
$('#mat-submit').prop("disabled", false);
|
||||
$('#eeg-submit').prop("disabled", false);
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
$('.mat-button').removeClass("active");
|
||||
socket.emit('submit_mat_response', {
|
||||
socket.emit('submit_eeg_response', {
|
||||
resp: choice
|
||||
});
|
||||
choice = Array(5).fill('');
|
||||
}
|
||||
});
|
||||
|
||||
socket.on('processing-complete', function(msg) {
|
||||
// Re-enable all inputs
|
||||
$('#main-div').find('input, textarea, button, select').removeAttr('disabled');
|
||||
alert("Matrix stimulus processing complete!")
|
||||
window.location.href = '/eeg/test/complete';
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -105,14 +105,6 @@
|
||||
$('#progress').css("width", msg.data);
|
||||
});
|
||||
|
||||
// Catch message when asynchronous process is complete
|
||||
socket.on('processing-complete', function(msg) {
|
||||
// Re-enable all inputs
|
||||
$('#main-div').find('input, textarea, button, select').removeAttr('disabled');
|
||||
alert("Matrix stimulus processing complete!")
|
||||
window.location.href = '/matrix_test/clinician/complete';
|
||||
});
|
||||
|
||||
socket.on('main-notification', function(msg) {
|
||||
alert(msg.data)
|
||||
});
|
||||
|
||||
@@ -41,6 +41,15 @@ $(document).ready(function(){
|
||||
socket.on('check-loaded', function(msg) {
|
||||
socket.emit('mat_page_loaded', {data: "clinician"});
|
||||
});
|
||||
|
||||
// Catch message when asynchronous process is complete
|
||||
socket.on('processing-complete', function(msg) {
|
||||
// Re-enable all inputs
|
||||
$('#main-div').find('input, textarea, button, select').removeAttr('disabled');
|
||||
alert("Matrix stimulus processing complete!")
|
||||
window.location.href = '/matrix_test/clinician/complete';
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -105,8 +105,12 @@
|
||||
$('#main-div').find('input, textarea, button, select').removeAttr('disabled');
|
||||
});
|
||||
|
||||
// Catch message when asynchronous process is complete
|
||||
socket.on('processing-complete', function(msg) {
|
||||
$('#main-div').find('input, textarea, button, select').attr('disabled','disabled');
|
||||
// Re-enable all inputs
|
||||
$('#main-div').find('input, textarea, button, select').removeAttr('disabled');
|
||||
alert("Matrix stimulus processing complete!")
|
||||
window.location.href = '/matrix_test/complete';
|
||||
});
|
||||
|
||||
socket.on('check-loaded', function(msg) {
|
||||
|
||||
@@ -67,15 +67,6 @@
|
||||
socket.on('participant_start_mat', function() {
|
||||
window.location.href = "/matrix_test/run";
|
||||
});
|
||||
|
||||
// Catch message when asynchronous process is complete
|
||||
socket.on('processing-complete', function(msg) {
|
||||
// Re-enable all inputs
|
||||
$('#main-div').find('input, textarea, button, select').removeAttr('disabled');
|
||||
alert("Matrix stimulus processing complete!")
|
||||
window.location.href = '/matrix_test/complete';
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user