timestocome / SwiftHeartRate

Use video in cell phone camera to determine a user's heart rate (pulse)
MIT License
36 stars 7 forks source link

How are these values calculated? #1

Open KatkayApps opened 5 years ago

KatkayApps commented 5 years ago

Hi there,

First of all thanks for your code. I appreciate if you can have the time to explain the part when you calculate the heartbeat.

You have this function:

        // find peak power and bin
        var power = 0.0 as Float
        var bin = 0 as vDSP_Length

        // calculate heart rate, ie pulse
        // course bandwidth filter --- skip hr under/over unreasonable amounts
        let minHeartRate = 20                                       // skip anything lower ~35 bpm
        let maxHeartRate = Double(windowSizeOverTwo) / 4            // skip anything over ~225 bpm
        vDSP_maxvi(&powerVector+minHeartRate, 1, &power, &bin, vDSP_Length(maxHeartRate))
        bin += vDSP_Length(minHeartRate)        

        // push heart rate data to the user
        let timeElapsed = NSDate().timeIntervalSinceDate(timeElapsedStart)
        timeLabel.text = NSString(format: "Seconds: %d", Int(timeElapsed)) as String

        let binSize = fps * 60.0 / Float(windowSize)
        let errorSize = fps * 60.0 / Float(windowSize)

        let bpm = Float(bin) / Float(windowSize) * (fps * 60.0)
        pulseLabel.text = ("\(Int(bpm))")

1) First of all, I think the values you get there for minHeartRate and maxHeartRate depends on the FPS you are using that is 30 FPS, right? How do you get these values? In my case I am using 60 FPS and still using 512 samples when the app gets there.

2) power will contain the maximum value coming from the fourier transform and bin its index. You calculate these values but you just use bin.

3) you do not use either binSize and errorSize. What these variables represent?

4) what shows on the pulseLabel is the result of bpm that is the division of bin by some number.

I do not understand this.

bin is the Fourier Transform bin that has the highest intensity. A bin in the Fourier Transform is a frequency. I do not understand the relation between a bin and the heartbeat..

thanks.

timestocome commented 5 years ago

Hello,

This code is several years old, let me see what I can recall

I probably decided not to use not use binSize, errorSize and power in the final code and they were only used while I was figuring things out.

minHeartRate and maxHeartRate were just guesses to clip the data. I'm guessing any bpm above or below that is junk. There is always noise to be filtered when using sensors

30 fps was the most I could use to get the data through processing and on screen to user with out getting backed up or losing data. If the device you are using can do more, by all mean do so. It'll increase your accuracy. The really interesting stuff happens when you get fps high enough to determine HRV

Using FFT the bin with the most power is the strongest frequency.

This is just a scale factor to correct units

Linda MacPhee-Cobb https://github.com/timestocome

On Mon, Mar 4, 2019 at 3:45 PM Magno Urbano notifications@github.com wrote:

Hi there,

First of all thanks for your code. I appreciate if you can have the time to explain the part when you calculate the heartbeat.

You have this function:

    // find peak power and bin
    var power = 0.0 as Float
    var bin = 0 as vDSP_Length

    // calculate heart rate, ie pulse
    // course bandwidth filter --- skip hr under/over unreasonable amounts
    let minHeartRate = 20                                       // skip anything lower ~35 bpm
    let maxHeartRate = Double(windowSizeOverTwo) / 4            // skip anything over ~225 bpm
    vDSP_maxvi(&powerVector+minHeartRate, 1, &power, &bin, vDSP_Length(maxHeartRate))
    bin += vDSP_Length(minHeartRate)

    // push heart rate data to the user
    let timeElapsed = NSDate().timeIntervalSinceDate(timeElapsedStart)
    timeLabel.text = NSString(format: "Seconds: %d", Int(timeElapsed)) as String

    let binSize = fps * 60.0 / Float(windowSize)
    let errorSize = fps * 60.0 / Float(windowSize)

    let bpm = Float(bin) / Float(windowSize) * (fps * 60.0)
    pulseLabel.text = ("\(Int(bpm))")

1.

First of all, I think the values you get there for minHeartRate and maxHeartRate depends on the FPS you are using that is 30 FPS, right? How do you get these values? In my case I am using 60 FPS and still using 512 samples when the app gets there. 2.

power will contain the maximum value coming from the fourier transform and bin its index. You calculate these values but you just use bin. 3.

you do not use either binSize and errorSize. What these variables represent? 4.

what shows on the pulseLabel is the result of bpm that is the division of bin by some number.

I do not understand this.

bin is the Fourier Transform bin that has the highest intensity. A bin in the Fourier Transform is a frequency. I do not understand the relation between a bin and the heartbeat..

thanks.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/timestocome/SwiftHeartRate/issues/1, or mute the thread https://github.com/notifications/unsubscribe-auth/ACJx4ULexGn1A5oC0S0DKVG2T9iDzKQAks5vTZPtgaJpZM4bdRUv .

KatkayApps commented 5 years ago

awsome answer. thanks!!!