How to analogueRead at 120 Hz sample rate

Hey everyone :slight_smile:

I am currently trying to design a display for ECG and pulse sensors with my BeagleBone Black.

I am totally new to this kind of programming so I began buy reading “Programming the BeagleBone Black - Getting Started with JavaScript and BoneScript” by Simon Monk. I have done all the exercises and then worked on my project.

Here is how it works :

1/ I run a Javascript server on my BBB which read (using b.analogRead) the values from the ECG sensor (plugged in P9_36) and from two others pulse sensors (in P9_33 and P9_35) with a function I call every 8 ms (with setInterval)

2/ I run an html file to access my server to display the values

Here are my problems :

In the 1/ step I have set my program to read the values of my sensors at 8ms so that my sample rate is about 120Hz (which is the minimum I can do to process ECG) but when I launch my program for 10 sec I just acquire like 860 to 950 values which correspond more to 10 ms even less.

The first problem is that I always have a different amount of values.

The second problem is that this amount is to low compare to the sampling rate I expect.

My clues for solutions :

I was first thinking that it might due to the BBB which cannot sample at that rate from the ADC, and also the clock inside is a bit rough which explain the inconsistency in the amount of values.

Then I figured out that it might be my program which is not efficient enough.

If anyone has a clue to help me with this problem it would be very nice.

I add my program files (my html/css is not very nice because i did not worked on it yet).

Best regards,
Matthieu Hoel.

The Javascript server :

