Ejemplo n.º 1
0
    def beatsfilter(self, data):
        self.all_data.append(data)
        scaled_csi = self.all_data
        no_frames = len(scaled_csi)

        if no_frames < 256:
            return None

        Fs = 10

        no_subcarriers = scaled_csi[0]["csi"].shape[0]
        finalEntries = self.getCSI(scaled_csi)

        sigs = []

        for x in range(no_subcarriers):
            finalEntry = finalEntries[x].flatten()
            filtData = bandpass(7, 1, 1.5, Fs, finalEntry)

            for i in range(0, 70):
                filtData[i] = 0

            sigs.append(filtData)

        pxxs = []

        for data in sigs:
            f, Pxx_den = signal.welch(data, Fs)
            pxxs.append(Pxx_den)

        meanPsd = np.mean(pxxs, axis=0)
        print("Beats: %.2f" % float(f[np.argmax(meanPsd)] * 60))
        self.all_data = []
Ejemplo n.º 2
0
def beatsfilter(scaled_csi):
    xax = getTimestamps(scaled_csi)
    csi, no_frames, no_subcarriers = getCSI(scaled_csi)

    Fs = 1 / np.mean(np.diff(xax))

    stabilities = []

    for x in range(no_subcarriers):
        finalEntry = csi[x].flatten()
        variation = stats.variation(finalEntry)

        if not np.isnan(variation) and variation < 0.5:
            hampelData = hampel(finalEntry, 5)
            smoothedData = running_mean(hampelData, 5)
            filtData = bandpass(5, 1, 1.3, Fs, smoothedData)

            wLength = 1 * Fs
            N = np.mod(len(filtData), wLength)
            windows = np.array_split(filtData, N)

            psds = []
            for window in windows:
                f, Pxx_den = signal.welch(window, Fs)
                fMax = f[np.argmax(Pxx_den)]
                psds.append(fMax)

            specStab = 1 / np.var(psds)
            print("Sub: {} has spectral stability: {}".format(x, specStab))

            # plt.plot(xax, filtData, alpha=0.5)
            stabilities.append({
                "sub": x,
                "stability": specStab,
                "data": filtData
            })

    stabilities.sort(key=lambda x: x["stability"], reverse=True)

    bestStab = stabilities[0]["stability"]
    news = []
    for stab in stabilities:
        if stab["stability"] >= (bestStab / 100) * 20:
            news.append(stab)

    print("Using {} subcarriers.".format(len(news)))
    pxxs = []
    for sub in news:
        filtData = sub["data"]
        f, Pxx_den = signal.welch(filtData, Fs)
        pxxs.append(Pxx_den)

    meanPsd = np.mean(pxxs, axis=0)

    plt.plot(f * 60, meanPsd, alpha=0.5)

    plt.xlabel("Estimated Heart Rate [bpm]")
    plt.ylabel("PSD [V**2/Hz]")
    plt.legend(loc="upper right")
    plt.show()
Ejemplo n.º 3
0
def heatmap(scaled_csi):

    timestamps = getTimestamps(scaled_csi)
    csi, no_frames, no_subcarriers = getCSI(scaled_csi)

    Fs = 1 / np.mean(np.diff(timestamps))
    print("Sampling Rate: " + str(Fs))

    limits = [0, timestamps[-1], 1, no_subcarriers]

    for x in range(no_subcarriers):
        hampelData = hampel(csi[x].flatten(), 5)
        smoothedData = running_mean(hampelData, 5)
        butteredData = bandpass(7, 0.2, 0.3, Fs, smoothedData)
        csi[x] = butteredData

    fig, ax = plt.subplots()
    im = ax.imshow(csi, cmap="jet", extent=limits, aspect="auto")

    cbar = ax.figure.colorbar(im, ax=ax)
    cbar.ax.set_ylabel("Amplitude (dBm)")

    plt.xlabel("Time (s)")
    plt.ylabel("Subcarrier Index")

    plt.show()
