File size: 4,440 Bytes
1cb40e2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# 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")