Here is the SC code for that:
(
SerialPort.listDevices;
~myPort = SerialPort("/dev/tty.usbserial-A600dSr9", baudrate: 9600, crtscts: true);
~myPort.close
SerialPort.closeAll;
~serialReceive.play;
~serialReceive.stop;
~pieceBegins = thisThread.seconds; //assign the start of the piece
~serialReceive = Task({
var serialArraySize = 7;
var serialArray = Array.newClear(serialArraySize);
inf.do({
if(~myPort.notNil, {
~incData = ~myPort.next;
if(~incData.notNil, {
~incData.postln;
serialArray = serialArray.shift(-1);
serialArray[serialArraySize - 1] = ~incData;
if(serialArray[serialArraySize - 1]==0, {
serialArray.postln;
});
});
});
0.1.wait;
});
});
)
The next step is to store completed serial arrays in order to compare data from consecutive arrays. When I began working with these sensors I noticed that they can sometimes be quite sensitive and so I thought I would compare the average of three initial sensor values to the average of the subsequent three values in order to determine whether or not there was a breath. The biggest problem with this approach was that it introduced a bit of a delay into the system so that breaths were not recognized in real time. And so while I am still storing values from the six 'most recent' arrays, I am no longer taking the time to find the average values of the sensors for comparison.
Storing arrays in a 2D array:
The first step in storing arrays is to capture the relevant data in new array. Here I fill a new array called ~newVal with the six values from the serialArray, and then post it:
The first step in storing arrays is to capture the relevant data in new array. Here I fill a new array called ~newVal with the six values from the serialArray, and then post it:
~newVal= Array.fill(6, { arg i; serialArray[i]});
"newVal is ".postln;
"newVal is ".postln;
~newVal.postln;
In order to avoid nil related errors, first I check to make sure that the serialArray is notNil, so the complete code looks like this:
if((serialArray[0]).notNil && (serialArray[1]).notNil && (serialArray[2]).notNil && (serialArray[3]).notNil, {
In order to avoid nil related errors, first I check to make sure that the serialArray is notNil, so the complete code looks like this:
if((serialArray[0]).notNil && (serialArray[1]).notNil && (serialArray[2]).notNil && (serialArray[3]).notNil, {
~newVal= Array.fill(6, { arg i; serialArray[i]});
"newVal is ".postln;
"newVal is ".postln;
~newVal.postln;
});
The next step is to store the next array that comes in. In order to do this I essentially made a bucket brigade which passes the ~newVal array up the line until it eventually becomes ~oldVal5. In the meantime, new arrays are filling up the chain. So it ends up looking like this:
The next step is to store the next array that comes in. In order to do this I essentially made a bucket brigade which passes the ~newVal array up the line until it eventually becomes ~oldVal5. In the meantime, new arrays are filling up the chain. So it ends up looking like this:
~curTime = thisThread.seconds - ~pieceBegins;
if(~curTime > 5.0, {
~oldVal5 = Array.newClear(6);
~oldVal5 = ~oldVal4;
~oldVal4 = Array.newClear(6);
~oldVal4 = ~oldVal3;
~oldVal3 = Array.newClear(6);
~oldVal3 = ~oldVal2;
~oldVal2 = Array.newClear(6);
~oldVal2 = ~oldVal1;
~oldVal1 = Array.newClear(6);
~oldVal1 = ~oldVal;
if(~newVal.notNil, {
~oldVal = Array.newClear(6);
~oldVal = ~newVal;
});
if((serialArray[0]).notNil
&& (serialArray[1]).notNil
&& (serialArray[2]).notNil
&& (serialArray[3]).notNil, {
&& (serialArray[1]).notNil
&& (serialArray[2]).notNil
&& (serialArray[3]).notNil, {
~newVal= Array.fill(6, { arg i; serialArray[i]});
"newVal is ".postln;
~newVal.postln;
});
Note that it's a bit counterintuitive...everything moves from the bottom newVal up to the top oldVal5.
Finally, all of these values are stored in a 2D array:
Finally, all of these values are stored in a 2D array:
~array = [~oldVal5, ~oldVal4, ~oldVal3, ~oldVal2, ~oldVal1, ~oldVal, ~newVal];
Again, the main purpose of storing so many arrays (actually 7, total) was so that I could compare the average sensor values to avoid reading in a lot of 'noise'. After I discovered that this was creating an awkward delay, instead of rewriting all of the code that dealt with the averages, I put a temporary bandaid on the situation by swapping out the arrays in my 2D array:
As previously mentioned: the code immediately above is repeated for each ~compareSensor array, #0-5, and is part of an infinite loop reading in and testing these values. Whether or not there is a breath is determined in a separate loop that considers the data coming in from all of the sensors, collectively. I'll save that for my next post...
~array = [~oldVal, ~oldVal, ~oldVal, ~newVal, ~newVal, ~newVal, ~newVal];
This way when I go to take the 'averages' I can do it right away because the arrays stored are really only the most recent arrays.
Here I get the 'averages' (again, will most likely be getting rid of this step):
//gets averages of 3 values for each sensor, and rounds
//get the average of the first sensor value in the OLDEST three arrays
if((~array[0][0]).notNil
&& (~array[1][0]).notNil
&& (~array[2][0]).notNil, { //avoid nil-related errors
~sensorOLD0 =
[~array[0][0], ~array[1][0], ~array[2][0]].mean;
//round that number to whole number
~sensorOLD0 = ~sensorOLD0.round;
//and post it
("sensorOLD0 is " ++ ~sensorOLD0).postln;
});
//and again...
if((~array[0][1]).notNil && (~array[1][1]).notNil && (~array[2][1]).notNil, {
~sensorOLD1 = [~array[0][1], ~array[1][1], ~array[2][1]].mean;
~sensorOLD1 = ~sensorOLD1.round;
("sensorOLD1 is " ++ ~sensorOLD1).postln;
});
if((~array[0][2]).notNil && (~array[1][2]).notNil && (~array[2][2]).notNil, {
~sensorOLD2 = [~array[0][2], ~array[1][2], ~array[2][2]].mean;
~sensorOLD2 = ~sensorOLD2.round;
//("sensorOLD2 is " ++ ~sensorOLD2).postln;
});
if((~array[0][3]).notNil && (~array[1][3]).notNil && (~array[2][3]).notNil, {
~sensorOLD3 = [~array[0][3], ~array[1][3], ~array[2][3]].mean;
~sensorOLD3 = ~sensorOLD3.round;
//("sensorOLD3 is " ++ ~sensorOLD3).postln;
});
if((~array[0][4]).notNil && (~array[1][4]).notNil && (~array[2][4]).notNil, {
~sensorOLD4 = [~array[0][4], ~array[1][4], ~array[2][4]].mean;
~sensorOLD4 = ~sensorOLD4.round;
//("sensorOLD4 is " ++ ~sensorOLD4).postln;
});
if((~array[0][5]).notNil && (~array[1][5]).notNil && (~array[2][5]).notNil, {
~sensorOLD5 = [~array[0][5], ~array[1][5], ~array[2][5]].mean;
~sensorOLD5 = ~sensorOLD5.round;
//("sensorOLD5 is " ++ ~sensorOLD5).postln;
});
//get the average of the first sensor value in the NEWEST three arrays
if((~array[3][0]).notNil
&& (~array[4][0]).notNil
&& (~array[5][0]).notNil, {
~sensorNEW0 = [~array[3][0], ~array[4][0], ~array[5][0]].mean;
//round that number to whole number
~sensorNEW0 = ~sensorNEW0.round;
//and post it
("sensorNEW0 is " ++ ~sensorNEW0).postln;
});
//...and again
if((~array[3][1]).notNil && (~array[4][1]).notNil && (~array[5][1]).notNil, {
~sensorNEW1 = [~array[3][1], ~array[4][1], ~array[5][1]].mean;
~sensorNEW1 = ~sensorNEW1.round;
//("sensorNEW1 is " ++ ~sensorNEW1).postln;
});
if((~array[3][2]).notNil && (~array[4][2]).notNil && (~array[5][2]).notNil, {
~sensorNEW2 = [~array[3][2], ~array[4][2], ~array[5][2]].mean;
~sensorNEW2 = ~sensorNEW2.round;
//("sensorNEW2 is " ++ ~sensorNEW2).postln;
});
if((~array[3][3]).notNil && (~array[4][3]).notNil && (~array[5][3]).notNil, {
~sensorNEW3 = [~array[3][3], ~array[4][3], ~array[5][3]].mean;
~sensorNEW3 = ~sensorNEW3.round;
//("sensorNEW3 is " ++ ~sensorNEW3).postln;
});
if((~array[3][4]).notNil && (~array[4][4]).notNil && (~array[5][4]).notNil, {
~sensorNEW4 = [~array[3][4], ~array[4][4], ~array[5][4]].mean;
~sensorNEW4 = ~sensorNEW4.round;
//("sensorNEW4 is " ++ ~sensorNEW4).postln;
});
if((~array[3][5]).notNil && (~array[4][5]).notNil && (~array[5][5]).notNil, {
~sensorNEW5 = [~array[3][5], ~array[4][5], ~array[5][5]].mean;
~sensorNEW5 = ~sensorNEW5.round;
//("sensorNEW5 is " ++ ~sensorNEW5).postln;
});
I then take the information about the newest and oldest values and place that in a series of short, two-index arrays:
if((~sensorOLD0.notNil) && (~sensorNEW0.notNil), { //make an array of 2 values, for comparison's sake: the old (averaged & rounded) value and the new (averaged & rounded) value
~compareSensor0 = [~sensorOLD0, ~sensorNEW0];
//("compare sensor 0 = " ++ ~compareSensor0).postln;
});
if((~sensorOLD1.notNil) && (~sensorNEW1.notNil), {//do this for each stretch sensor
~compareSensor1 = [~sensorOLD1, ~sensorNEW1];
//("compare sensor 1 = " ++ ~compareSensor1).postln;
});
if((~sensorOLD2.notNil) && (~sensorNEW2.notNil), {
~compareSensor2 = [~sensorOLD2, ~sensorNEW2];
//("compare sensor 2 = " ++ ~compareSensor2).postln;
});
if((~sensorOLD3.notNil) && (~sensorNEW3.notNil), {
~compareSensor3 = [~sensorOLD3, ~sensorNEW3];
//("compare sensor 3 = " ++ ~compareSensor3).postln;
});
if((~sensorOLD4.notNil) && (~sensorNEW4.notNil), {
~compareSensor4 = [~sensorOLD4, ~sensorNEW4];
//("compare sensor 4 = " ++ ~compareSensor4).postln;
});
if((~sensorOLD5.notNil) && (~sensorNEW5.notNil), {
~compareSensor5 = [~sensorOLD5, ~sensorNEW5];
//("compare sensor 5 = " ++ ~compareSensor5).postln;
});
Finally, for each of these small arrays, I test to see whether the new value is greater than, less than or equal to the old value (indicating, respectively, an inspiration, expiration or no change.
if(~compareSensor0[0] < ~compareSensor0[1], { //if the old value is less than the new value
~count0 = 1; //return a 1 to indicate an inspiration
//subtract the old value from the new value in the array to see depth:
~depthAtZeroInspiration = ~compareSensor0[1] - ~compareSensor0[0];
//"the depth of the inspiration at sensor 0 is ".post;
//~depthAtZeroInspiration.postln;
}, {
//if the old value is NOT less than the new value, check to see if the old value is > the new value.
if(~compareSensor0[0] > ~compareSensor0[1], {//if the old value is greater than the new value
~count0 = -1;//return -1 to show an exhalation
//depth of exhalation. Note that this will return a NEGATIVE NUMBER:
~depthAtZeroExhalation = ~compareSensor0[1] - ~compareSensor0[0];
//"the depth of the exhalation at sensor 0 is ".post;
//~depthAtZeroExhalation.postln;
}, {
//otherwise, if the sensors show no change, return a zero to indicate no
~count0 = 0;
~depthAtZeroInspiration = 0; breath
~depthAtZeroExhalation = 0;
//"depth at zero = 0".postln});
});
});
No comments:
Post a Comment