EMG bandwidth to calculate Shannon–Hartley theorem

katuto03katuto03 Argentina
edited May 2024 in Ganglion

Hi, I'm currently trying with a team to calculate an estimative channel capacity of a human arm for EMG signals. For that we are applying the Shannon-Hartley theorem that implies some calculations. What we're struggling the most it's to justify an appropriate bandwidth for this theorem. We know in OpenBCI GUI and projects you usually use a bandpass filter from 0.5 to 45.0Hz but we don't quite understand why. The thing is that for our calculation the SNR always wive us close to 1 so the bandwidth becomes crucial in the final result and we can't find anywhere some justification for which bandwidth to use to isolate the most only EMG signals. Any help on this matter would be appreciated. Thank you in advance.

Here is basically the calculation we are doing.

And this is our python code if needed:

import numpy as np
import pandas as pd
from scipy.signal import find_peaks
import matplotlib.pyplot as plt
from brainflow.data_filter import DataFilter, FilterTypes, NoiseTypes, AggOperations, DetrendOperations
from brainflow.board_shim import BoardShim, BoardIds

def main():
    test_name = "Ian-BB-3.1(unfiltered).csv"
    data_file = f"../official-tests/{test_name}"

    bandpass_low_limit = 0.5
    bandpass_high_limit = 45.0

    data = DataFilter.read_file(data_file)
    data_ch1 = data[1]
    sampling_rate = BoardShim.get_sampling_rate(BoardIds.GANGLION_BOARD.value)

    # Filters
    DataFilter.perform_rolling_filter(data_ch1, 2, AggOperations.MEAN.value)
    DataFilter.detrend(data_ch1, DetrendOperations.CONSTANT)
    DataFilter.perform_bandpass(data_ch1, sampling_rate, bandpass_low_limit, bandpass_high_limit, 2, FilterTypes.BUTTERWORTH_ZERO_PHASE, 0)
    DataFilter.remove_environmental_noise(data_ch1, sampling_rate, NoiseTypes.FIFTY.value)

    plt.figure()
    pd.DataFrame(data_ch1).plot(subplots=True)
    plt.savefig('original_signal.png')

    # Testing peak detection from Brainflow
    df_peaks = pd.DataFrame(np.transpose(data))
    df_peaks[1] = DataFilter.detect_peaks_z_score(data_ch1, lag=5, influence=0.1, threshold=10)
    plt.figure()
    df_peaks[1].plot(subplots=True)
    plt.savefig('peaks.png')

    # Plot
    plot_fft(data_ch1, 1, 200)
    bandwidth = bandpass_high_limit - bandpass_low_limit
    print("Bandwidth: %f" % bandwidth)

    SNR = calculate_snr(data_ch1)
    channel_capacity = calculate_channel_capacity(bandwidth, SNR)

    print("\nChannel Capacity: %.5f bps" % channel_capacity)


def calculate_snr(data):

    plt.figure()
    peaks, _ = find_peaks(data, prominence=(100, None))
    plt.plot(data)
    plt.plot(peaks, data[peaks], "x")
    plt.plot(np.zeros_like(data), "--", color="gray")
    plt.savefig("peaks2.png")

    # Peaks Standard Deviation
    peak_std = np.std(data[peaks])

    # Noise mask
    mask = np.ones(len(data), dtype=bool)
    mask[peaks] = False

    # Noise Standard Deviation
    noise_signal = data[mask]
    noise_signal_std = np.std(noise_signal)

    # Signal Standard Deviation
    signal_std = np.std(data)

    SNR = signal_std / noise_signal_std
    return SNR


def calculate_channel_capacity(bandwidth, snr):
    return bandwidth * np.log2(1 + snr)

Comments

  • wjcroftwjcroft Mount Shasta, CA
    edited May 2024

    @katuto03 said:
    ... We know in OpenBCI GUI and projects you usually use a bandpass filter from 0.5 to 45.0Hz but we don't quite understand why.

    That bandpass recommendation is mainly based on EEG usage. EEG below .5 Hz (even lower, below .1 Hz or .01 Hz) is considered a "DC offset" and generally not useful. EEG above 45 Hz (gamma band) gets close to mains frequencies and lower signal quality due to this noise.

    EMG in labs sometimes use higher sample rates, for example 500 Hz or 1000 Hz. However with Ganglion you are limited to 200 Hz sample rate. Technically by the Nyquist rule that would limit you to waveforms 100 Hz and below. But... a 100 Hz sine wave sampled at 200 Hz has tremendous alias effects. Imagine that the null points coincide with the sample times. Bad news. A better rule for maximum signal fidelity is to collect say 5 samples per waveform, instead of 2 or 3 or 4. So at 200 Hz you can get 'acceptable' fidelity for signals about (200 / 5 = 40) 40 Hz and below.

    Most EMG gathered with these types of sample rates is mainly interested in the 'envelope' of the maximum EMG samples voltage amplitudes. If you are doing EMG lab research and really need the high frequency details, then you want to use higher sample rates.

    https://www.google.com/search?q=emg+sample+rates

    https://www.sciencedirect.com/science/article/abs/pii/S1050641104000926
    "The effect of sampling frequency on EMG measures of occupational mechanical exposure"

    William

Sign In or Register to comment.