0
votes

I have a binary data file containing a header followed by a bunch of five-byte data records. Each byte is the measurement of a different quantity, all taken at the same time1. I want to display a graph with five lines, showing how each quantity changes over time. The start time of the data file is encoded in some bytes at the beginning of the file, and I know that each record is taken 2 seconds after the previous one, but the records don't have a separate timestamp.

I can get this to plot more-or-less like I want by ignoring the actual time completely; if you set xdata time, then gnuplot does the Right Thing. However, it can't display the Right Time. On the other hand, if you set xrange ["*time1*":"*time2*"], then you get no graphs at all, because gnuplot doesn't know that the un-timestamped records correspond to those times.

Is there a way to tell gnuplot that binary records in a file start with a particular timestamp, so that they get matched up to the correct xrange?

My binary data (50-byte header = 0003 signature, uint16 year, uint8 month, uint8 day, uint8 hour, uint8 minute, uint8 second, other random stuff, then 5-byte records):

00000000  03 00 e3 07 0b 0f 16 22  13 63 97 00 00 fc 78 00  |.......".c....x.|
00000010  00 60 5c 04 00 00 00 00  00 63 00 00 00 00 00 00  |.`\......c......|
00000020  00 00 00 00 00 00 00 00  ff ff ff 00 00 ff ff ff  |................|
00000030  00 00 61 3a 00 00 00 61  3a 00 00 00 61 3b 00 00  |..a:...a:...a;..|
00000040  00 61 3b 00 00 00 60 3c  00 00 00 60 3c 00 00 00  |.a;...`<...`<...|
00000050  60 3c 00 00 00 60 3c 00  00 00 60 3d 00 00 00 60  |`<...`<...`=...`|
00000060  3d 00 00 00 60 3c 00 00  00 60 3c 00 00 00 61 3e  |=...`<...`<...a>|
00000070  00 00 00 61 3e 00 00 00  61 3f 00 00 00 61 3f 00  |...a>...a?...a?.|
00000080  00 00 61 3f 00 02 00 61  3f 00 02 00 61 3f 00 01  |..a?...a?...a?..|
00000090  00 61 3f 00 01 00 61 3f  00 00 00 61 3f 00 00 00  |.a?...a?...a?...|
000000a0  61 3f 00 00 00 61 3f 00  00 00 61 41 00 01 00 61  |a?...a?...aA...a|
000000b0  41 00 01 00 60 42 00 00  00 60 42 00 00 00 60 40  |A...`B...`B...`@|
000000c0  00 00 00 60 40 00 00 00  60 3d 00 00 00 60 3d 00  |...`@...`=...`=.|
000000d0  00 00 60 3c 00 00 00 60  3c 00 00 00 60 3c 00 00  |..`<...`<...`<..|
000000e0  00 60 3c 00 00 00 60 3c  00 00 00 60 3c 00 00 00  |.`<...`<...`<...|
000000f0  60 3d 00 00 00 60 3d 00  00 00 60 3e 00 00 00 60  |`=...`=...`>...`|
00000100  3e 00 00 00 60 3e 00 00  00 60 3e 00 00 00 60 3f  |>...`>...`>...`?|
00000110  00 00 00 60 3f 00 00 00  60 40 00 00 00 60 40 00  |...`?...`@...`@.|
00000120  00 00 60 40 00 05 00 60  40 00 05 00 60 40 00 04  |..`@...`@...`@..|
00000130  00 60 40 00 04 00 60 3f  00 00 00 60 3f 00 00 00  |.`@...`?...`?...|
00000140  60 40 00 00 00 60 40 00  00 00 60 3f 00 00 00 60  |`@...`@...`?...`|
00000150  3f 00 00 00 60 3e 00 00  00 60 3e 00 00 00 60 3e  |?...`>...`>...`>|
00000160  00 0f 00 60 3e 00 0f 00  60 3c 00 00 00 60 3c 00  |...`>...`<...`<.|
00000170  00 00 60 3d 00 00 00 60  3d 00 00 00 60 3e 00 01  |..`=...`=...`>..|
00000180  00 60 3e 00 01 00 60 3e  00 18 00 60 3e 00 18 00  |.`>...`>...`>...|
00000190  60 3e 00 02 00 60 3e 00  02 00 60 3e 00 03 00 60  |`>...`>...`>...`|

My gnuplot script:

#!/usr/bin/gnuplot

fn="20191115223419"

set title "Heart Rate, O2, Motion"
set xlabel "Time"

set xdata time
set timefmt "%Y%m%d%H%M%S"
set xrange ["20191115223419":"20191116071015"]
set format x "%H:%M"

set yrange [40:120]     # Heart rate
set y2range [50:100]    # O2 saturation

plot \
     fn binary skip=0x32 format="%5uint8" using 0:2 with lines lt rgb "red" title "HR", \
     fn binary skip=0x32 format="%5uint8" using 0:(($4)/4+40) with lines lt rgb "orange" title "Motion", \
     fn binary skip=0x32 format="%5uint8" using 0:1 with lines lt rgb "gray60" title "O2" axes x1y2

pause -1 "Hit <ENTER> to continue..."

It plots as desired if I comment out the xrange line.

I know I could easily write a script to munge the data into better form, and perhaps that's the thing to do: Python it into a better string, then gnuplot that. But I'd be delighted if I could just tell gnuplot alone to do what I want.


1The 5 bytes are actually O2 saturation, pulse rate, dummy (always zero), motion sensor, and another dummy byte. My gnuplot script only plots the 3 non-dummy values.
2

2 Answers

0
votes

Not actually tested since I don't have your data file...

You don't need set xdata time for this. I'll leave extracting the start time as a separate problem and assume you have it in some usable form at the time you run the script. The incremental time for each record is 2 seconds, so the full time at each point is start + 2 * $0.

start = strptime("%Y%m%d%H%M%S", "20191115223419") # start time in seconds
set xtics time format "%H%M%S"
set xrange [start : start + whatever]
plot \
 fn binary skip=0x32 format="%5uint8" using (start+2*$0):2 with lines lt rgb "red" title "HR", \
 fn binary skip=0x32 format="%5uint8" using (start+2*$0):(($4)/4+40) with lines lt rgb "orange" title "Motion", \
 fn binary skip=0x32 format="%5uint8" using (start+2*$0):1 with lines lt rgb "gray60" title "O2" axes x1y2
0
votes

Here's a complete gnuplot script to extract the Y/M/D H:M:S data from the binary file and plot the rest of the data, plus a sample image.

#!/usr/bin/gnuplot
#
# This script plots data from a Viatom pulse oximeter (www.viatomtech.com).  The
# Android app extracts recorded data and stores it in an Sqlite3 database, and also
# creates files under /sdcard/PlusebitO2CN with names based on the recording start
# date & time.  These are binary files with a two-byte "signature" of 0x0003; 7 bytes
# of start date/time as uint16:year, uint8 month, day, hour, minute, second; 41 bytes
# of something else ??? and then 5-byte records of Oxygenation, Heart Rate, dummy-1,
# motion-sensor, dummy-2.
#

# Put file name here...everything else is automagic.
#
fn="20191115223419"
#
####################################################

set title "Heart Rate, O2, Motion"
set xlabel "Time"

#
# Get start time from binary file by fake-plotting.  This will
# print a warning message; I don't know how to get rid of it.
#
set term unknown
plot fn binary skip=2 format="%uint16%5uint8" every 1:1:0:0:0:0 \
     using (year=$1):(month=$2):(day=$3):(hour=$4):(minute=$5):(second=$6):1 with candlesticks
# Now put the values we extracted into a single 'YYYYmmddHHMMSS' string
sd=sprintf("%04d%d%d%d%d%d", year, month, day, hour, minute, second )
set term qt

set xdata time
start=strptime("%Y%m%d%H%M%S", sd ) # sd contains YYYYmmddHHMMSS extracted from file
set xtics time format "%H%M%S"
#set timefmt "%Y%m%d%H%M%S"
#set xrange ["20191115223419":"20191116071015"]
set format x "%H:%M"

set yrange [40:120]     # Heart rate
set y2range [50:100]    # O2 saturation

plot \
     fn binary skip=0x32 format="%5uint8" using (start+2*$0):2 with lines lt rgb "red" title "HR", \
     fn binary skip=0x32 format="%5uint8" using (start+2*$0):(($4)/4+40) with lines lt rgb "orange" title "Motion", \
     fn binary skip=0x32 format="%5uint8" using (start+2*$0):1 with lines lt rgb "gray60" title "O2" axes x1y2

pause -1 "Hit <ENTER> to continue..."

And the result: gnuplot heart rate example