def _filtering(signal,fs,pass_frequency,n): 
    if n == 1:
        order = int(0.3 * fs)
        filtered, _, _ = filter_signal(signal=signal,ftype='FIR',band='bandpass',order=order,frequency=pass_frequency,sampling_rate=fs)
    elif n == 2:
        order = 5
        filtered, _, _ = filter_signal(signal=signal,ftype='butter',band='bandpass',order=order,frequency=pass_frequency,sampling_rate=fs)
    elif n == 3:
        order = 5
        filtered, _, _ = filter_signal(signal=signal,ftype='bessel',band='bandpass',order=order,frequency=pass_frequency,sampling_rate=fs)
    elif n == 4:
        order = 5
        filtered, _, _ = filter_signal(signal=signal,ftype='ellip',band='bandpass',order=order,frequency=pass_frequency,sampling_rate=fs,rp=5,rs=40)
    return(filtered)
Exemplo n.º 2
0
    def biosppy_bandpass(self, data_time_pair):
        ret_list = []
        data = []

        # Give enough data points to filter properly
        if len(data_time_pair) > 300:
            # Extract vals
            for point in data_time_pair:
                data.append(point[1])

            # Calculate order of filter
            order = int(0.3 * self.sample_rate)

            # Apply filters
            filtered_data, _, _ = st.filter_signal(
                signal=data,
                ftype='FIR',
                band='bandpass',
                order=order,
                frequency=[1, 58],
                sampling_rate=self.sample_rate)

            # MIGHT NEED TO CONVERT filtered_data INTO A LIST!!!

            # Recompile data with times
            for i in range(0, len(data_time_pair)):
                ret_list.append([data_time_pair[i][0], filtered_data[i]])
        else:
            ret_list = data_time_pair

        return ret_list
    def find_peaks(self, X, channel=0):

        X_processed = X[:, channel].copy()
        X_processed = filter_signal(signal=X_processed,
                                    ftype='FIR',
                                    band='bandpass',
                                    order=150,
                                    frequency=[3, 45],
                                    sampling_rate=400)[0]

        # check original polarity
        ecg_object = ecg.ecg(signal=X_processed, sampling_rate=400, show=False)
        peaks_plus = ecg_object['rpeaks']  # rpeak indices

        # check reversed polarity
        ecg_object = ecg.ecg(signal=-1 * X_processed,
                             sampling_rate=400,
                             show=False)
        peaks_minus = ecg_object['rpeaks']  #

        # select polarity
        if np.abs(np.median(X_processed[peaks_minus])) > np.abs(
                np.median(X_processed[peaks_plus])):
            peaks = peaks_minus.copy()
        else:
            peaks = peaks_plus.copy()

        return peaks
Exemplo n.º 4
0
    def bandpass(self, data):
        ret_list = []
        data = []

        # Give enough data points to filter properly
        if len(data) > 300:

            # Calculate order of filter
            order = int(0.3 * self.sample_rate)

            # Apply filters
            filtered_data, _, _ = st.filter_signal(
                signal=data,
                ftype='FIR',
                band='bandpass',
                order=order,
                frequency=[2, 50],
                sampling_rate=self.sample_rate)

            ret_list = filtered_data

        else:
            ret_list = data

        return ret_list
Exemplo n.º 5
0
def get_rpeaks(ecg):
    """ function: get_rpeaks

    returns an array of indices of the r peaks in a given ecg

    Args:
        ecg : np.ndarray
            an ecg
    Returns:
        rpeaks : np.ndarray
            an array of indices of the r peaks
    """
    try:
        ecg = ecg[:, 0]
    except:
        pass

    filtered, _, _ = biosppy_tools.filter_signal(signal=ecg,
                                                 ftype='FIR',
                                                 band='bandpass',
                                                 order=150,
                                                 frequency=[3, 45],
                                                 sampling_rate=500)
    rpeaks, = biosppy_ecg.hamilton_segmenter(signal=filtered,
                                             sampling_rate=500)
    # correct R-peak locations
    rpeaks, = biosppy_ecg.correct_rpeaks(signal=filtered,
                                         rpeaks=rpeaks,
                                         sampling_rate=500,
                                         tol=0.05)

    return np.array(rpeaks)
Exemplo n.º 6
0
    def biosppy_bandpass(self, data_time_pair):
        ret_list = []
        data = []

        # Give enough data points to filter properly
        if len(data_time_pair) > 300:
            # Extract vals
            for point in data_time_pair:
                data.append(point[1])

            # Calculate order of filter
            order = int(0.3 * self.sample_rate)

            # Apply filters
            filtered_data, _, _ = st.filter_signal(signal=data,
                                                   ftype='FIR',
                                                   band='bandpass',
                                                   order=order,
                                                   frequency=[1, 58],
                                                   sampling_rate=self.sample_rate)

            # MIGHT NEED TO CONVERT filtered_data INTO A LIST!!!

            # Recompile data with times
            for i in range(0, len(data_time_pair)):
                ret_list.append([data_time_pair[i][0], filtered_data[i]])
        else:
            ret_list = data_time_pair

        return ret_list
Exemplo n.º 7
0
def test_imports():
    """
    Test to check import of libraries.
    """

    #checking scipy, keras, numpy, biosppy
    dummy = sp.__version__
    dummy3 = k.__version__
    dummy4 = np.__version__
    dummy5 = bsp.__version__

    sine = fn.sinewave()
    emg = em.emgsig()

    #checking matplotlib.pyplot
    if plt.plot(sine):
        pass

    #checking tensorflow
    help(tf.keras.Sequential)

    #checking scipy.signal
    if signal.correlate(emg, sine) is not None:
        pass

    #checking biosppy.signals.tools
    if tools.filter_signal(emg, ftype='butter', band='lowpass', order=2,
                           frequency=50, sampling_rate=1000) is not None:
        pass
Exemplo n.º 8
0
def passfilter(signal, fs, freq1, freq2):
    """Filter raw ECG waveform with bandpass finite-impulse-response filter."""
    # Calculate filter order
    order = int(0.3 * fs)

    # Filter waveform
    signal.val, _, _ = tools.filter_signal(signal=signal.val, ftype='FIR', band='bandpass', order=order,
                                       frequency=(freq1, freq2), sampling_rate=fs)
    return signal
Exemplo n.º 9
0
 def _apply_filter(self, signal_raw, filter_bandwidth):
     """Apply FIR bandpass filter to waveform."""
     signal_filtered, _, _ = filter_signal(signal=signal_raw,
                                           ftype='FIR',
                                           band='bandpass',
                                           order=int(0.3 * self.fs),
                                           frequency=filter_bandwidth,
                                           sampling_rate=self.fs)
     return signal_filtered