Ejemplo n.º 4
0
def shorttime(reader, subcarrier):

    scaled_csi = reader.csi_trace

    #Replace complex CSI with amplitude.

    no_frames, no_subcarriers, finalEntry = getCSI(scaled_csi)
    # hampelData = hampel(finalEntry, 30)
    # smoothedData = running_mean(hampelData, 20)
    y = finalEntry[subcarrier]
    n = no_frames

    Fs = 20

    fmin = 1
    fmax = 1.7

    y = bandpass(9, fmin, fmax, Fs, y)

    # f, t, Zxx = signal.stft(y, Fs, nperseg=2000, noverlap=1750)
    f, t, Zxx = signal.stft(y, Fs)

    #bin indices for the observed amplitude peak in each segment.
    Zxx = np.abs(Zxx)
    maxAx = np.argmax(Zxx, axis=0)

    freqs = []
    for i in maxAx:
        arc = f[i]
        if arc >= fmin and arc <= fmax:
            arc *= 60
            freqs.append(arc)
        else:
            freqs.append(None)

    bpms = []
    for freq in freqs:
        if freq != None:
            bpms.append(freq)

    print(bpms)
    print("Average HR: " + str(np.average(bpms)))

    #We're only interested in frequencies between 0.5 and 2.
    freq_slice = np.where((f >= fmin) & (f <= fmax))

    f = f[freq_slice]
    Zxx = Zxx[freq_slice, :][0]

    plt.pcolormesh(t, f * 60, np.abs(Zxx))
    plt.plot(t, freqs, color="red", marker="x")

    plt.title('STFT Magnitude')
    # plt.ylabel('Frequency [Hz]')
    plt.ylabel('Heart Rate [BPM]')
    plt.xlabel('Time [sec]')
    plt.show()
Ejemplo n.º 5
0
    def updateHeat2(self, data):
        self.all_data.append(data)
        if not self.updateTimestamps():
            self.all_data = self.all_data[:-1]
            return None
        scaled_csi = self.all_data

        no_frames = len(scaled_csi)
        no_subcarriers = scaled_csi[0]["csi"].shape[0]
        ylimit = scaled_csi[no_frames - 1]["timestamp"]

        if no_frames < 80:
            return None

        # limits = [1, no_subcarriers, 0, ylimit]
        limits = [0, ylimit, 1, no_subcarriers]

        finalEntry = np.zeros((no_subcarriers, no_frames))

        #Replace complex CSI with amplitude.
        for y in range(no_subcarriers):
            for x in range(no_frames):
                scaled_entry = scaled_csi[x]["csi"]
                finalEntry[y][x] = db(abs(scaled_entry[y][0][0]))

        for j in range(no_subcarriers):
            sig = finalEntry[j]
            #hampelData = hampel(sig, 10)
            #smoothedData = running_mean(sig, 30)

            y = sig.flatten()
            y = bandpass(5, 1.0, 1.3, 20, y)

            for x in range(70):
                y[x] = 0

            finalEntry[j] = y

        #x = subcarrier index
        #y = time (s)
        #z = amplitude (cBm)

        if not hasattr(self, "im"):
            self.im = self.ax.imshow(finalEntry,
                                     cmap="jet",
                                     extent=limits,
                                     aspect="auto")
            cbar = self.ax.figure.colorbar(self.im, ax=self.ax)
            cbar.ax.set_ylabel("Amplitude (dBm)", rotation=-91, va="bottom")
        else:
            self.im.set_array(finalEntry)
            self.im.set_extent(limits)

        self.ax.relim()
        self.ax.autoscale_view()
        self.fig.canvas.draw()
        self.fig.canvas.flush_events()
