The “Crivit Sports” wrist watch HRM (Heart Rate Monitor)
This is a wrist watch that can also display the heart rate BPM (Beats Per Minute).
.
The complete specs and the user manual can be found at http://www.lidl-service.com/cps/rde/xchg/SID-648946E8-5F850FDD/lsp/hs.xsl/product.html?id=47039228
The heart beats are detected by a chest strap included with the watch.
The chest strap have two conductive rubber pads that senses the electrical signals produced by the heart beats. No contact gel is required for the rubber pads.
The link between the chest strap and the wrist watch is wireless, by an RF (Radio Frequency) signal.
.
.
Missing features
Being a very cheap item, it does not have any kind of connectivity, it can not log data, and it can not make charts. It
would have been way more interesting to be able to see a ECG
(ElectroCardioGram) or a BPM chart for the whole day. Could it be
possible?
I couldn't find any online technical documentation about this 'Crivit Sports' model.
.
.
Reverse engineering the RF signal
To receive the RF, a one loop coil was wrapped around the chest strap,
by simply clipping the oscilloscope GND (GrouND) wire alligator to the
tip of the probe, and around the chest strap transmitter.
.
This is the signal received from the chest belt HRM for a constant
heart rate of 100 BPM. The RF carrier is at 110 kHz, 100% AM (Amplitude
Modulated) by a digital signal.
By looking at the received signal for various heart rates, it turns out that the BPM rate is computed by the chest wrap by averaging the last few heart beats, then the resulting number is used to modulate the RF signal like this:
- chest strap monitor’s RF carrier is at 110 kHz, 100% AM modulated
- a bit of 1 is made by a 3 ms ON (100% RF) followed by a 4.8 ms OFF (0% RF)
- a bit of 0 is made by a 7.8 ms OFF (0% RF)
The BPM data is constantly sent about 0.5 to 2 times per second. The delay between two data packets is unrelated with the heart beat. The structure of a packet is:
- one start sync bit with 5ms ON (100% RF) and 4.8ms OFF (0% RF)
- next 6 bits encode the chest strap ID (IDentification). The ID changes randomly each time the battery is disconnected. The observed IDs were all bigger then 48 (first two bits 11)
- the remaining 13 bits encodes the BPM.
This stream of data is received and decoded by the wrist watch, which then display one number, the BPM. Observed BPM displayed range was between 30 and 233. The watch displays the BPM no matter what ID the chest belt randomly picked.
I tried to look at the carrier waveform corresponding to a couple of different BPM numbers, by doing push-ups in order to accelerate the heart beat. My intention was to understand the correspondence between the last 13 bits sent by the chest strap and the BPM number displayed by the wrist watch.
Counting bits after making push-ups is not easy. I couldn’t figure out the encoding scheme.
.
Another more rigorous testing way was necessary. Instead of using real heart signals, a signal generator (RIGOL DG4102) was used to simulate the electrical signals coming from the heart. By contrast with a real heart, the generator can produce any BPM number with high accuracy. The output from the signal generator was connected to the two conductive rubber pads of the chest strap. An one wire loop antenna was wrapped around the chest belt, and the received RF signal was displayed on the oscilloscope (RIGOL DS1054Z).
.
Also, another signal was generated by the second channel of the generator, and was added as a grid (the magenta signal), to ease the task of counting consecutive bits of zero. Each magenta spike is now pointing to a zero or a one bit. The yellow signal in this capture is:
S 111001 0101000100011
Where ‘S’ is the Sync bit, ‘111001’ is the chest strap ID and ‘0101000100011’ is the BPM. For this particular signal, the wrist watch will display one hundred BPM.
.
By varying the period of the fake heart beat generated signal, all possible heart rates were browsed.
The following table...
Read more »
> Wireless code: Should display: Displays as:
> =====================================================
> ...
> 111100 0000101111100 31 95
> 111100 0100101111100 95 95
You made a small mistake, it seems. Actual value for 31 should be 0010101111100.
Coding scheme used here ensures there are no more than three zeros in a row.
Why it decodes that invalid code as 95, though, I have no idea. It can be considered as undefined behaviour in their decoding. "Garbage in - garbage out" should be sufficient explanation in that case. Bad thing they didn't detect and ignore invalid inputs, despite the possibility.