Exemplo n.º 10
0
def filter(signal):
    signal = np.array(signal, dtype=np.float)
    filtered, _, _ = filter_signal(signal=signal,
                                   ftype='FIR',
                                   band='bandpass',
                                   order=150,
                                   frequency=(2, 200),
                                   sampling_rate=500)
    return filtered
Exemplo n.º 11
0
def filter_ecg(signal=None, sampling_rate=1000.):
    order = int(0.3 * sampling_rate)
    filtered, _, _ = st.filter_signal(signal=signal,
                                      ftype='FIR',
                                      band='bandpass',
                                      order=order,
                                      frequency=[3, 45],
                                      sampling_rate=sampling_rate)
    return filtered
Exemplo n.º 12
0
Arquivo: mk3.py Projeto: Biospore/ecg
def filter_signal(signal, sampling_rate=360):
    signal = np.array(signal)
    order = int(0.3 * sampling_rate)
    filtered, _, _ = st.filter_signal(signal=signal,
                                      ftype='FIR',
                                      band='bandpass',
                                      order=order,
                                      frequency=[3, 45],
                                      sampling_rate=sampling_rate)
    return filtered
Exemplo n.º 13
0
def feature_extraction(recording, signal, labels):
    data = []
    for i in tqdm(range(len(labels)), desc=recording, file=sys.stdout):
        segment = signal[i * fs * 60:(i + 1) * fs * 60]
        segment, _, _ = st.filter_signal(segment,
                                         ftype='FIR',
                                         band='bandpass',
                                         order=int(0.3 * fs),
                                         frequency=[3, 45],
                                         sampling_rate=fs)
        # Finding R peaks
        rpeaks, = hamilton_segmenter(segment, sampling_rate=fs)
        rpeaks, = correct_rpeaks(segment, rpeaks, sampling_rate=fs, tol=0.1)
        # Extracting feature
        label = 0 if labels[i] == "N" else 1
        if 40 <= len(rpeaks) <= 200:  # Remove abnormal R peaks
            rri_tm, rri = rpeaks[1:] / float(fs), np.diff(rpeaks,
                                                          axis=-1) / float(fs)
            rri = medfilt(rri, kernel_size=3)
            edr_tm, edr = rpeaks / float(fs), segment[rpeaks]
            # Remove physiologically impossible HR signal
            if np.all(np.logical_and(60 / rri >= hr_min, 60 / rri <= hr_max)):
                rri_time_features, rri_frequency_features = time_domain(
                    rri * 1000), frequency_domain(rri, rri_tm)
                edr_frequency_features = frequency_domain(edr, edr_tm)
                # 6 + 6 + 6 + 1 = 19
                data.append([
                    rri_time_features["rmssd"], rri_time_features["sdnn"],
                    rri_time_features["nn50"], rri_time_features["pnn50"],
                    rri_time_features["mrri"], rri_time_features["mhr"],
                    rri_frequency_features["vlf"] /
                    rri_frequency_features["total_power"],
                    rri_frequency_features["lf"] /
                    rri_frequency_features["total_power"],
                    rri_frequency_features["hf"] /
                    rri_frequency_features["total_power"],
                    rri_frequency_features["lf_hf"],
                    rri_frequency_features["lfnu"],
                    rri_frequency_features["hfnu"],
                    edr_frequency_features["vlf"] /
                    edr_frequency_features["total_power"],
                    edr_frequency_features["lf"] /
                    edr_frequency_features["total_power"],
                    edr_frequency_features["hf"] /
                    edr_frequency_features["total_power"],
                    edr_frequency_features["lf_hf"],
                    edr_frequency_features["lfnu"],
                    edr_frequency_features["hfnu"], label
                ])
            else:
                data.append([np.nan] * 18 + [label])
        else:
            data.append([np.nan] * 18 + [label])
    data = np.array(data, dtype="float")
    return data
Exemplo n.º 14
0
    def _filter_waveform(self):
        """Filter raw ECG waveform with bandpass finite-impulse-response filter."""
        # Calculate filter order
        order = int(0.3 * self.fs)

        # Filter waveform
        filtered = np.zeros(self.waveform.shape)
        for lead in range(self.waveform.shape[1]):
            filtered[:, lead], _, _ = filter_signal(signal=self.waveform[:, lead], ftype='FIR', band='bandpass', order=order,
                                           frequency=self.filter_bands, sampling_rate=self.fs)

        return filtered
Exemplo n.º 15
0
    def _apply_filter(self, signal, filter_bandwidth):

        # Calculate filter order
        order = int(0.3 * self.fs)

        # Filter signal
        signal, _, _ = filter_signal(signal=signal,
                                     ftype='FIR',
                                     band='bandpass',
                                     order=order,
                                     frequency=filter_bandwidth,
                                     sampling_rate=self.fs)

        return signal
Exemplo n.º 16
0
    def _filter_waveform(self):

        # Calculate filter order
        order = int(0.3 * self.fs)

        # Filter waveform
        filtered, _, _ = filter_signal(signal=self.waveform,
                                       ftype='FIR',
                                       band='bandpass',
                                       order=order,
                                       frequency=self.filter_bands,
                                       sampling_rate=self.fs)

        return filtered
Exemplo n.º 17
0
    def _filter_waveform(self):
        """Filter raw ECG waveform with bandpass finite-impulse-response filter."""
        # Calculate filter order
        order = int(0.3 * self.fs)

        # Filter waveform
        filtered, _, _ = filter_signal(signal=self.waveform,
                                       ftype='FIR',
                                       band='bandpass',
                                       order=order,
                                       frequency=self.filter_bands,
                                       sampling_rate=self.fs)

        return filtered
def worker(name, labels):
    print("processing %s!" % name)
    X = []
    y = []
    groups = []
    signals = wfdb.rdrecord(os.path.join(base_dir, name),
                            channels=[0]).p_signal[:, 0]  # Read recording
    for j in range(len(labels)):
        if j < before or \
                (j + 1 + after) > len(signals) / float(sample):
            continue
        signal = signals[int((j - before) * sample):int((j + 1 + after) *
                                                        sample)]
        signal, _, _ = st.filter_signal(
            signal,
            ftype='FIR',
            band='bandpass',
            order=int(0.3 * fs),
            frequency=[3, 45],
            sampling_rate=fs)  # Filtering the ecg signal to remove noise
        # Find R peaks
        rpeaks, = hamilton_segmenter(signal,
                                     sampling_rate=fs)  # Extract R-peaks
        rpeaks, = correct_rpeaks(signal,
                                 rpeaks=rpeaks,
                                 sampling_rate=fs,
                                 tol=0.1)
        if len(rpeaks) / (1 + after + before) < 40 or \
                len(rpeaks) / (1 + after + before) > 200:  # Remove abnormal R peaks signal
            continue
        # Extract RRI, Ampl signal
        rri_tm, rri_signal = rpeaks[1:] / float(fs), np.diff(rpeaks) / float(
            fs)
        rri_signal = medfilt(rri_signal, kernel_size=3)
        ampl_tm, ampl_siganl = rpeaks / float(fs), signal[rpeaks]
        hr = 60 / rri_signal
        # Remove physiologically impossible HR signal
        if np.all(np.logical_and(hr >= hr_min, hr <= hr_max)):
            # Save extracted signal
            X.append([(rri_tm, rri_signal), (ampl_tm, ampl_siganl)])
            y.append(0. if labels[j] == 'N' else 1.)
            groups.append(name)
    print("over %s!" % name)
    return X, y, groups