Ejemplo n.º 6
0
    def updateButterworth(self, data):
        self.all_data.append(data)
        self.updateTimestamps()

        if not self.updateTimestamps():
            self.all_data = self.all_data[:-1]
            return None
        scaled_csi = self.all_data

        no_frames = len(scaled_csi)
        no_subcarriers = scaled_csi[0]["csi"].shape[0]

        if no_frames < 50:
            return None

        #Replace complex CSI with amplitude.
        finalEntry = [
            db(abs(scaled_csi[x]["csi"][15][0][0])) for x in range(no_frames)
        ]

        hampelData = hampel(finalEntry, 10)
        smoothedData = running_mean(hampelData, 30)
        y = smoothedData

        x = list([x["timestamp"] for x in scaled_csi])
        tdelta = (x[-1] - x[0]) / len(x)

        Fs = 1 / tdelta
        n = no_frames

        y = bandpass(5, 1.0, 1.3, Fs, y)

        ffty = np.fft.rfft(y, len(y))
        freq = np.fft.rfftfreq(len(y), tdelta)
        freqX = [((i * Fs) / n) * 60 for i in range(len(freq))]

        self.plotButt.set_xdata(freqX)
        self.plotButt.set_ydata(np.abs(ffty))

        self.ax.relim()
        self.ax.autoscale_view()
        self.fig.canvas.draw()
        self.fig.canvas.flush_events()
Ejemplo n.º 7
0
def fft(reader):

    scaled_csi = reader.csi_trace

    Fs = 20

    no_frames, no_subcarriers, finalEntry = getCSI(scaled_csi)

    y = bandpass(7, 1, 1.5, Fs, finalEntry[15])

    #rfft is a real Fast Fourier Transform, as we aren't interested in the imaginary parts.
    #as half of the points lie in the imaginary/negative domain, we get an n/2 point FFT.

    #rfftfreq produces a list of frequency bins, which requires calculation to produce
    #interpretable frequencies for BPM tracking. by plotting calculated bpm values,
    #the graph can be more easily read.

    #despite rfft producing an n/2 point fft, the calculation still uses n,
    #because the point spacing is still based on n points.

    # ((binNumber*samplingRate)/n)*60 produces a per minute rate.

    ffty = np.fft.rfft(y, len(y))
    freq = np.fft.rfftfreq(len(y), 0.05)
    freqX = [((i * Fs) / no_frames) * 60 for i in range(len(freq))]

    plt.subplot(211)
    plt.xlabel("Time (s)")
    plt.ylabel("Amplitude (Hz)")

    plt.plot(y)

    plt.subplot(212)
    plt.xlabel("Breaths Per Minute (BPM)")
    plt.ylabel("Amplitude (dB/Hz)")

    axes = plt.gca()
    axes.set_xlim([50, 100])

    plt.plot(freqX, np.abs(ffty))

    plt.show()
Ejemplo n.º 8
0
def beatsfilter(reader, Fs):
    scaled_csi = reader.csi_trace
    no_frames, no_subcarriers, finalEntries = getCSI(scaled_csi,
                                                     metric="phasediff")

    sigs = []

    for x in range(no_subcarriers):
        finalEntry = finalEntries[x]
        # hampelData = hampel(finalEntry, 10, 5)
        # # detrended = dynamic_detrend(hampelData, 5, 3, 1.2, Fs)
        # # rehampeledData = hampel(detrended, 10, 0.1)

        # # hampelData = hampel(finalEntry, 10)
        # # runningMeanData = running_mean(hampelData, 20)

        # filtData = bandpass(7, 1, 1.5, Fs, hampelData)

        # hampelData = hampel(finalEntries[x], 5, 3)
        # runningMeanData = running_mean(hampelData, 20)
        # smoothedData = dynamic_detrend(runningMeanData, 5, 3, 1.2, 10)
        # doubleHampel = hampel(smoothedData, 10, 3)

        filtData = bandpass(7, 1.1, 1.4, Fs, finalEntry)

        for i in range(0, 70):
            filtData[i] = 0

        sigs.append(filtData)

    pxxs = []

    for data in sigs:
        f, Pxx_den = signal.welch(data, Fs)
        pxxs.append(Pxx_den)

    meanPsd = np.mean(pxxs, axis=0)
    # plt.plot(f*60, meanPsd)
    # plt.xlim([40, 100])
    # plt.show()

    return f[np.argmax(meanPsd)] * 60
