Skip to content

Commit

Permalink
refinements for biofeedback, added provision for biofeedback over UART
Browse files Browse the repository at this point in the history
  • Loading branch information
jnj256 committed Oct 24, 2023
1 parent c99d504 commit ba1a9e0
Show file tree
Hide file tree
Showing 17 changed files with 412 additions and 202 deletions.
62 changes: 46 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# **Overview of PhysioKit**
Authors: Jitesh Joshi, Katherine Wang, and Youngjun Cho <br>
Contact: Physiological Computing and Artificial Intelligence lab @ GDIH - WHO Collaboration Centre for Assistive Technology, UCL Computer Science ([email protected])

Authors: Jitesh Joshi, Katherine Wang, and Youngjun Cho <br>
Contact: Physiological Computing and Artificial Intelligence lab @ GDIH - WHO Collaboration Centre for Assistive Technology, UCL Computer Science (<[email protected]>)

PhysioKit is a novel physiological computing toolkit which is open-source, accessible and affordable. HCI hobbyists and practitioners can easily access physiological sensing channels that help monitor our physiological signatures and vital signs including heart rate, heart rate variability, breathing rate, electrodermal activities. The toolkit works with a low-cost micro-controller such as Arduino. Currently, it supports acquiring EDA, Resp and PPG using any low-cost Arduino board.

Expand All @@ -11,19 +12,40 @@ Below figure shows architecture of PhysioKit:
<img src="images/architecture.png" alt="Architecture of PhysioKit" width="1024"/>
</p>

## **Installation**

Pre-requisite: Python >= 3.8

It is recommended to create separate Python virtual environment, which can be achieved using anaconda/ miniconda as follows:

``` bash
conda create -n phys python=3.11
```

Once the environment is created or already exists, activate the same as follows:

``` bash
conda activate phys
```