Exemplo n.º 19
0
    def low_pass_filter(self, signal, cutoff_frequency, framerate):
        """
        :param data: imported data -> self.podatki
        :return: filtered .wav data as np array
        """

        if cutoff_frequency == "" or cutoff_frequency == "0":
            cutoff_frequency = 1000

        cutoff_frequency = int(cutoff_frequency)

        filtered, _, _ = st.filter_signal(signal=signal,
                                          ftype='FIR',
                                          band='lowpass',
                                          frequency=cutoff_frequency,
                                          order=int(0.3 * 4000),
                                          sampling_rate=framerate)

        return np.array(filtered)
Exemplo n.º 20
0
def offline_rr_interval_orignal(signal, fs=200):  # 逐波心率(bmp),原始
    ecg_signal = np.array(signal)
    sampling_rate = fs
    sampling_rate = float(sampling_rate)

    # filter signal
    order = int(0.3 * sampling_rate)
    filtered, _, _ = st.filter_signal(signal=ecg_signal,
                                      ftype='FIR',
                                      band='bandpass',
                                      order=order,
                                      frequency=[5, 30],
                                      sampling_rate=sampling_rate)

    rpeaks, = eecg.hamilton_segmenter(signal=filtered, sampling_rate=sampling_rate)
    # correct R-peak locations
    rpeaks, = eecg.correct_rpeaks(signal=filtered,
                                  rpeaks=rpeaks,
                                  sampling_rate=sampling_rate,
                                  tol=0.05)
    rpeaks_orignal = np.unique(rpeaks)
    rr_interval_orignal = np.diff(rpeaks_orignal)
    rpeaks_whithoutfirst = rpeaks_orignal[1:]
    rpeaks_whithoutfirst = rpeaks_orignal

    outlier = []
    for jk in range(len(rr_interval_orignal)):
        if rr_interval_orignal[jk] >= sampling_rate * 2 or rr_interval_orignal[jk] <= sampling_rate * 0.4:
            if filtered[rr_interval_orignal[jk]] >= filtered[rr_interval_orignal[jk-1]]:
                outlier.append(jk-1)
            else:
                outlier.append(jk)

    outlier.reverse()
    rr_interval_outlier = np.asarray(rr_interval_orignal)
    for jk1 in outlier:
        rr_interval_outlier = np.delete(rr_interval_outlier, jk1)
        rpeaks_whithoutfirst = np.delete(rpeaks_whithoutfirst, jk1)
    return rpeaks_whithoutfirst.tolist(), filtered
Exemplo n.º 21
0
    sampling_rate = 960.0  # sampling rate
    Ts = 1.0 / sampling_rate  # sampling interval
    sm_size = int(0.08 * sampling_rate) #
    t = []
    eye_left = []

    for i in range(0, len(data_ch1)):
        t.append(i*Ts)

    order = int(0.3 * sampling_rate)

    # Filter Data
    filtered_data_ch1, _, _ = st.filter_signal(signal=data_ch1_arr,
                                               ftype='FIR',
                                               band='bandpass',
                                               order=order,
                                               frequency=[2, 50],
                                               sampling_rate=sampling_rate)

    filtered_data_ch2, _, _ = st.filter_signal(signal=data_ch2_arr,
                                               ftype='FIR',
                                               band='bandpass',
                                               order=order,
                                               frequency=[2, 50],
                                               sampling_rate=sampling_rate)


    # Smooth
    filtered_data_ch1, _ = st.smoother(signal=filtered_data_ch1,
                                       kernel='hamming',
                                       size=sm_size, mirror=True)