`

//////////////////////////////////////////////////////////////////////////////////////////////////
// IMPORT : //
// Importing the modules the code requires //
//////////////////////////////////////////////////////////////////////////////////////////////////

//http and file system libraries needed for web server
var app = require(‘http’).createServer(handler);
var fs = require(‘fs’);
//socket.io needed for socket communication with the browser
var io = require(‘socket.io’).listen(app);
//BeagleBone language
var b = require(‘bonescript’);
//Web page that is to be served when a web request comes in
var htmlPage = ‘metrycommented.html’;
//Starts web server listening for request on port 8085
app.listen(8085);

var soc;
var tmr;

//////////////////////////////////////////////////////////////////////////////////////////////////
// HANDLER : //
// Handling any incoming web requests //
// When it receives one, it reads the contents of the file .html or .js or .css or .jpg and //
// sends it to the browser //
//////////////////////////////////////////////////////////////////////////////////////////////////

function handler(req, res)
{
console.log("Received Request: " + req.url);
if(req.url.indexOf(’.html’) != -1)
{
//call to readFile specifies a callback for read being completed
fs.readFile(’.’ + req.url, function (error, data)
{
if (error)
{
//response is used to tell the browser that the page is not ok (status code 404) + JSON content of the pqge
res.writeHead(404, {“Content-type”:“text/plain”});
res.end(“No Html Page Found.”);
}
else
{
//response is used to tell the browser that the page is ok (status code 200)
res.writeHead(200, {‘Content-Type’: ‘text/html’});
//end is used to end the request and at the same time send the whole contents of the file
res.end(data);
}
});
}
else if(req.url.indexOf(’.js’) != -1)
{
console.log("js Request: " + ‘.’ + req.url);
fs.readFile(’.’ + req.url, function (error, data)
{
if (error)
{
res.writeHead(404, {“Content-type”:“text/plain”});
res.end(“No Javascript Page Found.”);
}
else
{
res.writeHead(200, {‘Content-Type’: ‘text/javascript’});
console.log("js send ");
res.end(data);
}

});
}
else if(req.url.indexOf(’.css’) != -1)
{
fs.readFile(’.’ + req.url, function (error, data)
{
if (error)
{
res.writeHead(404, {“Content-type”:“text/plain”});
res.end(“No Css Page Found.”);
}
else
{
res.writeHead(200, {‘Content-Type’: ‘text/css’});
res.end(data);
}

});
}
else if(req.url.indexOf(’.jpg’) != -1)
{
console.log("jpg Request: " + req.url);
fs.readFile(’.’ + req.url, function (error, data)
{
if (error)
{
res.writeHead(404, {“Content-Type”: “image/jpeg”});
res.end(“No Image Page Found.”);
}
else
{
res.writeHead(200, {‘Content-Type’: ‘image/jpeg’});
res.end(data);
}

});
}
else
{
fs.readFile(htmlPage, function(err, data)
{
if (err)
{
res.writeHead(500);
res.end('Error loading file: ’ + htmlPage);
}
else
{
res.writeHead(200);
res.end(data);
}
});
}
}

//////////////////////////////////////////////////////////////////////////////////////////////////
// Filters //
// Sampling rate is 100 Hz //
//////////////////////////////////////////////////////////////////////////////////////////////////

function IIR10Filter (inp) //II order filter using the values from Koh Bee Hock David
{
var inp2 = 0;
//Gains
var dGain1 = 0.569743229;
var dGain2 = 0.45713223;
var dGain3 = 0.391335773;
var dGain4 = 0.35428676;
var dGain5 = 0.337489037;

//Coefficients for the lowpassfilter
var dCoefficient11 = 0.537992527;
var dCoefficient12 = 0.740980389;
var dCoefficient21 = 0.431657124;
var dCoefficient22 = 0.396871795;
var dCoefficient31 = 0.369527377;
var dCoefficient32 = 0.195815713;
var dCoefficient41 = 0.334543036;
var dCoefficient42 = 0.082604006;
var dCoefficient51 = 0.318681417;
var dCoefficient52 = 0.03127473;

var xv1 = [0,0,0];
var yv1 = [0,0,0];
var xv2 = [0,0,0];
var yv2 = [0,0,0];
var xv3 = [0,0,0];
var yv3 = [0,0,0];
var xv4 = [0,0,0];
var yv4 = [0,0,0];
var xv5 = [0,0,0];
var yv5 = [0,0,0];

//Process 1
xv1[0] = xv1[1];
xv1[1] = xv1[2];
xv1[2] = (inp / dGain1);

yv1[0] = yv1[1];
yv1[1] = yv1[2];
yv1[2] = ((xv1[0] + xv1[2]) + 2 * xv1[1] + (dCoefficient11 * yv1[0]) + ( dCoefficient12 * yv1[1]));
inp = yv1[2];

//Process 2
xv2[0] = xv2[1];
xv2[1] = xv2[2];
xv2[2] = (inp / dGain2);

yv2[0] = yv2[1];
yv2[1] = yv2[2];
yv2[2] = ((xv2[0] + xv2[2]) + 2 * xv2[1] + (dCoefficient21 * yv2[0]) + ( dCoefficient22 * yv2[1]));
inp = yv2[2];

//Process 3
xv3[0] = xv3[1];
xv3[1] = xv3[2];
xv3[2] = (inp / dGain3);

yv3[0] = yv3[1];
yv3[1] = yv3[2];
yv3[2] = ((xv3[0] + xv3[2]) + 2 * xv3[1] + (dCoefficient31 * yv3[0]) + ( dCoefficient32 * yv3[1]));
inp = yv3[2];

//Process 4
xv4[0] = xv4[1];
xv4[1] = xv4[2];
xv4[2] = (inp / dGain4);

yv4[0] = yv4[1];
yv4[1] = yv4[2];
yv4[2] = ((xv4[0] + xv4[2]) + 2 * xv4[1] + (dCoefficient41 * yv4[0]) + ( dCoefficient42 * yv4[1]));
inp = yv4[2];

//Process 5
xv5[0] = xv5[1];
xv5[1] = xv5[2];
xv5[2] = (inp / dGain5);

yv5[0] = yv5[1];
yv5[1] = yv5[2];
yv5[2] = ((xv5[0] + xv5[2]) + 2 * xv5[1] + (dCoefficient51 * yv5[0]) + ( dCoefficient52 * yv5[1]));
inp = yv5[2];

inp2 = inp;
inp =0;
return inp2;
}

function LP4Filter (inp)
{ //Butterworth Filter :
//This function uses the Butterworth filter and returns a new value for an individual floating point value.
//Second Order System : Infinite Impulse Response
//Lowpass filter cutoff frequency 27Hz: for noisy environment, to detect heart rate

//Gain for the lowpass filter
var dGain = 8.352218539;

//Coefficients for the bandpassfilter
var dCoefficient1 = -0.0195666466;
var dCoefficient2 = -0.0667120257;
var dCoefficient3 = -0.5169062239;
var dCoefficient4 = -0.3124737907;

var xv = [0,0,0,0,0];
var yv = [0,0,0,0,0];

//Process
xv[0] = xv[1];
xv[1] = xv[2];
xv[2] = xv[3];
xv[3] = xv[4];
xv[4] = (inp / dGain);

yv[0] = yv[1];
yv[1] = yv[2];
yv[2] = yv[3];
yv[3] = yv[4];
yv[4] = (xv[0] + xv[4]) + 4 * (xv[1] + xv[3]) + 6 * xv[2] + ( dCoefficient1 * yv[0]) + ( dCoefficient2 * yv[1]) + ( dCoefficient3 * yv[2]) + ( dCoefficient4 * yv[3]);
inp = yv[4];

return inp;
}

function LPFilter (inp) //Lowpass filter cutoff frequency 27Hz
{
//Gain for the lowpass filter
var dGain = 3.024048313;

//Coefficients for the lowpassfilter
var dCoefficient1 =-0.1754120032;
var dCoefficient2 = -0.1473181871;

var xv = [0,0,0];
var yv = [0,0,0];

//Process
xv[0] = xv[1];
xv[1] = xv[2];
xv[2] = (inp / dGain);

yv[0] = yv[1];
yv[1] = yv[2];
yv[2] = ((xv[0] + xv[2]) + 2 * xv[1] + (dCoefficient1 * yv[0]) + ( dCoefficient2 * yv[1]));
inp = yv[2];

return inp;
}

function HP4Filter (inp)
{ //Butterworth Filter :
//This function uses the Butterworth filter and returns a new value for an individual floating point value.
//Second Order System : Infinite Impulse Response
//Highpass filter cutoff frequency 0.5Hz: filtering for noisy environment, to detect heart rate

//Gain for the bandpass filter
var dGain = 1.041903016;

//Coefficients for the bandpassfilter
var dCoefficient1 = -0.9211819292;
var dCoefficient2 =3.7603495077;
var dCoefficient3 = -5.7570763791;
var dCoefficient4 = 3.9179078654;

var xv = [0,0,0,0,0];
var yv = [0,0,0,0,0];

//Process
xv[0] = xv[1];
xv[1] = xv[2];
xv[2] = xv[3];
xv[3] = xv[4];
xv[4] = (inp / dGain);

yv[0] = yv[1];
yv[1] = yv[2];
yv[2] = yv[3];
yv[3] = yv[4];
yv[4] = (xv[0] + xv[4]) - 4 * (xv[1] + xv[3]) + 6 * xv[2] + ( dCoefficient1 * yv[0]) + ( dCoefficient2 * yv[1]) + ( dCoefficient3 * yv[2]) + ( dCoefficient4 * yv[3]);
inp = yv[4];

return inp;
}

function HPFilter (inp) //Highpass filter cutoff frequency 0.5Hz
{
//Gain for the highpass filter
var dGain = 1.022463023;

//Coefficients for the highpassfilter
var dCoefficient1 = -0.9565436765;
var dCoefficient2 = 1.9555782403;

var xvh1 = [0,0,0];
var yvh1 = [0,0,0];
var xvh2 = [0,0,0];
var yvh2 = [0,0,0];

//Process
xvh1[0] = xvh1[1];
xvh1[1] = xvh1[2];
xvh1[2] = (inp / dGain);

yvh1[0] = yvh1[1];
yvh1[1] = yvh1[2];
yvh1[2] = ((xvh1[0] + xvh1[2]) - 2 * xvh1[1] + (dCoefficient1 * yvh1[0]) + ( dCoefficient2 * yvh1[1]));
inp = yvh1[2];

//Process
xvh2[0] = xvh2[1];
xvh2[1] = xvh2[2];
xvh2[2] = (inp / dGain);

yvh2[0] = yvh2[1];
yvh2[1] = yvh2[2];
yvh2[2] = ((xvh2[0] + xvh2[2]) - 2 * xvh2[1] + (dCoefficient1 * yvh2[0]) + ( dCoefficient2 * yvh2[1]));
inp = yvh2[2];

return inp;
}

//////////////////////////////////////////////////////////////////////////////////////////////////
// PEAK DETECTION / Pulse transit time: //
// Mean chanel 1, 2, 3 //
// Standard deviation chanel 1, 2, 3 //
//////////////////////////////////////////////////////////////////////////////////////////////////

//Initialize lookforpeak so that it enter in the first if loop during peak detection
var lookforpeak1 = 1; var lookforpeak2 = 1; var lookforpeak3 = 1;
var pos=0;
//Initialize the max value and position (peak coordinates)
var mxval1 = 0; var mxval2 = 0; var mxval3 = 0;
var mxpos1 = 0; var mxpos2 = 0; var mxpos3 = 0;

//Initialize the threshold value
var threshold1 = 0.03; var threshold2 = 0.03; var threshold3 = 0.03;

//Array in which is stored the peak values and position
var pkval1 = new Array (0); var pkval2 = new Array (0); var pkval3 = new Array (0);
var pkpos1 = new Array (0); var pkpos2 = new Array (0); var pkpos3 = new Array (0);

//Initialize the min value and position (valley coordinates)
var mnval1 = 1; var mnval2 = 1; var mnval3 = 1;
var mnpos1 = 0; var mnpos2 = 0; var mnpos3 = 0;

//Array in which is stored the valley values and position
var vyval1 = new Array (0); var vyval2 = new Array (0); var vyval3 = new Array (0);
var vypos1 = new Array (0); var vypos2 = new Array (0); var vypos3 = new Array (0);

var t1 = new Array (0); var t2 = new Array (0); var t3 = new Array (0);

//Missed peaks on each chanel
var Miss1=0; var Miss2=0; var Miss3=0;

//Mean of each chanel
var Mean1=0; var Mean2=0; var Mean3=0;

//Standard deviation of each chanel
var Std1=0; var Std2=0; var Std3=0;

//Number of peaks on each chanel
var N1=0, N2=0, N3=0;
var win1=0;

//////////////////////////////////////////////////////////////////////////////////////////////////
// Timers //
// //
//////////////////////////////////////////////////////////////////////////////////////////////////

//Take the time duration parametre
function handleStartTimer(duration)
{
N1=0;
N2=0;
N3=0;
pos=0;
if (duration == -1)
{
handleCancelTimer();
}
else
{
//Executes “checkInputs” fonction at 8 ms intervals => 120Hz sampling
tmr = setInterval(checkInputs, 8);
//If duration is not a number timer is set to default value 30 seconds
if (isNaN(duration))
{
setTimeout(handleCancelTimer, 30000);
}
//Convert duration entered by user in seconds
else
{
tmrTL = setTimeout(handleCancelTimer, duration*1000);
}
}
}
var dbg = 0;

function handleCancelTimer()
{
console.log("p: " + pos + " dbg: " + dbg);

clearInterval(tmr);

if (t1.length>0)
{
Mean1 = 0;
Std1 = 0;
for (var i=0; i < t1.length; i++)
{
// calculate mean of signal 1
Mean1 += t1[i];
Mean1 = Mean1 /t1.length;
// calculate standard deviation of signal 1
Std1 += (t1[i]-Mean1)*(t1[i]-Mean1);
Std1 = Math.sqrt(Std1/(t1.length-1));
}
}
else
{
Mean1 = -1;
Std1 = -1;
}

if (t2.length>0)
{
Mean2 = 0;
Std2 = 0;
for (var i=0; i < t2.length; i++)
{
// calculate mean of signal 2
Mean2 += (t2[i]) / (t2.length);
Mean2 = Mean2 /t2.length;
// calculate standard deviation of signal 2
Std2 += (t2[i]-Mean2)*(t2[i]-Mean2);
Std2 = Math.sqrt(Std2/(t2.length-1));
}
}
else
{
Mean2 = -1;
Std2 = -1;
}

if (t3.length>0)
{
Mean3 = 0;
Std3 = 0;
for (var i=0; i < t3.length; i++)
{
// calculate mean of signal 3
Mean3 += t3[i];
Mean3 = Mean3 /t3.length;
// calculate standard deviation of signal 3
Std3 += (t3[i]-Mean3)*(t3[i]-Mean3);
Std3 = Math.sqrt(Std3/(t3.length-1));
}
}
else
{
Mean3 = -1;
Std3 = -1;
}

//Board emit the results in JSON format
soc.emit(“resultUpdate”, ‘{“result”:“Mean2”, “value”:’ + Mean2 + ‘}’);
soc.emit(“resultUpdate”, ‘{“result”:“Mean3”, “value”:’ + Mean3 + ‘}’);
soc.emit(“resultUpdate”, ‘{“result”:“Std2”, “value”:’ + Std2 + ‘}’);
soc.emit(“resultUpdate”, ‘{“result”:“Std3”, “value”:’ + Std3 + ‘}’);
soc.emit(“resultUpdate”, ‘{“result”:“Miss2”, “value”:’ + Miss2 + ‘}’);
soc.emit(“resultUpdate”, ‘{“result”:“Miss3”, “value”:’ + Miss3 + ‘}’);
}

//////////////////////////////////////////////////////////////////////////////////////////////////
// ON CONNECT : //
// Automatically called when START is clicked on the web interface //
// Call the Start timer handler //
//////////////////////////////////////////////////////////////////////////////////////////////////

function onConnect(socket)
{
//Specify the commands to handle and associate them with a function (here the timer)
socket.on(‘startTimer’, handleStartTimer);
soc = socket;
}

function checkInputs()
{
// auto ends at 5min
pos++;
//reading sensor 1: ECG
b.analogRead(“P9_36”,printVoltage1);
//reading sensor 2: BioS
b.analogRead(“P9_33”,printVoltage2);
//reading sensor 3: PO
b.analogRead(“P9_35”,printVoltage3);
}

//Sensor 1: ECG
function printVoltage1(reading)
{
if (!reading.err)
{
//var newValue = IIR10Filter(reading.value*1.8)0.05; // best for now with drift
//var newValue = HPFilter(IIR10Filter(reading.value)); // Try to reduce baseline drift
//var newValue = HPFilter(LP4Filter(reading.value
1.8)*300)400; //cleaner
//var newValue = HPFilter(LPFilter(reading.value
1.8)400); // a bit dirty
//var newValue = LP4Filter(reading.value
1.8);

var newValue = reading.value; //Display without filters
//Board emit the filtered value converted as a string with 3 decimals
soc.emit(“pinUpdate”, ‘{“pin”:“P9_36”, “value”:’ + newValue.toFixed(3) + ‘}’);

dbg++; //Is incremented each time a new value is read from the board, helps to check the sample rate
win1++;

//Goes into this loop the first time as lookforpeak is initialize at 1
if (lookforpeak1==1)
{
// Adaptive Threshold
if (pkval1.length>0)
{
threshold1 = 0.7 * (pkval1[pkval1.length-1]-vyval1[vyval1.length-1]);
if (threshold1 < 0.01)
{
threshold1 = 0.01;
}
if (threshold1 > 0.15)
{
threshold1 = 0.15;
}
}
// Track, max value update
if (newValue > mxval1)
{
mxval1 = newValue;
mxpos1 = pos;
}
// peak detection
if (newValue < (mxval1-threshold1))
{
pkval1.push(mxval1);
pkpos1.push(mxpos1);
N1++;
//Board emit the peak (+1 each time a new pick is found)
soc.emit(“resultUpdate”, ‘{“result”:“N1”, “value”:’ + N1 + ‘}’);
mnval1 = mxval1;
lookforpeak1 = 0;
win1 = 0;
}
}
else
{
// track
if (newValue < mnval1)
{
mnval1 = newValue;
mnpos1 = pos;
}
// valley detection
if (newValue > (mnval1+threshold1))
{
vyval1.push(mnval1);
vypos1.push(mnpos1);
mxval1 = mnval1;
lookforpeak1 = 1;
}
}
}
}

//Sensor 2: Bios Magnetic (SQUID)
function printVoltage2(reading)
{
if (!reading.err)
{
var newValue = reading.value;
soc.emit(“pinUpdate”, ‘{“pin”:“P9_33”, “value”:’ + newValue.toFixed(3) + ‘}’);

if (lookforpeak2==1)
{
// adaptive threshold
if (pkval2.length>0)
{
threshold2 = 0.7 * (pkval2[pkval2.length-1]-vyval2[vyval2.length-1]);
if (threshold2 < 0.01) threshold2 = 0.01;
if (threshold2 > 0.15) threshold2 = 0.15;
}
// track
if (newValue > mxval2)
{
mxval2 = newValue;
mxpos2 = pos;
}
// peak detection
if (newValue < (mxval2-threshold1))
{
pkval2.push(mxval2);
pkpos2.push(mxpos2);
mnval2 = mxval2;
N2++;
var delay1 = 0;
delay1 = mxpos1-mxpos2;
soc.emit(“resultUpdate”, ‘{“result”:“delay1”, “value”:’ + delay1 + ‘}’);
soc.emit(“resultUpdate”, ‘{“result”:“N2”, “value”:’ + N2 + ‘}’);
lookforpeak2 = 0;
if (win1>5)
{
Miss2++; //missed
}
else
{
t2.push(win1);
}
}
}
else
{
// track
if (newValue < mnval2)
{
mnval2 = newValue;
mnpos2 = pos;
}
// valley detection
if (newValue > (mnval2+threshold2))
{
vyval2.push(mnval2);
vypos2.push(mnpos2);
mxval2 = mnval2;
lookforpeak2 = 1;
}
}
}
}

//Sensor 3: Pulse Oximetry
function printVoltage3(reading)
{
if (!reading.err)
{
var newValue = reading.value*1.800;
soc.emit(“pinUpdate”, ‘{“pin”:“P9_35”, “value”:’ + newValue.toFixed(3) + ‘}’);

if (lookforpeak3==1)
{
// adaptive threshold
if (pkval3.length>0)
{
threshold3 = 0.7 * (pkval3[pkval3.length-1]-vyval3[vyval3.length-1]);
if (threshold3 < 0.01) threshold3 = 0.01;
if (threshold3 > 0.15) threshold3 = 0.15;
}
// track
if (newValue > mxval3)
{
mxval3 = newValue;
mxpos3 = pos;
}
// peak detection
if (newValue < (mxval3-threshold3))
{
pkval3.push(mxval3);
pkpos3.push(mxpos3);
mnval3 = mxval3;
N3++;
var delay2 = 0;
delay2 = mxpos2-mxpos3;
var delay3 = 0;
delay3 = mxpos1-mxpos3;
soc.emit(“resultUpdate”, ‘{“result”:“delay2”, “value”:’ + delay2 + ‘}’);
soc.emit(“resultUpdate”, ‘{“result”:“delay3”, “value”:’ + delay3 + ‘}’);
soc.emit(“resultUpdate”, ‘{“result”:“N3”, “value”:’ + N3 + ‘}’);
lookforpeak3 = 0;
if (win1>5)
{
Miss3++; //missed
}
else {
t3.push(win1);
}
}
}
else
{
// track
if (newValue < mnval3)
{
mnval3 = newValue;
mnpos3 = pos;
}
// valley detection
if (newValue > (mnval3+threshold3))
{
vyval3.push(mnval3);
vypos3.push(mnpos3);
mxval3 = mnval3;
lookforpeak3 = 1;
}
}
}
}

//Ensures that onConnect gets called when communication is established
io.sockets.on(‘connection’, onConnect);

`

