ecg-arrhythmia-detection / step1_preprocessing.py
Ranjith445's picture
ECG Arrhythmia Detection System
1cb40e2
Raw
History Blame Contribute Delete
4.44 kB
# step1_preprocessing.py
# Purpose: Load and clean raw ECG signals from your local MIT-BIH dataset
# Dataset path: D:\ecg_arr\mit-bih-arrhythmia-database-1.0.0\mit-bih-arrhythmia-database-1.0.0
# Output: Cleaned ECG signal + comparison plot saved as step1_output.png
import numpy as np
import matplotlib.pyplot as plt
import wfdb
from scipy.signal import butter, filtfilt
# -------------------------------------------------------
# SECTION 1: Define Dataset Path
# -------------------------------------------------------
# Full path to where your .dat and .hea files are located
DATA_PATH = r'D:\ecg_arr\mit-bih-arrhythmia-database-1.0.0\mit-bih-arrhythmia-database-1.0.0'
# Record to load (record 100 = good starting point, has normal + arrhythmia beats)
RECORD_NAME = '100'
# -------------------------------------------------------
# SECTION 2: Load ECG Record
# -------------------------------------------------------
# Load the ECG record from your local folder
# rdrecord reads the .hea and .dat files together
record = wfdb.rdrecord(f'{DATA_PATH}\\{RECORD_NAME}')
# Extract channel 0 (MLII lead β€” the standard clinical lead in MIT-BIH)
ecg_signal = record.p_signal[:, 0]
# Get sampling frequency (MIT-BIH records are sampled at 360 Hz)
fs = record.fs
print(f"Record : {RECORD_NAME}")
print(f"Sampling Rate : {fs} Hz")
print(f"Total Samples : {len(ecg_signal)}")
print(f"Duration : {len(ecg_signal)/fs:.1f} seconds ({len(ecg_signal)/fs/60:.1f} minutes)")
print(f"Lead Name : {record.sig_name[0]}")
# -------------------------------------------------------
# SECTION 3: Bandpass Filter (0.5 Hz – 40 Hz)
# -------------------------------------------------------
# Why these limits?
# Below 0.5 Hz β†’ baseline wander (body/breathing movement) β†’ REMOVE
# 0.5 to 40 Hz β†’ real ECG waveforms (P, QRS, T waves) β†’ KEEP
# Above 40 Hz β†’ muscle noise + powerline hum (50/60 Hz) β†’ REMOVE
def bandpass_filter(signal, lowcut=0.5, highcut=40.0, fs=360, order=4):
"""
Butterworth bandpass filter to remove ECG noise.
Parameters:
signal : raw ECG signal (numpy array)
lowcut : lower frequency cutoff in Hz (removes baseline wander)
highcut : upper frequency cutoff in Hz (removes high freq noise)
fs : sampling frequency in Hz
order : filter sharpness (4 is standard for ECG)
Returns:
filtered_signal : cleaned ECG signal (numpy array)
"""
nyquist = 0.5 * fs # Nyquist = half of sampling rate
low = lowcut / nyquist # Normalize lower cutoff
high = highcut / nyquist # Normalize upper cutoff
b, a = butter(order, [low, high], btype='band') # Design Butterworth filter
filtered_signal = filtfilt(b, a, signal) # Zero-phase filtering (no signal shift)
return filtered_signal
# Apply filter to the loaded ECG signal
ecg_filtered = bandpass_filter(ecg_signal, fs=fs)
print("\nFiltering complete!")
# -------------------------------------------------------
# SECTION 4: Plot Raw vs Filtered (First 5 Seconds)
# -------------------------------------------------------
duration_to_show = 5 # Show first 5 seconds
samples_to_show = duration_to_show * fs # 5 Γ— 360 = 1800 samples
time_axis = np.arange(samples_to_show) / fs # X-axis in seconds
plt.figure(figsize=(14, 7))
# --- Top plot: Raw Signal ---
plt.subplot(2, 1, 1)
plt.plot(time_axis, ecg_signal[:samples_to_show],
color='steelblue', linewidth=0.8, label='Raw ECG')
plt.title(f'RAW ECG Signal β€” Record {RECORD_NAME} (Before Filtering)', fontsize=13)
plt.xlabel('Time (seconds)')
plt.ylabel('Amplitude (mV)')
plt.legend(loc='upper right')
plt.grid(True, alpha=0.3)
# --- Bottom plot: Filtered Signal ---
plt.subplot(2, 1, 2)
plt.plot(time_axis, ecg_filtered[:samples_to_show],
color='crimson', linewidth=0.8, label='Filtered ECG')
plt.title(f'FILTERED ECG Signal β€” After Bandpass Filter (0.5–40 Hz)', fontsize=13)
plt.xlabel('Time (seconds)')
plt.ylabel('Amplitude (mV)')
plt.legend(loc='upper right')
plt.grid(True, alpha=0.3)
plt.tight_layout()
# Save plot to same folder as the script
output_path = r'D:\ecg_arr\step1_output.png'
plt.savefig(output_path, dpi=150)
plt.show()
print(f"\nPlot saved to: {output_path}")
print("\nStep 1 Complete! Ready for Step 2: Segmentation")