Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Updating the N-back timeline
Browse files Browse the repository at this point in the history
CharlieHFFF committed Nov 25, 2024
1 parent 3390109 commit 67e5f9c
Showing 7 changed files with 322 additions and 0 deletions.
71 changes: 71 additions & 0 deletions packages/n-back/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# n-back

## Overview

A timeline for the nback task

## Loading

### In browser

```html
<script src="https://unpkg.com/@jspsych-timelines/n-back">
```
### Via NPM
```
npm install @jspsych-timelines/n-back
```
```js
import { createTimeline } from "@jspsych-timelines/n-back"
```
## Compatibility
`@jspsych-timelines/n-back` requires jsPsych v8.0.0 or later.
## Documentation
### createTimeline
#### jsPsychTimelineNBack.createTimeline(jsPsych, { *options* }) ⇒ <code>timeline</code>
This timeline describes an N-back task setup that is customizable based on several parameters, allowing researchers to control the level of difficulty, timing, and data output format.
| Parameter | Type | Default | Description |
|---------------------|---------------------------|---------------|-----------------------------------------------------------------------------------------------|
| `stimuli` | `any` | | Stimuli array used in the N-back task, which can be customized based on the experiment needs. |
| `keyboard_response` | `string` | `"n"` | Key used by participants to respond during trials. |
| `trial_duration` | `number` | `1000` ms | Duration of each trial in milliseconds. |
| `post_trial_gap` | `number` | `500` ms | Gap between trials in milliseconds. |
| `fixation_duration` | `number` | `500` ms | Duration of the fixation cross before each trial. |
| `n` | `number` | `2` | Level of N-back, determining how many trials back the participant should remember. |
| `num_trials` | `number` | `20` | Total number of trials in the experiment. |
| `rep_ratio` | `number` | `0.2` | Probability that a stimulus will repeat in the N-back sequence, affecting task difficulty. |
| `debrief` | `boolean` | `false` | Whether to show a debrief screen at the end of the task. |
| `return_accuracy` | `boolean` | `false` | Whether to return participant accuracy as part of the output data. |
| `data_output` | `"none"`, `"json"`, `"csv"` | `"none"` | Specifies the format for saving output data, if any. |
## Reference for Standard Performance
### Standard N-back Task Performance
The following table summarizes the standard performance (accuracy and reaction times) for control subjects in the 1-back, 2-back, and 3-back tasks, as reported by Harvey et al. (2004).
| Condition | Accuracy (%) | Reaction Time (ms) |
|-----------|-------------------|----------------------------|
| 1-back | 96.5 (±3.6) | 749.3 (±199.0) |
| 2-back | 85.6 (±8.8) | 1005.5 (±247.2) |
| 3-back | 80.0 (±7.4) | 1049.5 (±214.8) |
with a sample size of 22 individuals.
## Reference
Harvey, P. O., Le Bastard, G., Pochon, J. B., Levy, R., Allilaire, J. F., Dubois, B., & Fossati, P. (2004). Executive functions and updating of the contents of working memory in unipolar depression. Journal of Psychiatric Research, 38(6), 567–576. https://doi.org/10.1016/j.jpsychires.2004.03.003
## Author
Feng Wan
51 changes: 51 additions & 0 deletions packages/n-back/docs/n-back.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# n-back

Building n-back experiment templates in JsPsych

## Parameters

### Initialization Parameters

Initialization parameters can be set when calling `initJsPsych()`

```js
initJsPsych({
timelines: [
{type: jsPsychTimelineNBack, params: {...}}
]
})
```

Parameter | Type | Default Value | Description
----------|------|---------------|------------
| | |

### Trial Parameters

Trial parameters can be set when adding the timeline to a trial object.

```js
var trial = {
type: jsPsych...,
timelines: [
{type: jsPsychTimelineNBack, params: {...}}
]
}
```

Parameter | Type | Default Value | Description
----------|------|---------------|------------
| | |

## Data Generated

Name | Type | Value
-----|------|------
| |

## Functions

If the timeline adds any static functions, list them here.

### function()

43 changes: 43 additions & 0 deletions packages/n-back/examples/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html>

<head>
<script src="https://unpkg.com/jspsych"></script>
<script src="https://unpkg.com/@jspsych/plugin-html-keyboard-response"></script>
<script src="../dist/index.global.js"></script>
<link rel="stylesheet" href="https://unpkg.com/jspsych/css/jspsych.css">
</head>

<body></body>
<script>

const timeline = [];

const jsPsych = initJsPsych({
on_finish: function() {
jsPsych.data.displayData();
}
});

const stimuli = ["b", "B", "d", "D", "g", "G", "p", "P", "t", "T", "v", "V"];

const timeline2Back = jsPsychTimelineNBack.createTimeline(jsPsych, stimuli, "n", 1000, 500, 500, 1, 12, 0.8, data_output = "csv");

const instructions = {
type: jsPsychHtmlKeyboardResponse,
stimulus: `
<p>Welcome to the N-back task.</p>
<p>You will see a sequence of letters on the screen.</p>
<p>Press "space" if the current letter matches the one seen "2“ steps before.</p>
<p>Press any key to begin.</p>
`
};

timeline.push(instructions)

timeline.push(timeline2Back)

jsPsych.run(timeline);
</script>