You can then use [PyPI package](https://pypi.org/project/PhysioKit2/) to install PhysioKit, using the below mentioned command:

## **Installation**
If you are using Python virtual environment, activate the same or create new.
You can use [PyPI package](https://pypi.org/project/PhysioKit2/) to install PhysioKit, using the below mentioned command:
``` bash
pip install PhysioKit2
```

To update the currently installed package:

``` bash
pip install --upgrade PhysioKit2
```

## **Usage Instructions**

### **Step-1: Upload program on the Arduino board**

Connect the Arduino board that you want to use. For this step, the sensors need not be connected.
Navigate to "*arduino/default*" folder (for AVR family boards which are most common, e.g. Nano, Uno, Mega) and as per the number of sensors that you want to use, go to the respective folder and open the ".ino" file using Arduino IDE.
Navigate to "*arduino/default*" folder (for AVR family boards which are most common, e.g. Nano, Uno, Mega) and as per the number of sensors that you want to use, go to the respective folder and open the ".ino" file using Arduino IDE.
For example, if you want to use all three supported sensors, you may choose "*three_sensors*" folder and open "*three_sensors.ino*". "*four_sensors.ino*" can be used in a setting where two pulse sensors (at different sensor sites, e.g. finger, ear) are to be used.

Having identified the correct Arduino program, upload the same to the Arduino board using Arduino IDE. If you are unfamiliar with this step, you may have a look at [this](https://support.arduino.cc/hc/en-us/articles/4733418441116-Upload-a-sketch-in-Arduino-IDE) tutorial for detailed instructions on how to upload program on Arduino board.
Expand All @@ -32,20 +54,22 @@ The Arduino program files for Arm based board (e.g. Due) are also provided at "*
The default sampling rate is 250 samples per second for all boards. If you need to change this, please follow the comments written in the arduino code. Similarly, the default baudrate for AVR boards is set to 115200. To set a different baudrate, both the Arduino program and software configuration file (e.g. *configs/avr_default/sw_config.json*) are required to be changed appropriately.

### **Step-2: Choose or Update Software Configuration File**

If no changes have been made to Arduino program, then it is only required to identify the correct software configuration file. For single-user scenario and default AVR family boards, the config file to be used is *configs/avr_default/sw_config.json*. In this config file, *external_sync* is specified with *enable* field set to *false*.

For multi-user settings, *external_sync* is specified with *enable* field set to *true*. Depending on the *role* speficied for the computer, it can serve either as *server* or as *client* - for which one of the two config files - *sw_config_server.json* or *sw_config_client.json* can be used.
For multi-user settings, *external_sync* is specified with *enable* field set to *true*. Depending on the *role* speficied for the computer, it can serve either as *server* or as *client* - for which one of the two config files - *sw_config_server.json* or *sw_config_client.json* can be used.

While no changes are required for *sw_config_server.json*, the *client* field in the *sw_config_client.json* file is required to specify the "*server_ip*" address. Please ensure that the "*server_ip*" address is reachable, and both the clients and the server are on the same enterprise network, or reachable using VPN.

### **Step-3: Update Experiment Configuration File**

Experiment configuration file needs to be updated as per the study protocol. This is described below with an illustration of the experiment configuration file used for the validation study of PhysioKit.

Study name and conditions field once specified, are used by the interface to store the acquired data. There are no restrictions on the number of experimental conditions that can be added here.
Study name and conditions field once specified, are used by the interface to store the acquired data. There are no restrictions on the number of experimental conditions that can be added here.

*channels* are the user-facing names of the sensors that are used in the study. For the interface to plot signals with physiological signal specific filtering, it is required to correctly specify the *channel_types*. The order of *channels*, *channel_types* and the connection of physiological sensors on the analog channels of Arduino board shall match precisely.
*channels* are the user-facing names of the sensors that are used in the study. For the interface to plot signals with physiological signal specific filtering, it is required to correctly specify the *channel_types*. The order of *channels*, *channel_types* and the connection of physiological sensors on the analog channels of Arduino board shall match precisely.

If the study protocol requires acquisition for indefinitely long duration with manual stop, then *timed_acquisition* can be specified as *False*, otherwise in every other scenario, this is to be set as *true*. If this is specified as *true*, it is required to specify the acquisition duration (in seconds) separately for each experimental condition.
If the study protocol requires acquisition for indefinitely long duration with manual stop, then *timed_acquisition* can be specified as *False*, otherwise in every other scenario, this is to be set as *true*. If this is specified as *true*, it is required to specify the acquisition duration (in seconds) separately for each experimental condition.

Using the *datapath* field, we can specify the path at which the acquired data with get stored.

Expand All @@ -64,9 +88,11 @@ Lastly, as the interface supports marking of asynchronous events, the descriptio
}

### **Step-4: Launch the PhysioKit Interface**

Before launching the interface, ensure that the Arduino board is connected to the computer using USB connection or through Bluetooth connection. At this step, sensors are required to be appropriately connected to the analog channels of Arduino board.

To launch the interface, run the following command in the terminal:

``` bash
physiokit --config <path of config file>
see example below
Expand All @@ -85,11 +111,11 @@ A brief description of each step is mentioned below:
> **Step-4b: Browse and select appropriate Experiment Configuration file**: Using the interface, browse the *Experiment Configuration File* as updated in [Step-3](#step-3-update-experiment-configurartion-file). On successful loading of the config file, the interface shall start displaying he plotting area with the specified number of channels. Please note if the number of channels are more than 4, the interface will only show real-time plotting of first four physiological signals as specified in the configuration file.
> **Step-4c: Specify Participant ID**: This allows specifying the participant ID in user preferred manner. The ID specified here will be used for storing the data in organized manner.
> **Step-4c: Specify Participant ID**: This allows specifying the participant ID in user preferred manner. The ID specified here will be used for storing the data in organized manner.
> **Step-4d: Select Experiment Condition**: This part of the interface shows a list of conditions as specified in the *Experiment Configuration File* in [Step-3](#step-3-update-experiment-configurartion-file). Each condition listed can be selected with a mouse click. Experimental condition will also be used in naming the file while storing acquired physiological signals.
> **Step-4e: Start Live Acquisition**: In this step, real-time plots can be seen in the plotting area of the interface. Signals are not yet being recorded and the objective at this step is to visually inspect the physiological signals and verify if good quality signals are being acquired.
> **Step-4e: Start Live Acquisition**: In this step, real-time plots can be seen in the plotting area of the interface. Signals are not yet being recorded and the objective at this step is to visually inspect the physiological signals and verify if good quality signals are being acquired.
> **Step-4f: Start Recording**: Having verified the signals with real-time plotting feature, recording can be started with a manual trigger. In case of multi-user settings, all the client computers are required to remain ready for recording the data before the recording starts at the server computer. Pressing *Record Data* on client computer makes it ready to wait for a trigger from the connected server. The recording of the data on all the computers can be started synchronously with a manual trigger at server computer.
Expand All @@ -100,16 +126,20 @@ A brief description of each step is mentioned below:
---

### **Data Analysis**

Data analysis is supported by the *analysis_helper* folder. To extract features and export in spreadsheet, please refer to the README provided within the folder.
In addition, Jupyter notebooks *phys_analysis_eda.ipynb*, *phys_analysis_ppg.ipynb*, and *phys_analysis_resp.ipynb* are provided to illustrate basic analysis steps. This includes pre-processing as well as feature extraction for EDA, PPG and Resp signals respectively.

---
### **Additional Support or Reporting Issues with the Library**:
Please use Github's *Issues* to report any problem you face while using the PhysioKit.

### **Additional Support or Reporting Issues with the Library**

Please use Github's *Issues* to report any problem you face while using the PhysioKit.

---

### **Citation**:
### **Citation**

@Article{s23198244,
AUTHOR = {Joshi, Jitesh and Wang, Katherine and Cho, Youngjun},
TITLE = {PhysioKit: An Open-Source, Low-Cost Physiological Computing Toolkit for Single- and Multi-User Studies},
Expand All @@ -118,7 +148,7 @@ VOLUME = {23},
YEAR = {2023},
NUMBER = {19},
ARTICLE-NUMBER = {8244},
URL = {https://www.mdpi.com/1424-8220/23/19/8244},
URL = {<https://www.mdpi.com/1424-8220/23/19/8244}>,
PubMedID = {37837074},
ISSN = {1424-8220},
DOI = {10.3390/s23198244}
Expand Down
47 changes: 47 additions & 0 deletions arduino/default/two_sensors_bf/two_sensors_bf.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#include <util/delay.h>

// Variables
int APin = 0; // Sensor1 connected to ANALOG PIN 0
int BPin = 1; // Sensor2 connected to ANALOG PIN 1
const int PWM_PIN = 5;

int sampling_rate = 250;
long int baudrate = 115200;

unsigned int aVal = 0;
unsigned int bVal = 0;
int bf = 0;

// To compute: inter_sample_interval_us
//int(round(float(1000/sampling_rate))) ->use this formula to calculate. Here it can not be made dymanic due to library limitation
// Also account for the average processing delay, and substract from the value, e.g. for 250 sampling rate, 4 - 0.7
// 0.1 -> ADC, 0.2 - serial.Print, 0.1 - Misc
double inter_sample_interval_us = 3.3;

// The SetUp Function:
void setup() {
Serial.begin(baudrate); // Set's up Serial Communication at certain speed.
pinMode(APin, INPUT);
pinMode(BPin, INPUT);
}

// The Main Loop Function
void loop() {

bf = Serial.read();
if (bf > 0)
{
analogWrite(PWM_PIN, bf);
}

aVal = analogRead(APin); // Read the Sensor1 value. Assign this value to the "aVal" variable.
bVal = analogRead(BPin); // Read the Sensor2 value. Assign this value to the "bVal" variable.

Serial.print(aVal); // Send the aVal value to Serial.
Serial.print(",");
Serial.println(bVal); // Send the bVal value to Serial.

noInterrupts();
_delay_ms(inter_sample_interval_us);
interrupts();
}
12 changes: 6 additions & 6 deletions configs/exp_config_EDA.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@
},
"biofeedback": {
"enabled": false,
"ch_index": 0,
"metric": "SCR_Magnitude",
"window": 10,
"step": 1,
"mapping": "linear_increase",
"type": "visual",
"visual_feedback": {
"shape": "circle",
"ch_index": 3,
"varying_parameter": "color",
"metric": "HRV_MeanNN",
"window": 30,
"step": 1,
"mapping": "linear_increase"
"varying_parameter": "size"
}
}
}
14 changes: 7 additions & 7 deletions configs/exp_config_EDA_Resp_PPG.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{
"study_name": "Study1",
"conditions": ["baseline", "expCond1"],
"channels": ["EDA", "Resp", "PPG Ear"],
"channels": ["EDA", "Resp", "PPG"],
"channel_types": ["eda", "resp", "ppg"],
"timed_acquisition": true,
"assess_signal_quality": true,
Expand All @@ -16,15 +16,15 @@
},
"biofeedback": {
"enabled": false,
"ch_index": 1,
"metric": "RSP",
"window": 0.2,
"step": 0.1,
"mapping": "linear_increase",
"type": "visual",
"visual_feedback": {
"shape": "circle",
"ch_index": 3,
"varying_parameter": "color",
"metric": "HRV_MeanNN",
"window": 30,
"step": 1,
"mapping": "linear_increase"
"varying_parameter": "size"
}
}
}
14 changes: 7 additions & 7 deletions configs/exp_config_EDA_Resp_PPG1_PPG2.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{
"study_name": "Study1",
"conditions": ["baseline", "expCond1"],
"channels": ["EDA", "Resp", "PPG Finger", "PPG Ear"],
"channels": ["EDA", "Resp", "PPG1", "PPG2"],
"channel_types": ["eda", "resp", "ppg", "ppg"],
"timed_acquisition": true,
"assess_signal_quality": true,
Expand All @@ -16,15 +16,15 @@
},
"biofeedback": {
"enabled": false,
"ch_index": 3,
"metric": "HRV_MeanNN",
"window": 10,
"step": 1,
"mapping": "linear_increase",
"type": "visual",
"visual_feedback": {
"shape": "circle",
"ch_index": 3,
"varying_parameter": "color",
"metric": "HRV_MeanNN",
"window": 30,
"step": 1,
"mapping": "linear_increase"
"varying_parameter": "size"
}
}
}
12 changes: 6 additions & 6 deletions configs/exp_config_PPG.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@
},
"biofeedback": {
"enabled": false,
"ch_index": 0,
"metric": "HRV_MeanNN",
"window": 10,
"step": 1,
"mapping": "linear_increase",
"type": "visual",
"visual_feedback": {
"shape": "circle",
"ch_index": 3,
"varying_parameter": "color",
"metric": "HRV_MeanNN",
"window": 30,
"step": 1,
"mapping": "linear_increase"
"varying_parameter": "color"
}
}
}
12 changes: 6 additions & 6 deletions configs/exp_config_PPG1_PPG2.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@
},
"biofeedback": {
"enabled": false,
"ch_index": 0,
"metric": "HRV_MeanNN",
"window": 10,
"step": 1,
"mapping": "linear_increase",
"type": "visual",
"visual_feedback": {
"shape": "circle",
"ch_index": 3,
"varying_parameter": "color",
"metric": "HRV_MeanNN",
"window": 30,
"step": 1,
"mapping": "linear_increase"
"varying_parameter": "size"
}
}
}
12 changes: 6 additions & 6 deletions configs/exp_config_Resp.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@
},
"biofeedback": {
"enabled": false,
"ch_index": 0,
"metric": "RSP",
"window": 0.2,
"step": 0.1,
"mapping": "linear_increase",
"type": "visual",
"visual_feedback": {
"shape": "circle",
"ch_index": 3,
"varying_parameter": "color",
"metric": "HRV_MeanNN",
"window": 30,
"step": 1,
"mapping": "linear_increase"
"varying_parameter": "size"
}
}
}
30 changes: 30 additions & 0 deletions configs/exp_config_Resp_BF.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"exp":
{
"study_name": "Demo",
"conditions": ["baseline", "expCond1"],
"channels": ["Resp"],
"channel_types": ["resp"],
"timed_acquisition": true,
"assess_signal_quality": false,
"max_time_seconds": [180, 180],
"datapath": "data",
"event_codes": {
"0": "event_1",
"1": "event_2"
}
},
"biofeedback": {
"enabled": true,
"ch_index": 0,
"metric": "RSP",
"window": 0.2,
"step": 0.1,
"mapping": "linear_increase",
"type": "visual",
"visual_feedback": {
"shape": "circle",
"varying_parameter": "size"
}
}
}
Loading

0 comments on commit ba1a9e0

Please sign in to comment.