コード例 #1
0
    def get_bpm_estimate(self, time_data, cam_data):

        fps = hp.get_samplerate_datetime(time_data, '%S.%f')

        cam_bpm = 0

        filtered_ppg_r = hp.filter_signal(cam_data,
                                          cutoff=[0.8, 1],
                                          filtertype='bandpass',
                                          sample_rate=fps,
                                          order=4,
                                          return_top=False)
        try:
            working_data, measures = hp.process(cam_data, fps)
        except BadSignalWarning:
            print("Bad signal")
        else:
            if (measures['bpm'] > 40 and measures['bpm'] < 180):
                cam_bpm = measures['bpm']

        return filtered_ppg_r, cam_bpm
コード例 #2
0
def main(writer):
    """
    A function to extract the bpm from PPG data in a .csv file.
    
    Parameters
    ----------
    writer: PPG_Writer
            A PPG_Writer object initialized with the desired .csv file.
    """
    global bpms, snrs
    '''
    Get/Display raw data and sampling rate.
    '''
    # Acquire time-series data from the .csv file
    # Ignore the first second of data, since it's very different from the other data.
    timeData = writer.get_time_data()[30:]
    camDataRed = writer.get_cam_data_red()[30:]
    camDataGreen = writer.get_cam_data_green()[30:]
    pulseData = writer.get_pulseox_data()[30:]

    # Acquire sampling rate and ground truth BPM from the .csv file
    sampling_rate = hp.get_samplerate_datetime(timeData, '%S.%f')
    BPM_TRUTH = writer.get_bpm()

    # If desired, graph the raw PPG time-series data for both channels.
    if DISPLAY:
        plt.title("Raw PPG Data")
        #plt.plot(timeData, camDataRed,   "-r", label="Red")
        plt.plot(timeData, camDataGreen, "-g", label="Green")
        plt.legend(loc="lower right")
        plt.ylabel("Mean Pixel Intensity")
        plt.xlabel("Time (seconds)")
        plt.show()
    '''
    Interpolate PPG signals
    '''
    new_fs = 30
    sampling_interval = 1 / new_fs

    # Quantize beginning + ending time to the nearest multiple of sampling_interval.
    initial_time = int(timeData[0] * new_fs) / new_fs
    end_time = int(timeData[-1] * new_fs) / new_fs

    # Figure out number of samples.
    elapsed_time = end_time - initial_time
    num_samples = int(elapsed_time * new_fs) + 1

    # Generate uniform time scale and interpolation function
    uniform_time = np.linspace(initial_time,
                               end_time,
                               num=num_samples,
                               endpoint=True)
    f_red = interp1d(timeData, camDataRed, fill_value="extrapolate")
    f_green = interp1d(timeData, camDataGreen, fill_value="extrapolate")

    # Use interpolation function to generate wave.
    new_red = f_red(uniform_time)
    new_green = f_green(uniform_time)
    N = len(new_red)
    '''
    Filter/Enhance Signals
    '''

    # Filter the interpolated PPG signals with a [0.7, 4] Hz bandpass filter.
    LOWER_CUTOFF = 0.7
    UPPER_CUTOFF = 4
    new_red = hp.filter_signal(new_red,
                               cutoff=[LOWER_CUTOFF, UPPER_CUTOFF],
                               filtertype='bandpass',
                               sample_rate=new_fs,
                               order=4,
                               return_top=False)

    new_green = hp.filter_signal(new_green,
                                 cutoff=[LOWER_CUTOFF, UPPER_CUTOFF],
                                 filtertype='bandpass',
                                 sample_rate=new_fs,
                                 order=4,
                                 return_top=False)

    # If desired, graph the filtered PPG time-series for both color channels.
    if DISPLAY:
        plt.title("Filtered PPG Data")
        #plt.plot(uniform_time, new_red,   '-r', label='Red')
        plt.plot(uniform_time, new_green, '-g', label='Green')
        plt.legend(loc="lower right")
        plt.ylabel("Mean Pixel Intensity")
        plt.xlabel("Time (seconds)")
        plt.show()
    '''
    Take FFT of PPGs
    '''
    # Calculate FFT magnitude of both PPG signals.
    # Remove frequencies above the sampling frequency.
    fft_red = np.fft.fft(new_red) / N
    fft_green = np.fft.fft(new_green) / N
    fft_red = fft_red[range(N // 2)]
    fft_green = fft_green[range(N // 2)]
    fft_red = abs(fft_red)
    fft_green = abs(fft_green)

    # Get frequency axis corresponding to the FFTs.
    values = np.arange(N // 2)
    timePeriod = N * sampling_interval
    frequencies = values / timePeriod

    # Find indices corresponding to f_bpm-0.1, f_bpm, and f_bpm+0.1,
    # Where f_bpm = the ground truth BPM in Hz.
    f_bpm = BPM_TRUTH / 60
    bpm_index = np.abs(frequencies - f_bpm).argmin()
    upper_index = np.abs(frequencies - f_bpm - 0.1).argmin()
    lower_index = np.abs(frequencies - f_bpm + 0.1).argmin()

    # Find the peaks of the FFTs for both color channels.
    red_peak_index = np.argmax(fft_red)
    red_bpm = int(frequencies[red_peak_index] * 60)

    green_peak_index = np.argmax(fft_green)
    green_bpm = int(frequencies[green_peak_index] * 60)
    '''
    Calculate SNR
    '''
    # Find indices corresponding to the cutoff frequencies of the bandpass filter from earlier.
    lower_cutoff_index = np.abs(frequencies - LOWER_CUTOFF).argmin()
    upper_cutoff_index = np.abs(frequencies - UPPER_CUTOFF).argmin()

    red_signal = 0
    red_noise = 0
    green_signal = 0
    green_noise = 0

    # Iterate through all indices between the lower and upper cutoff frequencies
    for x in range(lower_cutoff_index, upper_cutoff_index + 1):
        # If current index's frequency is close to the ground truth BPM frequency,
        # then add its power (magnitude squared) to the signal variable.
        if (x >= lower_index and x <= upper_index):
            red_signal = red_signal + fft_red[x]**2
            green_signal = green_signal + fft_green[x]**2
        # Else, add its power to the noise variable.
        else:
            red_noise = red_noise + fft_red[x]**2
            green_noise = green_noise + fft_green[x]**2

    red_snr = red_signal / red_noise
    green_snr = green_signal / green_noise

    print('ppg analysis done')

    bpms = {'truth': BPM_TRUTH, 'red': red_bpm, 'green': green_bpm}
    snrs = {'red': red_snr, 'green': green_snr}

    # If desired, graph the FFTs of both color channels,
    # with dots indicating the frequencies of the BPM estimates and ground truth.
    if DISPLAY:
        '''
        plt.title('Red FFT. BPM Estimate = {},Truth = {}'.format(red_bpm, BPM_TRUTH))
        plt.plot(frequencies, fft_red)
        plt.ylabel('Spectral Power')
        plt.xlabel('Frequency (Hz)')
    
        plt.plot(frequencies[red_peak_index], fft_red[red_peak_index], 'ro', label='Estimate')
        plt.plot(frequencies[bpm_index],      fft_red[bpm_index],      'go', label='Reality')
        plt.legend(loc='upper right')
        plt.show()
        '''

        plt.title('Green FFT. BPM Estimate = {},Truth = {}'.format(
            green_bpm, BPM_TRUTH))
        plt.plot(frequencies, fft_green)
        plt.ylabel('Spectral Power')
        plt.xlabel('Frequency (Hz)')

        plt.plot(frequencies[green_peak_index],
                 fft_green[green_peak_index],
                 'ro',
                 label='Estimate')
        plt.plot(frequencies[bpm_index],
                 fft_green[bpm_index],
                 'go',
                 label='Reality')
        plt.legend(loc='upper right')
        plt.show()

    # If desired, graph the results from the heart rate variability algorithm,
    # with the input being the green channel signal,
    # and plot the pulseox hrv for comparison.
    if DISPLAY:

        # PulseOx interpolation and filtering
        f_pox = interp1d(timeData, pulseData, fill_value="extrapolate")
        new_pox = hp.filter_signal(
            f_pox(uniform_time),
            cutoff=[LOWER_CUTOFF / 4, UPPER_CUTOFF],
            filtertype='bandpass',
            sample_rate=new_fs,  #sampling_rate 
            order=4,
            return_top=False)

        # PulseOx FFT and BPM Estimation
        fft_pox = abs(np.fft.fft(new_pox) / N)
        fft_pox = fft_pox[range(N // 2)]
        pox_bpm = int(frequencies[np.argmax(fft_pox)] * 60)

        print('pulse ox bpm: {}'.format(pox_bpm))
        print('ground truth: {}'.format(BPM_TRUTH))
        '''
        plt.plot(uniform_time, f_pox(uniform_time))
        plt.show()
        '''

        performance_tracker = PerformanceTracker()
        # Calculate + plot pulse oximeter hrv
        hrv, thrv, lfcam, hfcam, lf_hfcam, BRcam, sdnncam, sdsdcam, rmssdcam = hrv_function(
            new_pox, fs=int(30 * BPM_TRUTH / pox_bpm), bpm=BPM_TRUTH)
        performance_tracker.track_performance()
        pox_hrv = hrv
        pox_thrv = thrv
        print('Pulse Ox Statistics:')
        print('lfcam: {:.2f}'.format(lfcam))
        print('hfcam: {:.2f}'.format(hfcam))
        print('lf_hfcam: {:.2f}'.format(lf_hfcam))
        print('BRcam: {:.2f}'.format(BRcam))
        print('sdnncam: {:.2f}'.format(sdnncam))
        print('sdsdcam: {:.2f}'.format(sdsdcam))
        print('rmssdcam: {:.2f}'.format(rmssdcam))
        print()
        print()

        performance_tracker.reset()
        # Calculate + plot green channel hrv
        num = int(len(new_green) * pox_bpm / BPM_TRUTH)
        hrv, thrv, lfcam, hfcam, lf_hfcam, BRcam, sdnncam, sdsdcam, rmssdcam = hrv_function(
            new_green[:num], fs=30, bpm=green_bpm)
        performance_tracker.track_performance()
        print('PPG Statistics:')
        print('lfcam: {:.2f}'.format(lfcam))
        print('hfcam: {:.2f}'.format(hfcam))
        print('lf_hfcam: {:.2f}'.format(lf_hfcam))
        print('BRcam: {:.2f}'.format(BRcam))
        print('sdnncam: {:.2f}'.format(sdnncam))
        print('sdsdcam: {:.2f}'.format(sdsdcam))
        print('rmssdcam: {:.2f}'.format(rmssdcam))

        plt.title("BPM as a function of HRV Algorithm")
        plt.plot(thrv / 1000, 60000 / hrv, label="ppg")
        plt.plot(pox_thrv / 1000, 60000 / pox_hrv, label="pulseox")
        plt.xlabel("Time Window 30s")
        plt.ylabel("BPM")
        plt.legend(loc="lower right")
        plt.show()
        '''
コード例 #3
0
def main(writer):
    global bpms, snrs
    '''
    Get/Display raw data and sampling rate.
    '''

    # Ignore the first second of data, since it's very different from the other data.
    timeData = writer.get_time_data()[30:]
    camDataRed = writer.get_cam_data_red()[30:]
    camDataGreen = writer.get_cam_data_green()[30:]
    pulseData = writer.get_pulseox_data()[30:]

    sampling_rate = hp.get_samplerate_datetime(timeData, '%S.%f')
    BPM_TRUTH = writer.get_bpm()

    if DISPLAY:
        plt.title("Raw PPG Data")
        plt.plot(timeData, camDataRed, "-r", label="Red")
        plt.plot(timeData, camDataGreen, "-g", label="Green")
        plt.legend(loc="lower right")
        plt.ylabel("Mean Pixel Intensity")
        plt.xlabel("Time (seconds)")
        plt.show()
    '''
    Interpolate PPG signals
    '''
    new_fs = 30
    sampling_interval = 1 / new_fs

    # Quantize time
    initial_time = int(timeData[0] * new_fs) / new_fs
    end_time = int(timeData[-1] * new_fs) / new_fs

    # Figure out number of samples.
    elapsed_time = end_time - initial_time
    num_samples = int(elapsed_time * new_fs) + 1

    # Generate uniform time scale and interpolation function
    uniform_time = np.linspace(initial_time,
                               end_time,
                               num=num_samples,
                               endpoint=True)
    f_red = interp1d(timeData, camDataRed, fill_value="extrapolate")
    f_green = interp1d(timeData, camDataGreen, fill_value="extrapolate")

    # Use interpolation function to generate wave.
    new_red = f_red(uniform_time)
    new_green = f_green(uniform_time)
    N = len(new_red)
    '''
    Filter/Enhance Signals
    '''

    # Display the filtered PPG, print the heartpy bpm estimate
    LOWER_CUTOFF = 0.7
    UPPER_CUTOFF = 4
    #filtered_red_ppg = hp.filter_signal(camDataRed,
    new_red = hp.filter_signal(
        new_red,
        cutoff=[LOWER_CUTOFF, UPPER_CUTOFF],
        filtertype='bandpass',
        sample_rate=new_fs,  #sampling_rate 
        order=4,
        return_top=False)

    #filtered_green_ppg = hp.filter_signal(camDataGreen,
    new_green = hp.filter_signal(
        new_green,
        cutoff=[LOWER_CUTOFF, UPPER_CUTOFF],
        filtertype='bandpass',
        sample_rate=new_fs,  #sampling_rate 
        order=4,
        return_top=False)

    if DISPLAY:
        plt.title("Filtered PPG Data")
        plt.plot(uniform_time, new_red, '-r', label='Red')
        plt.plot(uniform_time, new_green, '-g', label='Green')
        #plt.plot(timeData, filtered_red_ppg, "-r", label="Red")
        #plt.plot(timeData, filtered_green_ppg, "-g", label="Green")
        plt.legend(loc="lower right")
        plt.ylabel("Mean Pixel Intensity")
        plt.xlabel("Time (seconds)")
        plt.show()
    '''
    Take FFT of PPGs
    '''
    # Take FFT of waves. Remove frequencies above the sampling frequency.
    fft_red = np.fft.fft(new_red) / N
    fft_green = np.fft.fft(new_green) / N
    fft_red = fft_red[range(N // 2)]
    fft_green = fft_green[range(N // 2)]
    fft_red = abs(fft_red)
    fft_green = abs(fft_green)

    # Get frequency spectrum of FFTs.
    values = np.arange(N // 2)
    timePeriod = N * sampling_interval
    frequencies = values / timePeriod

    # Find indices of bpm spike.
    f_bpm = BPM_TRUTH / 60
    bpm_index = np.abs(frequencies - f_bpm).argmin()
    upper_index = np.abs(frequencies - f_bpm - 0.1).argmin()
    lower_index = np.abs(frequencies - f_bpm + 0.1).argmin()

    red_peak_index = np.argmax(fft_red)
    red_bpm = int(frequencies[red_peak_index] * 60)

    green_peak_index = np.argmax(fft_green)
    green_bpm = int(frequencies[green_peak_index] * 60)
    '''
    Calculate SNR
    '''
    lower_cutoff_index = np.abs(frequencies - LOWER_CUTOFF).argmin()
    upper_cutoff_index = np.abs(frequencies - UPPER_CUTOFF).argmin()

    red_signal = 0
    red_noise = 0
    green_signal = 0
    green_noise = 0

    for x in range(lower_cutoff_index, upper_cutoff_index + 1):
        if (x >= lower_index and x <= upper_index):
            red_signal = red_signal + fft_red[x]**2
            green_signal = green_signal + fft_green[x]**2
        else:
            red_noise = red_noise + fft_red[x]**2
            green_noise = green_noise + fft_green[x]**2

    red_snr = red_signal / red_noise
    green_snr = green_signal / green_noise

    print('ppg analysis done')

    bpms = {'truth': BPM_TRUTH, 'red': red_bpm, 'green': green_bpm}
    snrs = {'red': red_snr, 'green': green_snr}

    if DISPLAY:
        plt.title('Red FFT. Estimate = {},Truth = {}'.format(
            red_bpm, BPM_TRUTH))
        plt.plot(frequencies, fft_red)
        plt.ylabel('Spectral Power')
        plt.xlabel('Frequency (Hz)')

        plt.plot(frequencies[red_peak_index],
                 fft_red[red_peak_index],
                 'ro',
                 label='Estimate')
        plt.plot(frequencies[bpm_index],
                 fft_red[bpm_index],
                 'go',
                 label='Reality')
        plt.legend(loc='upper right')
        plt.show()

        plt.title('Green FFT. Estimate = {},Truth = {}'.format(
            green_bpm, BPM_TRUTH))
        plt.plot(frequencies, fft_green)
        plt.ylabel('Spectral Power')
        plt.xlabel('Frequency (Hz)')

        plt.plot(frequencies[green_peak_index],
                 fft_green[green_peak_index],
                 'ro',
                 label='Estimate')
        plt.plot(frequencies[bpm_index],
                 fft_green[bpm_index],
                 'go',
                 label='Reality')
        plt.legend(loc='upper right')
        plt.show()
コード例 #4
0
 def get_samplerate(self):
     loaded_times = hp.get_data(self.filename, column_name='time')
     fs = hp.get_samplerate_datetime(loaded_times, '%S.%f')
     return fs
コード例 #5
0
    data_influx = client.query(
        "SELECT analog from autogen.sensor WHERE sessionId = '" + sessionId +
        "' ORDER BY DESC LIMIT 10000 OFFSET 0",
        database='vr_data_test')
    points = data_influx.get_points()
    analog_list = []
    time_list = []
    for p in points:
        analog_list.append(p['analog'])
        time_list.append(p['time'])
    analog_list.reverse()
    time_list.reverse()
    data = np.array(analog_list)
    datetime_data = np.array(time_list)

    fs = hp.get_samplerate_datetime(datetime_data,
                                    timeformat='%Y-%m-%dT%H:%M:%S.%fZ')

    filtered = hp.enhance_peaks(data, iterations=2)
    filtered = hp.filter_signal(filtered, cutoff=3, sample_rate=fs, order=2)
    try:
        working_data, measures = hp.process(filtered,
                                            fs,
                                            report_time=True,
                                            calc_freq=True)
    except:
        print("error calculating RR")
        sys.exit(0)

#     hp.plotter(working_data, measures)

    filtered_body = []