3

我的应用程序正在从智能心脏设备接收信息。现在我可以看到脉冲值了。你能帮我解析 RR Interval 值吗?我如何检查设备是否支持 RR 间隔值?

你的任何建议

谢谢

4

5 回答 5

11

你检查过蓝牙规格吗?下面的示例代码是用 C# 编写的,但我认为它显示了解析每个心率数据包中数据的方法。

//first byte of heart rate record denotes flags
byte flags = heartRateRecord[0];

ushort offset = 1;

bool HRC2 = (flags & 1) == 1;
if (HRC2) //this means the BPM is un uint16
{
    short hr = BitConverter.ToInt16(heartRateRecord, offset);
    offset += 2;
}
else //BPM is uint8
{
    byte hr = heartRateRecord[offset];
    offset += 1;
}

//see if EE is available
//if so, pull 2 bytes
bool ee = (flags & (1 << 3)) != 0;
if (ee)
    offset += 2;

//see if RR is present
//if so, the number of RR values is total bytes left / 2 (size of uint16)
bool rr = (flags & (1 << 4)) != 0;
if (rr)
{
    int count = (heartRateRecord.Length - offset)/2;
    for (int i = 0; i < count; i++)
    {
        //each existence of these values means an R-Wave was already detected
        //the ushort means the time (1/1024 seconds) since last r-wave
        ushort value = BitConverter.ToUInt16(heartRateRecord, offset);

        double intervalLengthInSeconds = value/1024.0;
        offset += 2;
    }
}
于 2013-10-30T20:31:36.597 回答
2

这篇文章有点旧,但还没有给出完整的答案。当我遇到这篇文章时,它确实对我有所帮助,我想分享我的最终代码。希望它会帮助其他人。

Daniel Judge 提供的代码实际上是正确的,但正如他已经写的那样,它是 C#。与 Simon M 最后提出的代码相比,他的代码要好一些,因为 Daniel Judge 的代码考虑到一条消息中可以有两个以上的 RR 值。这是Heart_rate_measurement 特性的实际规格

我已将 Daniel Judge 他的代码翻译成 Objective-C:

// Instance method to get the heart rate BPM information
- (void) getHeartBPMData:(CBCharacteristic *)characteristic error:(NSError *)error
{
    // Get the BPM //
    // https://developer.bluetooth.org/gatt/characteristics/Pages/CharacteristicViewer.aspx?u=org.bluetooth.characteristic.heart_rate_measurement.xml //

    // Convert the contents of the characteristic value to a data-object //
    NSData *data = [characteristic value];

    // Get the byte sequence of the data-object //
    const uint8_t *reportData = [data bytes];

    // Initialise the offset variable //
    NSUInteger offset = 1;
    // Initialise the bpm variable //
    uint16_t bpm = 0;


    // Next, obtain the first byte at index 0 in the array as defined by reportData[0] and mask out all but the 1st bit //
    // The result returned will either be 0, which means that the 2nd bit is not set, or 1 if it is set //
    // If the 2nd bit is not set, retrieve the BPM value at the second byte location at index 1 in the array //
    if ((reportData[0] & 0x01) == 0) {
        // Retrieve the BPM value for the Heart Rate Monitor
        bpm = reportData[1];

        offset = offset + 1; // Plus 1 byte //
    }
    else {
        // If the second bit is set, retrieve the BPM value at second byte location at index 1 in the array and //
        // convert this to a 16-bit value based on the host’s native byte order //
        bpm = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[1]));

        offset =  offset + 2; // Plus 2 bytes //
    }
    NSLog(@"bpm: %i", bpm);



    // Determine if EE data is present //
    // If the 3rd bit of the first byte is 1 this means there is EE data //
    // If so, increase offset with 2 bytes //
    if ((reportData[0] & 0x03) == 1) {
        offset =  offset + 2; // Plus 2 bytes //
    }



    // Determine if RR-interval data is present //
    // If the 4th bit of the first byte is 1 this means there is RR data //
    if ((reportData[0] & 0x04) == 0)
    {
        NSLog(@"%@", @"Data are not present");
    }
    else
    {
        // The number of RR-interval values is total bytes left / 2 (size of uint16) //

        NSUInteger length = [data length];
        NSUInteger count = (length - offset)/2;
        NSLog(@"RR count: %lu", (unsigned long)count);

        for (int i = 0; i < count; i++) {

            // The unit for RR interval is 1/1024 seconds //
            uint16_t value = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[offset]));
            value = ((double)value / 1024.0 ) * 1000.0;


            offset = offset + 2; // Plus 2 bytes //

            NSLog(@"RR value %lu: %u", (unsigned long)i, value);

        }

    }

}
于 2014-10-23T07:50:10.473 回答
0