The HTML file to access it:

`

BeagleBone Black

BeagleBone Black :
Signal acquisition

Datas

Time in seconds:

       
  • Delay ECG / Bios = -
  • Delay ECG / PO = -
  • Delay Bios / PO = -
  • ECG Peaks = -
  • BioS Peaks = -
  • PO Peaks = -
  • Mean Bios = -
  • Mean PO = -
  • STD Bios = -
  • STD PO = -
  • Missed Channel 2 = -
  • Missed Channel 3 = -
  • P9_36 Value = -
  • P9_33 Value = -
  • P9_35 Value = -

Display

`

The CSS page :

`

  • { padding: 0; margin: 0; vertical-align: top; }

body {
background: url(background.png) repeat-x;
font: 18px/1.5em “proxima-nova”, Helvetica, Arial, sans-serif;
}

a { color: #069; }

h3 {
margin-left: 30px;
font: normal 26px “omnes-pro”, Helvetica, Arial, sans-serif;
color: #666;
}

p {
margin-top: 10px;
}

button {
font-size: 18px;
padding: 1px 7px;
}

input {
font-size: 18px;
}

input[type=checkbox] {
margin: 7px;
}

#header {
position: relative;
width: 900px;
margin: auto;
}

#header h2 {
margin-left: 10px;
vertical-align: middle;
font-size: 42px;
font-weight: bold;
text-decoration: none;
color: #000;
}

#content {
width: 880px;
margin: 0 auto;
padding: 10px;
}

#footer {
margin-top: 25px;
margin-bottom: 10px;
text-align: center;
font-size: 12px;
color: #999;
}

.demo-container {
float: right;
box-sizing: border-box;
width: 850px;
height: 450px;
padding: 20px 15px 15px 15px;
margin: 15px auto 30px auto;
border: 1px solid #ddd;
background: #fff;
background: linear-gradient(#f6f6f6 0, #fff 50px);
background: -o-linear-gradient(#f6f6f6 0, #fff 50px);
background: -ms-linear-gradient(#f6f6f6 0, #fff 50px);
background: -moz-linear-gradient(#f6f6f6 0, #fff 50px);
background: -webkit-linear-gradient(#f6f6f6 0, #fff 50px);
box-shadow: 0 3px 10px rgba(0,0,0,0.15);
-o-box-shadow: 0 3px 10px rgba(0,0,0,0.1);
-ms-box-shadow: 0 3px 10px rgba(0,0,0,0.1);
-moz-box-shadow: 0 3px 10px rgba(0,0,0,0.1);
-webkit-box-shadow: 0 3px 10px rgba(0,0,0,0.1);
}

.demo-placeholder {
width: 100%;
height: 100%;
font-size: 14px;
line-height: 1.2em;
}

.legend table {
border-spacing: 5px;
}

.header
{
float: top;
text-align: center
border: 1px solid black;
height: 100px;
}

.datas
{
float: left;
width: 300px;
border: 1px solid black;
position: absolute;
bottom: 0;
;
}

.graphtitledatas
{
float: left;
width: 300px;
}

.graphtitledisplay
{
float: right;
width: 850px;
}

h1 { text-align: center }
h2 { text-align: center }

`