Exemplo n.º 22
0
def preprocess_signal(raw_sig: np.ndarray,
                      fs: Real,
                      config: Optional[ED] = None) -> Dict[str, np.ndarray]:
    """ finished, checked,

    Parameters
    ----------
    raw_sig: ndarray,
        the raw ecg signal
    fs: real number,
        sampling frequency of `raw_sig`
    config: dict, optional,
        extra process configuration,
        `PreprocCfg` will be updated by this `config`

    Returns
    -------
    retval: dict,
        with items
        - 'filtered_ecg': the array of the processed ecg signal
        - 'rpeaks': the array of indices of rpeaks; empty if 'rpeaks' in `config` is not set

    NOTE
    ----
    output (`retval`) are resampled to have sampling frequency
    equal to `config.fs` (if `config` has item `fs`) or `PreprocCfg.fs`
    """
    filtered_ecg = raw_sig.copy()

    cfg = deepcopy(PreprocCfg)
    cfg.update(deepcopy(config) or {})

    if fs != cfg.fs:
        filtered_ecg = resample(filtered_ecg,
                                int(round(len(filtered_ecg) * cfg.fs / fs)))

    # remove baseline
    if 'baseline' in cfg.preproc:
        window1 = 2 * (cfg.baseline_window1 //
                       2) + 1  # window size must be odd
        window2 = 2 * (cfg.baseline_window2 // 2) + 1
        baseline = median_filter(filtered_ecg, size=window1, mode='nearest')
        baseline = median_filter(baseline, size=window2, mode='nearest')
        filtered_ecg = filtered_ecg - baseline

    # filter signal
    if 'bandpass' in cfg.preproc:
        filtered_ecg = filter_signal(
            signal=filtered_ecg,
            ftype='FIR',
            band='bandpass',
            order=int(0.3 * fs),
            sampling_rate=fs,
            frequency=cfg.filter_band,
        )['signal']

    if cfg.rpeaks and cfg.rpeaks.lower() not in DL_QRS_DETECTORS:
        # dl detectors not for parallel computing using `mp`
        detector = QRS_DETECTORS[cfg.rpeaks.lower()]
        rpeaks = detector(sig=filtered_ecg, fs=fs).astype(int)
    else:
        rpeaks = np.array([], dtype=int)

    retval = ED({
        "filtered_ecg": filtered_ecg,
        "rpeaks": rpeaks,
    })

    return retval
Exemplo n.º 23
0
        diff = time.time() - start
    # datafile.close()

    # Numpy Array Creation
    # data = np.loadtxt(filepath)
    samplrate = (data.size) / 10.0
    samplrate = float(samplrate)

    # Powerline Interference Frequency Filter
    lowfiltered = butter_lowpass_filter(data, lowcut, samplingf, 5)

    # Filter Signal For Smoothing
    order = int(0.3 * samplrate)
    filtered, _, _ = st.filter_signal(signal=lowfiltered,
                                      ftype='FIR',
                                      band='bandpass',
                                      order=order,
                                      frequency=[3, 45],
                                      sampling_rate=samplrate)
    # Normalization
    filtered -= basedrift
    filtered *= scalefactor

    # Save to TXT file
    np.savetxt(filepath, filtered)
    counter = counter + 1


# Low pass filter functions
def butter_lowpass(cutoff, samplef, order=5):
    nyq = 0.5 * samplef  # Nyquist frequency
    normal_cutoff = cutoff / nyq
Exemplo n.º 24
0
    def call_filter(
            self,
            filter_type,
            filter_band,
            first_cutoff,
            second_cutoff,
            order,
            max_ripple,
            min_attenuation):
        """
        Call specified filter function on all audio clips

        :param filter_type: type of filter
        :param filter_band:  band of filter
        :param first_cutoff: first cutoff frequency
        :param second_cutoff: second cutoff frequency
        :param order: filter order
        :param max_ripple: the maximum ripple
        :param min_attenuation: the minimum attenuatio
        :return: Void
        """

        if self.data is None:
            return

        filterBand = (''.join(c for c in filter_band if c not in "-")).lower()
        filterType = self.convertTypeToStr(filter_type)

        error = None

        self.X = []
        self.metas = []

        try:
            for i in range(len(self.data.metas)):
                if self.data.X != []:
                    input_data = self.data.X[i]
                else:
                    input_data = read(self.data.metas[i][1])[1]
                    if len(input_data.shape) > 1:
                        input_data = input_data[:, 0]

                if filterType == "FIR" or filterType == "butter" or filterType == "bessel":
                    if filterBand == "lowpass" or filterBand == "highpass":
                        filtered = st.filter_signal(input_data,
                                                    ftype=filterType,
                                                    band=filterBand,
                                                    order=order,
                                                    frequency=first_cutoff,
                                                    sampling_rate=self.data.metas[i][-1])
                    else:
                        filtered = st.filter_signal(input_data, ftype=filterType, band=filterBand, order=order,
                                                    frequency=[first_cutoff, second_cutoff],
                                                    sampling_rate=self.data.metas[i][-1])
                elif filterType == "cheby1":
                    if filterBand == "lowpass" or filterBand == "highpass":
                        filtered = st.filter_signal(input_data,
                                                    ftype=filterType,
                                                    band=filterBand,
                                                    order=order,
                                                    frequency=first_cutoff,
                                                    sampling_rate=self.data.metas[i][-1],
                                                    rp=max_ripple)
                    else:
                        filtered = st.filter_signal(input_data, ftype=filterType, band=filterBand, order=order,
                                                    frequency=[first_cutoff, second_cutoff], sampling_rate=self.data.metas[i][-1],
                                                    rp=max_ripple)
                elif filterType == "cheby2":
                    if filterBand == "lowpass" or filterBand == "highpass":
                        filtered = st.filter_signal(input_data,
                                                    ftype=filterType,
                                                    band=filterBand,
                                                    order=order,
                                                    frequency=first_cutoff,
                                                    sampling_rate=self.data.metas[i][-1],
                                                    rs=min_attenuation)
                    else:
                        filtered = st.filter_signal(input_data, ftype=filterType, band=filterBand, order=order,
                                                    frequency=[first_cutoff, second_cutoff], sampling_rate=self.data.metas[i][-1],
                                                    rs=min_attenuation)

                else:
                    if filterBand == "lowpass" or filterBand == "highpass":
                        filtered = st.filter_signal(input_data,
                                                    ftype=filterType,
                                                    band=filterBand,
                                                    order=order,
                                                    frequency=first_cutoff,
                                                    sampling_rate=self.data.metas[i][-1],
                                                    rp=max_ripple,
                                                    rs=min_attenuation)
                    else:
                        filtered = st.filter_signal(input_data,
                                                    ftype=filterType,
                                                    band=filterBand,
                                                    order=order,
                                                    frequency=[first_cutoff,
                                                               second_cutoff],
                                                    sampling_rate=self.data.metas[i][-1],
                                                    rp=max_ripple,
                                                    rs=min_attenuation)

                self.new_tmp_dir = os.path.dirname(
                    self.data.metas[i][1]) + os.sep + "filtered-" + self.tmp_dir_id + os.sep

                if not os.path.exists(self.new_tmp_dir):
                    os.makedirs(self.new_tmp_dir)
                    self.new_tmp_dirs.append(self.new_tmp_dir)

                filename = self.new_tmp_dir + self.data.metas[i][0] + ".wav"
                self.metas.append([self.data.metas[i][0],
                                   filename,
                                   self.data.metas[i][2],
                                   self.data.metas[i][3],
                                   self.data.metas[i][4]])

                data = filtered["signal"]
                data = data / data.max()
                data = data * (2 ** 15 - 1)
                data = data.astype(numpy.int16)
                write(filename, self.data.metas[i][-1], data)

        except Exception as ex:
            error = ex

        if not error:
            self.info.setStyleSheet(success_green)
            self.info.setText(
                filter_type +
                " " +
                filter_band +
                " " +
                "filter successful!")
            orange_table = Orange.data.Table.from_numpy(
                self.data.domain, numpy.empty((len(self.data.Y), 0), dtype=float),
                self.data.Y, self.metas
            )

            self.send("Filtered data", orange_table)
        if error:
            self.info.setStyleSheet(error_red)
            self.info.setText("An error occurred:\n{}".format(error))
            return
Exemplo n.º 25
0
def preprocess_single_lead_signal(raw_sig: np.ndarray,
                                  fs: Real,
                                  bl_win: Optional[List[Real]] = None,
                                  band_fs: Optional[List[Real]] = None,
                                  rpeak_fn: Optional[str] = None,
                                  verbose: int = 0) -> Dict[str, np.ndarray]:
    """ finished, checked,

    perform preprocessing for single lead ecg signal (with units in mV),
    preprocessing may include median filter, bandpass filter, and rpeaks detection, etc.

    Parameters:
    -----------
    raw_sig: ndarray,
        the raw ecg signal, with units in mV
    fs: real number,
        sampling frequency of `raw_sig`
    bl_win: list (of 2 real numbers), optional,
        window (units in second) of baseline removal using `median_filter`,
        the first is the shorter one, the second the longer one,
        a typical pair is [0.2, 0.6],
        if is None or empty, baseline removal will not be performed
    band_fs: list (of 2 real numbers), optional,
        frequency band of the bandpass filter,
        a typical pair is [0.5, 45],
        be careful when detecting paced rhythm,
        if is None or empty, bandpass filtering will not be performed
    rpeak_fn: str, optional,
        name of the function detecting rpeaks,
        can be one of keys of `QRS_DETECTORS`, case insensitive
    verbose: int, default 0,
        print verbosity

    Returns:
    --------
    retval: dict,
        with items
        - 'filtered_ecg': the array of the processed ecg signal
        - 'rpeaks': the array of indices of rpeaks; empty if `rpeak_fn` is not given
    """
    filtered_ecg = raw_sig.copy()

    # remove baseline
    if bl_win:
        window1 = 2 * (int(bl_win[0] * fs) // 2) + 1  # window size must be odd
        window2 = 2 * (int(bl_win[1] * fs) // 2) + 1
        baseline = median_filter(filtered_ecg, size=window1, mode='nearest')
        baseline = median_filter(baseline, size=window2, mode='nearest')
        filtered_ecg = filtered_ecg - baseline

    # filter signal
    if band_fs:
        filtered_ecg = filter_signal(
            signal=filtered_ecg,
            ftype='FIR',
            # ftype='butter',
            band='bandpass',
            order=int(0.3 * fs),
            sampling_rate=fs,
            frequency=band_fs,
        )['signal']

    if rpeak_fn:
        rpeaks = QRS_DETECTORS[rpeak_fn.lower()](filtered_ecg, fs).astype(int)
    else:
        rpeaks = np.array([], dtype=int)

    retval = ED({
        "filtered_ecg": filtered_ecg,
        "rpeaks": rpeaks,
    })

    if verbose >= 3:
        from utils.misc import plot_single_lead
        from cfg import PlotCfg
        t = np.arange(len(filtered_ecg)) / fs
        waves = {
            "qrs":
            get_mask(
                shape=len(filtered_ecg),
                critical_points=rpeaks,
                left_bias=ms2samples(PlotCfg.qrs_radius, fs),
                right_bias=ms2samples(PlotCfg.qrs_radius, fs),
                return_fmt="intervals",
            )
        }
        plot_single_lead(t=t,
                         sig=filtered_ecg,
                         ticks_granularity=2,
                         waves=waves)

    return retval
Exemplo n.º 26
0
def reshape_resting_ecg_to_tidy(
    sample_id: Union[int, str], folder: Optional[str] = None, tmap: TensorMap = DEFAULT_RESTING_ECG_SIGNAL_TMAP,
) -> pd.DataFrame:
  """Wrangle resting ECG data to tidy.

  Args:
    sample_id: The id of the ECG sample to retrieve.
    folder: The local or Cloud Storage folder under which the files reside.
    tmap: The TensorMap to use for ECG input.

  Returns:
    A pandas dataframe in tidy format or print a notebook-friendly error and return an empty dataframe.
  """
  if folder is None:
    folder = get_resting_ecg_hd5_folder(sample_id)

  data: Dict[str, Any] = {'lead': [], 'raw': [], 'ts_reference': [], 'filtered': [], 'filtered_1': [], 'filtered_2': []}

  with tempfile.TemporaryDirectory() as tmpdirname:
    sample_hd5 = str(sample_id) + '.hd5'
    local_path = os.path.join(tmpdirname, sample_hd5)
    try:
      tf.io.gfile.copy(src=os.path.join(folder, sample_hd5), dst=local_path)
    except (tf.errors.NotFoundError, tf.errors.PermissionDeniedError) as e:
      print(f'''Warning: Resting ECG not available for sample {sample_id} in folder {folder}.
      Use the folder parameter to read HD5s from a different directory or bucket.\n\n{e.message}''')
      return pd.DataFrame(data)

    with h5py.File(local_path, mode='r') as hd5:
      try:
        signals = tmap.tensor_from_file(tmap, hd5)
      except (KeyError, ValueError) as e:
        print(f'''Warning: Resting ECG TMAP {tmap.name} not available for sample {sample_id}.
        Use the tmap parameter to choose a different TMAP.\n\n{e}''')
        _examine_available_keys(hd5)
        return pd.DataFrame(data)
      for (lead, channel) in ECG_REST_LEADS.items():
        signal = signals[:, channel]
        signal_length = len(signal)
        data['raw'].extend(signal)
        data['lead'].extend([lead] * signal_length)
        data['ts_reference'].extend(np.array([i*1./(SAMPLING_RATE+1.) for i in range(0, signal_length)]))
        filtered, _, _ = filter_signal(
            signal=signal,
            ftype='FIR',
            band='bandpass',
            order=int(0.3 * SAMPLING_RATE),
            frequency=[.9, 50],
            sampling_rate=SAMPLING_RATE,
        )
        data['filtered'].extend(filtered)
        filtered_1, _, _ = filter_signal(
            signal=signal,
            ftype='FIR',
            band='bandpass',
            order=int(0.3 * SAMPLING_RATE),
            frequency=[.9, 20],
            sampling_rate=SAMPLING_RATE,
        )
        data['filtered_1'].extend(filtered_1)
        filtered_2, _, _ = filter_signal(
            signal=signal,
            ftype='FIR',
            band='bandpass',
            order=int(0.3 * SAMPLING_RATE),
            frequency=[.9, 30],
            sampling_rate=SAMPLING_RATE,
        )
        data['filtered_2'].extend(filtered_2)

  signal_df = pd.DataFrame(data)
  # Convert the raw signal to mV.
  signal_df['raw_mV'] = signal_df['raw'] * RAW_SCALE
  signal_df['filtered_mV'] = signal_df['filtered'] * RAW_SCALE
  signal_df['filtered_1_mV'] = signal_df['filtered_1'] * RAW_SCALE
  signal_df['filtered_2_mV'] = signal_df['filtered_2'] * RAW_SCALE
  # Reshape to tidy (long format).
  tidy_signal_df = signal_df.melt(
      id_vars=['lead', 'ts_reference'],
      value_vars=['raw_mV', 'filtered_mV', 'filtered_1_mV', 'filtered_2_mV'],
      var_name='filtering', value_name='signal_mV',
  )

  # The leads have a meaningful order, apply the order to this column.
  lead_factor_type = pd.api.types.CategoricalDtype(
      categories=[
          'strip_I', 'strip_aVR', 'strip_V1', 'strip_V4',
          'strip_II', 'strip_aVL', 'strip_V2', 'strip_V5',
          'strip_III', 'strip_aVF', 'strip_V3', 'strip_V6',
      ],
      ordered=True,
  )
  tidy_signal_df['lead'] = tidy_signal_df.lead.astype(lead_factor_type)

  return tidy_signal_df
Exemplo n.º 27
0
            data.append(float(str(row[1])))
            counter+= 1

    data_arr = np.array(data)

    sampling_rate = 256.0  # sampling rate
    Ts = 1.0 / sampling_rate  # sampling interval
    t = []

    for i in range(0, len(data)):
        t.append(i*Ts)

    order = int(0.3 * sampling_rate)

    # filtered_data = ecg.ecg(data_arr, 256, False)['filtered']
    filtered_data, _, _ = st.filter_signal(signal=data_arr,
                                           ftype='FIR',
                                           band='bandpass',
                                           order=order,
                                           frequency=[3, 45],
                                           sampling_rate=sampling_rate)

    print(filtered_data)

    plt.plot(t, filtered_data, 'r')
    #plt.plot(t, data, 'b')
    plt.xlabel("Time")
    plt.ylabel("Amplitude (V)")

    plt.show()
Exemplo n.º 28
0
def fir(signal,
        order=2,
        cutoff=[50, 450],
        ftype='bandpass',
        fs=1000.0,
        plot='yes',
        **kwargs):
    """
    Apply a FIR filter to the input signal.

    Input parameters
    ----------------
    signal: ndarray
        the input signal to be filter
    order: int, optional
        the order of the filter; default set to 2
    cutoff: scalar (int or float) or 2 length sequence (for band-pass and band-stop filter)
        the critical frequency; default set to [50,500]
    ftype: str, optional
        type of filter to be used; default set to 'bandpass'
        types: 'lowpass','highpass', 'bandpass', 'bandstop'
    fs: int or float, optional
        sampling rate
    plot: str - yes/Y or no/N (non-case sensitive), optional
        plot the filtered signal or not; default set to yes
    **kwargs: dict, optional
        Additional keyword arguments are passed to the underlying
        scipy.signal function

    Output
    ------
    Output will be in the format --> filtersig

    filtersig: ndarray
        the filtered signal
    """

    #cutoff error
    try:
        cutoff = float(cutoff)
    except TypeError:
        cutoff = np.array(cutoff)
    except ValueError:
        raise ValueError("Cutoff can only be an int, float or numpy array.")

    if isinstance(cutoff, np.ndarray):
        if cutoff.size == 2:
            if isinstance(cutoff[0], complex):
                raise TypeError("Cutoff frequency cannot be complex.")
            if isinstance(cutoff[-1], complex):
                raise TypeError("Cutoff frequency cannot be complex.")
        else:
            raise ValueError(
                "Cutoff must be a scalar (int or float) or 2 length sequence (list or numpy array)."
            )

    #sampling frequency error
    try:
        fs = float(fs)
    except TypeError:
        raise TypeError("Sampling frequency (fs) must be int or float.")
    except ValueError:
        raise ValueError("Sampling frequency (fs) must be int or float.")

    #signal error
    if isinstance(signal, (list, np.ndarray)):
        signal = np.array(signal)
    elif isinstance(signal, (int, float)):
        raise ValueError("Signal should be a list or numpy array.")
    else:
        raise TypeError("Signal should be a list or numpy array.")

    for i in signal:
        if isinstance(i, complex):
            raise ValueError("Signal cannot contain complex elements.")

    #order error
    try:
        order = int(order)
    except TypeError:
        raise TypeError("Order must be an int.")
    except ValueError:
        raise ValueError("Order must be an int.")

    #filter type error
    if ftype in ['lowpass', 'highpass', 'bandpass', 'bandstop']:
        pass
    elif isinstance(ftype, str):
        raise ValueError(
            "Filter type must be 'lowpass', 'highpass', 'bandpass', 'bandstop'."
        )
    else:
        raise TypeError("Filter type must be a string.")

    #plot error
    if plot in ['Yes', 'yes', 'No', 'no', 'Y', 'y', 'N', 'n', 'YES', 'NO']:
        pass
    elif isinstance(plot, str):
        raise ValueError("Plot can be Yes/Y or No/N (non-case sensitive).")
    else:
        raise TypeError(
            "Plot must be a string - Yes/Y or No/N (non-case sensitive).")

    #filtering
    filtersig = tools.filter_signal(signal,
                                    ftype='FIR',
                                    band=ftype,
                                    order=order,
                                    frequency=cutoff,
                                    sampling_rate=fs,
                                    **kwargs)
    filtersig = filtersig['signal']

    #plotting
    if plot in ['yes', 'Yes', 'Y', 'y', 'YES']:
        time = np.arange(0, len(signal) / fs, 1 / fs)
        plt.figure(figsize=(12, 6))
        plt.subplot(211)
        plt.plot(time, signal, label="Raw signal")
        plt.suptitle("Raw & Filtered signal")
        plt.ylabel("Amplitude")
        plt.legend()

        plt.subplot(212)
        plt.plot(time, filtersig, c='#ff7f0e', label="Filtered signal")
        plt.xlabel("Time")
        plt.ylabel("Amplitude")
        plt.legend()
        plt.tight_layout()
        plt.show()

    return filtersig
Exemplo n.º 29
0
            data.append(float(str(row[1])))
            counter += 1

    data_arr = np.array(data)

    sampling_rate = 256.0  # sampling rate
    Ts = 1.0 / sampling_rate  # sampling interval
    t = []

    for i in range(0, len(data)):
        t.append(i * Ts)

    order = int(0.3 * sampling_rate)

    # filtered_data = ecg.ecg(data_arr, 256, False)['filtered']
    filtered_data, _, _ = st.filter_signal(signal=data_arr,
                                           ftype='FIR',
                                           band='bandpass',
                                           order=order,
                                           frequency=[3, 45],
                                           sampling_rate=sampling_rate)

    print(filtered_data)

    plt.plot(t, filtered_data, 'r')
    #plt.plot(t, data, 'b')
    plt.xlabel("Time")
    plt.ylabel("Amplitude (V)")

    plt.show()
Exemplo n.º 30
0
def run_algo(algorithm: str, sig: numpy.ndarray,
             freq_sampling: int) -> List[int]:
    """
    run a qrs detector on a signal

    :param algorithm: name of the qrs detector to use
    :type algorithm: str
    :param sig: values of the sampled signal to study
    :type sig: ndarray
    :param freq_sampling: value of sampling frequency of the signal
    :type freq_sampling: int
    :return: localisations of qrs detections
    :rtype: list(int)
    """
    detectors = Detectors(freq_sampling)
    if algorithm == 'Pan-Tompkins-ecg-detector':
        qrs_detections = detectors.pan_tompkins_detector(sig)
    elif algorithm == 'Hamilton-ecg-detector':
        qrs_detections = detectors.hamilton_detector(sig)
    elif algorithm == 'Christov-ecg-detector':
        qrs_detections = detectors.christov_detector(sig)
    elif algorithm == 'Engelse-Zeelenberg-ecg-detector':
        qrs_detections = detectors.engzee_detector(sig)
    elif algorithm == 'SWT-ecg-detector':
        qrs_detections = detectors.swt_detector(sig)
    elif algorithm == 'Matched-filter-ecg-detector' and freq_sampling == 360:
        qrs_detections = detectors.matched_filter_detector(
            sig, 'templates/template_360hz.csv')
    elif algorithm == 'Matched-filter-ecg-detector' and freq_sampling == 250:
        qrs_detections = detectors.matched_filter_detector(
            sig, 'templates/template_250hz.csv')
    elif algorithm == 'Two-average-ecg-detector':
        qrs_detections = detectors.two_average_detector(sig)
    elif algorithm == 'Hamilton-biosppy':
        qrs_detections = bsp_ecg.ecg(signal=sig,
                                     sampling_rate=freq_sampling,
                                     show=False)[2]
    elif algorithm == 'Christov-biosppy':
        order = int(0.3 * freq_sampling)
        filtered, _, _ = bsp_tools.filter_signal(signal=sig,
                                                 ftype='FIR',
                                                 band='bandpass',
                                                 order=order,
                                                 frequency=[3, 45],
                                                 sampling_rate=freq_sampling)
        rpeaks, = bsp_ecg.christov_segmenter(signal=filtered,
                                             sampling_rate=freq_sampling)
        rpeaks, = bsp_ecg.correct_rpeaks(signal=filtered,
                                         rpeaks=rpeaks,
                                         sampling_rate=freq_sampling,
                                         tol=0.05)
        _, qrs_detections = bsp_ecg.extract_heartbeats(
            signal=filtered,
            rpeaks=rpeaks,
            sampling_rate=freq_sampling,
            before=0.2,
            after=0.4)
    elif algorithm == 'Engelse-Zeelenberg-biosppy':
        order = int(0.3 * freq_sampling)
        filtered, _, _ = bsp_tools.filter_signal(signal=sig,
                                                 ftype='FIR',
                                                 band='bandpass',
                                                 order=order,
                                                 frequency=[3, 45],
                                                 sampling_rate=freq_sampling)
        rpeaks, = bsp_ecg.engzee_segmenter(signal=filtered,
                                           sampling_rate=freq_sampling)
        rpeaks, = bsp_ecg.correct_rpeaks(signal=filtered,
                                         rpeaks=rpeaks,
                                         sampling_rate=freq_sampling,
                                         tol=0.05)
        _, qrs_detections = bsp_ecg.extract_heartbeats(
            signal=filtered,
            rpeaks=rpeaks,
            sampling_rate=freq_sampling,
            before=0.2,
            after=0.4)
    elif algorithm == 'Gamboa-biosppy':
        order = int(0.3 * freq_sampling)
        filtered, _, _ = bsp_tools.filter_signal(signal=sig,
                                                 ftype='FIR',
                                                 band='bandpass',
                                                 order=order,
                                                 frequency=[3, 45],
                                                 sampling_rate=freq_sampling)
        rpeaks, = bsp_ecg.gamboa_segmenter(signal=filtered,
                                           sampling_rate=freq_sampling)
        rpeaks, = bsp_ecg.correct_rpeaks(signal=filtered,
                                         rpeaks=rpeaks,
                                         sampling_rate=freq_sampling,
                                         tol=0.05)
        _, qrs_detections = bsp_ecg.extract_heartbeats(
            signal=filtered,
            rpeaks=rpeaks,
            sampling_rate=freq_sampling,
            before=0.2,
            after=0.4)
    elif algorithm == 'mne-ecg':
        qrs_detections = mne_ecg.qrs_detector(freq_sampling, sig)
    elif algorithm == 'heartpy':
        rol_mean = rolling_mean(sig, windowsize=0.75, sample_rate=100.0)
        qrs_detections = hp_pkdetection.detect_peaks(
            sig, rol_mean, ma_perc=20, sample_rate=100.0)['peaklist']
    elif algorithm == 'gqrs-wfdb':
        qrs_detections = processing.qrs.gqrs_detect(sig=sig, fs=freq_sampling)
    elif algorithm == 'xqrs-wfdb':
        qrs_detections = processing.xqrs_detect(sig=sig, fs=freq_sampling)
    else:
        raise ValueError(
            f'Sorry... unknown algorithm. Please check the list {algorithms_list}'
        )
    cast_qrs_detections = [int(element) for element in qrs_detections]
    return cast_qrs_detections
Exemplo n.º 31
0
def resp(signal=None, sampling_rate=1000., show=True):
    """Process a raw Respiration signal and extract relevant signal features
    using default parameters.
    Parameters
    ----------
    signal : array
        Raw Respiration signal.
    sampling_rate : int, float, optional
        Sampling frequency (Hz).
    show : bool, optional
        If True, show a summary plot.
    Returns

    -------
    ts : array
        Signal time axis reference (seconds).
    filtered : array
        Filtered Respiration signal.
    zeros : array
        Indices of Respiration zero crossings.
    resp_rate_ts : array
        Inspiration rate time axis reference (seconds).
    resp_rate : array
        Instantaneous respiration rate (Hz).
    """

    # check inputs
    if signal is None:
        raise TypeError("Please specify an input signal.")

    # ensure numpy
    signal = np.array(signal)
    sampling_rate = float(sampling_rate)

    # filter signal
    # 0.1 ~~ 0.35 Hzのバンドパスフィルタ
    filtered, _, _ = st.filter_signal(signal=signal,
                                      ftype='butter',
                                      band='bandpass',
                                      order=2,
                                      frequency=[0.1, 0.35],
                                      sampling_rate=sampling_rate)

    # compute zero crossings
    filtered = filtered - np.mean(filtered)

    # zeros
    df = np.diff(np.sign(filtered))
    inspiration = np.nonzero(df > 0)[0]
    expiration = np.nonzero(df < 0)[0]

    if len(inspiration) < 2:
        rate_idx = []
        rate = []
    else:
        # compute resp peaks between inspiration and expiration
        peaks = []
        for i in range(len(inspiration) - 1):
            cycle = filtered[inspiration[i]:inspiration[i + 1]]
            peaks.append(np.argmax(cycle) + inspiration[i])
        # list to array
        peaks = np.array(peaks)

        # compute respiration rate
        rate_idx = inspiration[1:]
        rate = sampling_rate * (1. / np.diff(inspiration))

        # physiological limits
        # 0.35Hz以下のresp_rateは省かれる
        indx = np.nonzero(rate <= 0.35)
        rate_idx = rate_idx[indx]
        rate = rate[indx]

        # smooth with moving average
        size = 3
        rate, _ = st.smoother(signal=rate,
                              kernel='boxcar',
                              size=size,
                              mirror=True)

    # get time vectors
    length = len(signal)
    T = (length - 1) / sampling_rate
    ts = np.linspace(0, T, length, endpoint=True)
    ts_rate = ts[rate_idx]

    # plot
    if show:
        plotting.plot_resp(ts=ts,
                           raw=signal,
                           filtered=filtered,
                           zeros=zeros,
                           resp_rate_ts=ts_rate,
                           resp_rate=rate,
                           path=None,
                           show=True)
    # output
    args = (ts, filtered, ts_rate, rate, inspiration, expiration, peaks)
    names = ('ts', 'filtered', 'resp_rate_ts', 'resp_rate', 'inspiration',
             'expiration', 'peaks')
    return utils.ReturnTuple(args, names)
Exemplo n.º 32
0
def scale_maxabs(arr, maxabs, thres):
    arr = (arr / maxabs) * thres
    return arr


def apply_threshold(arr, thres):
    arr[arr > thres] = thres
    arr[arr < -thres] = thres
    return arr


order = int(0.3 * 100)
filtered_train_x, _, _ = st.filter_signal(signal=X_train,
                                          ftype='FIR',
                                          band='bandpass',
                                          order=order,
                                          frequency=[3, 45],
                                          sampling_rate=100)
filtered_test_x, _, _ = st.filter_signal(signal=X_test,
                                         ftype='FIR',
                                         band='bandpass',
                                         order=order,
                                         frequency=[3, 45],
                                         sampling_rate=100)
X_threshold = apply_threshold(filtered_train_x, 1000)
test_x_thres = apply_threshold(filtered_test_x, 1000)
current_x = scale_maxabs(X_threshold, np.max(np.abs(X_threshold)), 30)
current_test_x = scale_maxabs(test_x_thres, np.max(np.abs(test_x_thres)), 30)
import os
data_dir = '../../subsampled_data'
Exemplo n.º 33
0
def plot_class_activation_map_template(model, index, time_series, labels, fs):
    """
    Plots one univariate time series

    Parameters
    ----------
    model : object
        Active model with live session
    index : int
        time series id
    time_series : np.array([m, length])
        image array
    labels : np.array([m,])
        a 1D array of length m training examples containing class labels
    fs : int
        sample frequency
    """

    # Label lookup
    label_lookup = [
        'Normal Sinus Rhythm', 'Atrial Fibrillation', 'Other Rhythm'
    ]

    # Get logits
    logits = model.sess.run(fetches=[model.graph.logits],
                            feed_dict={
                                model.graph.x: time_series[[index]],
                                model.graph.y: labels[[index]],
                                model.graph.is_training: False,
                            })

    # Get output conv
    conv = model.sess.run(fetches=[model.graph.net],
                          feed_dict={
                              model.graph.x: time_series[[index]],
                              model.graph.y: labels[[index]],
                              model.graph.is_training: False,
                          })

    # Get class activation map
    cam = model.sess.run(get_class_map(conv[0], np.squeeze(np.argmax(logits))))
    cam = ((cam - cam.min()) / (cam.max() - cam.min()))
    cam = cam[0, :, 0]
    cam_time = np.arange(conv[0].shape[1]) / (conv[0].shape[1] / 60)

    # Get non-zero-pad indices
    non_zero_index = np.where(time_series[index, :, 0] != 0)[0]

    # Get non-zero-pad waveform
    time_series_filt = time_series[index, non_zero_index, 0]
    time_series_filt_ts = np.arange(time_series_filt.shape[0]) * 1 / fs

    # Linear interpolation
    cam_time_intrp = np.arange(time_series[index].shape[0]) * 1 / fs
    cam_intrp = np.interp(cam_time_intrp, cam_time, cam)

    # Get non-zero-pad cam
    cam_filt = cam_intrp[non_zero_index]

    # Setup figure
    fig = plt.figure(figsize=(15, 15))
    fig.subplots_adjust(wspace=0, hspace=0)
    ax1 = plt.subplot2grid((3, 5), (0, 0), colspan=5)
    ax2 = plt.subplot2grid((3, 5), (1, 0), colspan=5)
    ax3 = plt.subplot2grid((3, 5), (2, 1), colspan=3)

    prob = model.sess.run(tf.nn.softmax(logits[0]))

    # Set plot title
    ax1.set_title('True Label: ' +
                  label_lookup[np.squeeze(np.argmax(labels[index]))] + '\n' +
                  'Predicted Label: ' +
                  label_lookup[np.squeeze(np.argmax(logits))] + '\n' +
                  'Normal Sinus Rhythm: ' + str(np.round(prob[0][0], 2)) +
                  '     Atrial Fibrillation: ' + str(np.round(prob[0][1], 2)) +
                  '     Other Rhythm: ' + str(np.round(prob[0][2], 2)),
                  fontsize=20,
                  y=1.03)

    # Plot image
    ax1.plot(time_series_filt_ts, time_series_filt, '-k', lw=1.5)

    # Axes labels
    ax1.set_ylabel('Normalized Amplitude', fontsize=22)
    ax1.set_xlim([0, time_series_filt_ts.max()])
    ax1.tick_params(labelbottom='off')
    ax1.yaxis.set_tick_params(labelsize=16)

    # Plot CAM
    ax2.plot(time_series_filt_ts, cam_filt, '-k', lw=1.5)

    # Axes labels
    ax2.set_xlabel('Time, seconds', fontsize=22)
    ax2.set_ylabel('Class Activation Map', fontsize=22)
    ax2.set_xlim([0, time_series_filt_ts.max()])
    ax2.set_ylim([cam_filt.min() - 0.05, cam_filt.max() + 0.05])
    ax2.xaxis.set_tick_params(labelsize=16)
    ax2.yaxis.set_tick_params(labelsize=16)

    # Get ECG object
    ecg_object = ecg.ecg(time_series_filt, sampling_rate=fs, show=False)

    # Get waveform templates
    templates, _ = _get_templates(time_series_filt, ecg_object['rpeaks'], 0.4,
                                  0.6, fs)

    cam_filt, _, _ = filter_signal(signal=cam_filt,
                                   ftype='FIR',
                                   band='bandpass',
                                   order=int(0.3 * fs),
                                   frequency=[3, 100],
                                   sampling_rate=fs)

    # Get cam templates
    cam_templates, _ = _get_templates(cam_filt, ecg_object['rpeaks'], 0.4, 0.6,
                                      fs)

    templates_ts = np.linspace(-250, 400, templates.shape[0], endpoint=False)

    ax3.plot(templates_ts, templates, '-', color=[0.7, 0.7, 0.7])
    ax3.plot(templates_ts, np.median(templates, axis=1), '-k')

    ax3.set_ylim([-0.75, 1.5])

    ax4 = ax3.twinx()
    ax3.set_xlim([-250, 400])
    ax4.set_xlim([-250, 400])
    ax4.plot(templates_ts, cam_templates, '-r', lw=0.25, alpha=0.5)
    ax4.plot(templates_ts, np.mean(cam_templates, axis=1), '-r')

    ax4.set_ylim([
        np.median(cam_templates, axis=1).min() - 0.02,
        np.median(cam_templates, axis=1).max() + 0.02
    ])

    plt.savefig(
        r'C:\Users\sgoodfellow\Documents\Sebastian\Sick Kids\Publications\Conference\mlforhc\2018\Draft\template.eps'
    )

    plt.show()