编辑:这对我有用,我得到了正确的 rr 值:在某些情况下,您可以同时为 rr 找到两个值。

- (void) updateWithHRMData:(NSData *)datas {

    const uint8_t *reportData = [datas bytes];

    uint16_t bpm = 0;
    uint16_t bpm2 = 0;

    if ((reportData[0] & 0x04) == 0)
    {
        NSLog(@"%@", @"Data are not present");
    }
    else
    {

        bpm = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[2]));

        bpm2 = CFSwapInt16LittleToHost(*(uint16_t *)(&reportData[4]));

        if (bpm != 0 || bpm2 != 0) {

                NSLog(@"%u", bpm);

                if (bpm2 != 0) {
                    NSLog(@"%u", bpm2);
                }

        }

    }

}
于 2013-11-07T10:23:10.483 回答
0

解析“C”中的心率参数

我将示例应用程序上传到 GitHub Heart-Rate-Bluegiga

void ble_evt_attclient_attribute_value(const struct ble_msg_attclient_attribute_value_evt_t *msg)
{
    if (msg->value.len < 2) {
        printf("Not enough fields in Heart Rate Measurement value");
        change_state(state_finish);
    }


    // Heart Rate Profile defined flags 
    const unsigned char HEART_RATE_VALUE_FORMAT = 0x01;
    const unsigned char ENERGY_EXPENDED_STATUS = 0x08;
    const unsigned char RR_INTERVAL = 0x10;


    unsigned char current_offset = 0;
    unsigned char flags = msg->value.data[current_offset];
    int is_heart_rate_value_size_long = ((flags & HEART_RATE_VALUE_FORMAT) != 0);
    int has_expended_energy = ((flags & ENERGY_EXPENDED_STATUS) != 0);
    int has_rr_intervals = ((flags & RR_INTERVAL) != 0);


    current_offset++;


    uint16 heart_rate_measurement_value = 0;


    if (is_heart_rate_value_size_long)
    {
        heart_rate_measurement_value = (uint16)((msg->value.data[current_offset + 1] << 8) +
            msg->value.data[current_offset]);
        current_offset += 2;
    }
    else
    {
        heart_rate_measurement_value = msg->value.data[current_offset];
        current_offset++;
    }


    printf("Heart rate measurment value: %d ", heart_rate_measurement_value);


    uint16 expended_energy_value = 0;


    if (has_expended_energy)
    {
        expended_energy_value = (uint16)((msg->value.data[current_offset + 1] << 8) +
            msg->value.data[current_offset]);
        current_offset += 2;


        printf(" Expended energy value: %d ", expended_energy_value);
    }


    uint16 rr_intervals[10] = {0};


    if (has_rr_intervals)
    {
        printf(" Rr intervals: ");


        int rr_intervals_count = (msg->value.len - current_offset) / 2;


        for (int i = 0; i < rr_intervals_count; i++)
        {
            int raw_rr_interval = (uint16)((msg->value.data[current_offset + 1] << 8) +
                msg->value.data[current_offset]);
            rr_intervals[i] = ((double)raw_rr_interval / 1024) * 1000;
            current_offset += 2;


            printf("%d ", rr_intervals[i]);
        }
        printf("\n");
    }
}
于 2016-11-20T11:20:11.887 回答
0

在@Brabbeldas 解决方案中,我必须使用不同的标志来获取 rri 值。但可能取决于使用的设备。

if ((reportData[0] & 0x10) == 0)

代替

if ((reportData[0] & 0x04) == 0)
于 2016-07-19T10:24:47.387 回答