Ejemplo n.º 9
0
    def filter_seismo(sismo, freqs=[0.1, 10], ftype='bandpass', dt=0.01):
        """
    filter seismograms.
    Inputs:
      -freqs[tuple][(0.1,10)] : corner frequencies of filter response
      -ftype[str][default=bandpass] : filter type
    Return:
      -Updates self.velocity array.
    """
        filtered_s = np.zeros(sismo.shape)
        if ftype == 'bandpass':
            for i in range(sismo.shape[-1]):
                filtered_s[:, i] = bandpass(sismo[:, i],
                                            freqs[0],
                                            freqs[1],
                                            dt=dt,
                                            corners=4,
                                            zerophase=True)

        return filtered_s
Ejemplo n.º 10
0
 def filter_signal(self, signal):
   filtered_signal = filters.bandpass(signal, self.sample_rate,
                                      MORSE_FREQUENCY-self.options['bandwidth'],
                                      MORSE_FREQUENCY+self.options['bandwidth'])
   return filtered_signal
Ejemplo n.º 11
0
def specstabfilter(reader, Fs):

    scaled_csi = reader.csi_trace
    no_frames, no_subcarriers, finalEntries = getCSI(scaled_csi)

    #Using CSI phase difference data.

    stabilities = []

    for x in range(no_subcarriers):
        finalEntry = finalEntries[x]

        #CardioFi paper uses 100Hz uniformly sampled data, which may mean we need to use different
        #filter parameters. For now, we will copy them verbatim.
        #Currently the initial hampel filter is run using T1=0.5s t1=0.4
        #              dynamic_detrending is run with c=5 l=3 alpha=1.2 Fs=Fs
        #          the second hampel filter is run using T1=0.5s t1=0.1
        #          the bandpass filter is run at 5th order with a range of 1-2Hz.

        hampelData = hampel(finalEntry, 20)
        detrended = dynamic_detrend(hampelData, 5, 3, 1.2, Fs)
        rehampeledData = hampel(detrended, 20)

        filtData = bandpass(7, 1, 1.5, Fs, rehampeledData)

        #Spectral Stability section.
        #The spectral stability metric aims to score subcarriers based on the
        #variance of their heart rate estimations.

        #To do this, both the length of the data being used for estimations,
        #and a sliding window length must be selected.

        #While the dataLength should ideally be around 40s to mirror that used
        #in the CardioFi paper, this is difficult to replicate using the data
        #which was produced over the last few months.

        #Shorter data and window lengths are being experimented with but do not
        #appear to be working well. This is evidenced by the number of subcarriers
        #being selected using the metric, which is typically lower than that seen
        #in the CardioFi paper.

        #Notably, it is also difficult to take consistent ground truth heart rate
        #measurements over a 40 second period.

        wLength = 5 * Fs
        dataLength = 10 * Fs
        windows = []
        position = 0

        #This sliding window system splits filtData into wLength-sized windows,
        #except for the final window which contains the remainder of the data.
        #Each sliding window has an overlap of 1 second (or Fs).

        while position < dataLength:
            if (position + wLength) > dataLength:
                window = filtData[position:]
            else:
                window = filtData[position:position + wLength]
            windows.append(window)
            position += wLength - Fs

        #PSD measurements are then taken for each window, and the variance of
        #these measurements are then collected to produce a final score for
        #this subcarrier.

        psds = []
        for window in windows:
            f, Pxx_den = signal.welch(window, Fs)
            fMax = f[np.argmax(Pxx_den)]
            psds.append(fMax)

        specStab = 1 / np.var(psds)

        if specStab == np.inf:
            specStab = 0
        stabilities.append([x, specStab, filtData])

        # print("Sub: {} has spectral stability: {}".format(x, specStab))
        # print("Sub: {} mean pred: {}".format(x, np.mean(psds)*60))

    stabilities.sort(key=lambda x: x[1], reverse=True)
    bestStab = stabilities[0][1]
    news = [x for x in stabilities if x[1] > bestStab * 0.2]

    print("Using {} subcarriers.".format(len(news)))
    pxxs = []
    for sub in news:
        data = sub[2]
        f, Pxx_den = signal.welch(data, Fs)
        pxxs.append(Pxx_den)

    #The mean PSD of the top subcarriers is then selected, with the
    #peak taken as the final heart rate estimation.

    meanPsd = np.mean(pxxs, axis=0)
    return f[np.argmax(meanPsd)] * 60