I feel like the problem is coming from the javascript because I implemented a new moving average just after the acquisition and I think it slowed the sampling even more. :frowning:

Anyone with an idea?

I think javascript is not the best implementation platform for this
code because you need guaranteed latency, even though 8ms period is
not very demanding. You could try playing with the interpreter process
priority and scheduling algorithm, but in the end you probably should
start looking at implementing this in a compiled language (C/C++).

Thank you for your answer.

Do you know if I will be able to do the same stuff with a server on one side and an html on the other to display real time acquisition ?

It is a 3 month project I realy feel like I lost a month implementing all of this with Java script.

Thanks again.

Best regards,
Matthieu Hoel.

Thank you for your answer.

Do you know if I will be able to do the same stuff with a server on one side and an html on the other to display real time acquisition ?

It is a 3 month project I realy feel like I lost a month implementing all of this with Java script.

There are several ways you can approach this. One that sticks in my mind would be to:

a) Use a compiled language such as C/C++ to do the actual data acquisition. The application would then write values with perhaps timestamps to a file created in memory.

b) Nodejs with fs.watch() method + socket.io.to stream data to the client browser. Where client side javascript can deal with all the heavy work.

So, while there may be some latency between the actual data acquisition application, and the client side browser. The data could be displayed in a reasonably timely fashion. With time stamp information. However, it is also a reasonable assumption that if you need to make real time “adjustments” from the client side . . . this would not work so well. socket.io may be what some consider “real-time” but the reality is that there are sometimes, and sometimes often latencies of 100ms + between server / client. Even on a closed local network.