</html>
1 change: 1 addition & 0 deletions packages/n-back/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require("@jspsych/config/jest").makePackageConfig(__dirname);
37 changes: 37 additions & 0 deletions packages/n-back/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"name": "@jspsych-timelines/n-back",
"version": "0.0.1",
"description": "Building n-back experiment templates in JsPsych",
"type": "module",
"main": "dist/index.mjs",
"types": "dist/index.d.ts",
"unpkg": "dist/index.browser.min.js",
"scripts": {
"build": "tsup src/index.ts --format esm,iife --sourcemap --dts --treeshake --clean --global-name jsPsychTimelineNBack"
},
"repository": {
"type": "git",
"url": "git+https://github.com/jspsych/jspsych-timelines.git"
},
"keywords": [
"jsPsych"
],
"author": {
"name": "Feng Wan",
"url": "https://github.com/CharlieHFFF"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/jspsych/jspsych-timelines/issues"
},
"homepage": "https://github.com/jspsych/jspsych-timelines/packages/n-back#readme",
"peerDependencies": {
"jspsych": "^8.0.1"
},
"dependencies": {
},
"devDependencies": {
"tsup": "^6.7.0",
"typescript": "^5.0.2"
}
}
109 changes: 109 additions & 0 deletions packages/n-back/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { JsPsych } from "jspsych";
import jsPsychHtmlKeyboardResponse from '@jspsych/plugin-html-keyboard-response'

export function createTimeline(jsPsych: JsPsych,
stimuli: any,
keyboard_response: string = "n", // Default key for response
trial_duration: number = 1000, // Default trial duration in ms
post_trial_gap: number = 500, // Default gap between trials in ms
fixation_duration: number = 500, // Default fixation duration in ms
n: number = 2, // Default value for N-back level
num_trials: number = 20, // Default number of trials
rep_ratio: number = 0.2,
debrief: boolean = false,
return_accuracy: boolean = false,
data_output: "none" | "json" | "csv" = "none") {

const trial_sequence: any[] = [];

for (var i = 0; i < num_trials; i++) {
if (i >= n && Math.random() < rep_ratio) {
trial_sequence.push(trial_sequence[i - n]);
} else {
const possible_stimuli = stimuli.filter(function (s: any) {
return (i < n || s !== trial_sequence[i - n]);
});
const random_stimulus = jsPsych.randomization.sampleWithoutReplacement(possible_stimuli, 1)[0];
trial_sequence.push(random_stimulus)
}
}

const timeline: any[] = [];

for (var i = 0; i < trial_sequence.length; i++) {

timeline.push({
type: jsPsychHtmlKeyboardResponse,
stimulus: `<p style="font-size: 48px; color: gray;">+</p>`,
choices: "NO_KEYS",
trial_duration: fixation_duration
});

timeline.push({
type: jsPsychHtmlKeyboardResponse,
stimulus: `<p style="font-size: 48px;">${trial_sequence[i]}</p>`,
choices: [keyboard_response],
trial_duration: trial_duration,
post_trial_gap: post_trial_gap,
data: { correct: i >= n && trial_sequence[i].toLowerCase() === trial_sequence[i - n].toLowerCase() },
on_finish: function (data: any) {
data.correct_response = data.correct && data.response != null;
data.correct_no_response = !data.correct && data.response === null;
}
})
}


if (debrief){
if (return_accuracy){
timeline.push(
{
type: jsPsychHtmlKeyboardResponse,
stimulus: function(){
var correct_responses = jsPsych.data.get().filter({correct_response: true}).count();
var correct_no_responses = jsPsych.data.get().filter({correct_no_response: true}).count();
var total_trials = jsPsych.data.get().count();
var accuracy = Math.round(((correct_responses + correct_no_responses) / total_trials) * 100);
const return_prompt = (correct_response: number, correct_no_response: number, accuracy: number): string => {
return `<p>Thank you for participating!</p>
<p>You correctly responded to <strong>${correct_response}</strong> matching trials.</p>
<p>You correctly did not respond to <strong>${correct_no_response}</strong> non-matching trials.</p>
<p>Your accuracy was <strong>${accuracy}%</strong>.</p>
<p>Press any key to finish the experiment.</p>`;
};
return return_prompt(correct_responses, correct_no_responses, accuracy)
},
choices: "ALL_KEYS",
on_start: function () {
if (data_output == "csv"){
jsPsych.data.get().localSave('csv', `n_back.csv`);} else if (data_output == "json") {
jsPsych.data.get().localSave('json', `n_back.json`);
} else {return null}
},
simulation_options: {
simulate: false
}
})
} else {
timeline.push(
{
type: jsPsychHtmlKeyboardResponse,
stimulus: function(){
return `<p>Thank you for participating!</p>
<p>Press any key to finish the experiment.</p>`;
},
choices: "ALL_KEYS",
on_start: function () {
if (data_output == "csv"){
return jsPsych.data.get().localSave('csv', `n_back.csv`);} else if (data_output == "json") {
return jsPsych.data.get().localSave('json', `n_back.json`)
} else {return null}
},
simulation_options: {
simulate: false
}
})
}}

return timeline
}
10 changes: 10 additions & 0 deletions packages/n-back/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "@jspsych/config/tsconfig.contrib.json",
"compilerOptions": {
"baseUrl": "."
},
"include": [
"src",
"../cli/src/build.js"
]
}

0 comments on commit 67e5f9c

Please sign in to comment.