Hi Matthieu!

I missed your post on the FreeBASIC forum, sorry. Unfortunately you deleted the text.

I think you need not redo all your work. It should be possible to reach your target when you organize the data flow as William said: “Where client side javascript can deal with all the heavy work.”.

The problem is to fetch the data on BBB in real time, which is impossible with sysfs. Instead use libpruio. You’ll have better control over the ADC subsystem and you can read the data asynchronously from a ring buffer. AFAIK there’s no (complete) JavaScript binding jet, so this code should be done in C/C++ or FreeBASIC. (There’s also a Python binding, which seems to work in this project).

BR

Hey Kimg TJF !

I saw your name a lot of times this past month :stuck_out_tongue: You are doing a lot for the newbies like me it is very nice.

I deleted the code because one of my internship supervisor asked me. I said that it is confidential work but I talk with him and I really don’t see what could be confidential in my code but never mind…

I have to admit that I stop working on libpruio cause it is at the limit of my abilities in computer science and programming in general and also because I realized that 120 Hz were enough for me and I was not very far from it.

I am going to check the ring buffer and redo my work with libpruio.

Thank you very much for your answer !

PS: the project you linked is very nice :slight_smile:

Hello :slight_smile:

I am going to check the b) way and if still doesn’t work i will finally try with libpruio and C or C++ as I should have done earlier.

Thank you for your answer and precious help.

I am using BBB as a server connected to the host PC by USB cable for development purpose. Do you think it might be why I have so much latency and it would be better if I connect both of them to a wifi router?

Sorry if my question sounds noob.