{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Noise Reduction\n",
    "\n",
    "This Notebook is used to reduce the noise in the ECG signals.\n",
    "First a Butterworth filter is applied to the signals to remove the high frequency noise.\n",
    "Than a loess filter is applied to the signals to remove the low frequency noise.\n",
    "Last Non local means filter is applied to the signals to remove the remaining noise."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from matplotlib import pyplot as plt\n",
    "import wfdb.processing\n",
    "import sys\n",
    "import json\n",
    "\n",
    "sys.path.append('../scripts')\n",
    "import data_helper"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Load Data"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "For a better understanding of the structure and dimensions of the individual data sets, there are printed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Reading GSVT\n",
      "Reading AFIB\n",
      "Reading SR\n",
      "Reading SB\n",
      "Number of patients per category:\n",
      "GSVT: 1027\n",
      "AFIB: 9787\n",
      "SR: 10426\n",
      "SB: 15826\n"
     ]
    }
   ],
   "source": [
    "data = data_helper.load_data(only_demographic=False)\n",
    "\n",
    "print(\"Number of patients per category:\")\n",
    "for cat_name in data.keys():\n",
    "    print(f\"{cat_name}: {len(data[cat_name])}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 83276 characters]",
      "text/plain": [
       "<Figure size 1500x400 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "example_data = data['SB'][0]\n",
    "#Plot specific Channel of Record\n",
    "fig = wfdb.plot_items(example_data.p_signal[:,0],title=\"Example for Channel 0\",figsize=(15,4),return_fig=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "filter_params = {\n",
    "    'names': ['butterlowpass', 'lowess', 'non_local_means'],\n",
    "    # params for butterworth filter\n",
    "    'order':1,\n",
    "    'fs':500.0,\n",
    "    'cutoff':25,\n",
    "    # params for lowess filter\n",
    "    'filter_strength':50,\n",
    "    'template_window_size':7,\n",
    "    'search_window_size':21,\n",
    "    # params for nlm filter\n",
    "    'frac':0.003,\n",
    "    'it':1\n",
    "}\n",
    "\n",
    "#save filter params to json file\n",
    "with open('../filter_params.json', 'w') as f:\n",
    "    json.dump(filter_params, f)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 111016 characters]",
      "text/plain": [
       "<Figure size 1000x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "butter_filtered_sig = data_helper.butterlowpass_filter(example_data, filter_params['cutoff'], filter_params['fs'], filter_params['order'])\n",
    "# Plot the original and denoised signal\n",
    "plt.figure(figsize=(10, 5))\n",
    "plt.plot(example_data.p_signal[:,0], label='Original signal')\n",
    "plt.plot(butter_filtered_sig.p_signal[:,0], label='Butterlow signal')\n",
    "plt.xlabel('Time')\n",
    "plt.ylabel('Amplitude')\n",
    "plt.title('Signal with and without Butterlow signal Denoising')\n",
    "plt.legend()\n",
    "plt.grid(True)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 111692 characters]",
      "text/plain": [
       "<Figure size 1000x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "lowess_filtered_sig = data_helper.lowess_filter(example_data, filter_params['frac'], filter_params['it'])\n",
    "# Plot the original and denoised signal\n",
    "plt.figure(figsize=(10, 5))\n",
    "plt.plot(example_data.p_signal[:,0], label='Original signal')\n",
    "plt.plot(lowess_filtered_sig.p_signal[:,0], label='Lowess signal')\n",
    "plt.xlabel('Time')\n",
    "plt.ylabel('Amplitude')\n",
    "plt.title('Signal with and without Lowess Denoising')\n",
    "plt.legend()\n",
    "plt.grid(True)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 108984 characters]",
      "text/plain": [
       "<Figure size 1000x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "nlm_filtered_sig = data_helper.non_local_means_filter(example_data, filter_params['filter_strength'], filter_params['template_window_size'], filter_params['search_window_size'])\n",
    "# Plot the original and denoised signal\n",
    "plt.figure(figsize=(10, 5))\n",
    "plt.plot(example_data.p_signal[:,0], label='Original signal')\n",
    "plt.plot(nlm_filtered_sig.p_signal[:,0], label='NLM signal')\n",
    "plt.xlabel('Time')\n",
    "plt.ylabel('Amplitude')\n",
    "plt.title('Signal with and without Non-Local Means Denoising')\n",
    "plt.legend()\n",
    "plt.grid(True)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 107296 characters]",
      "text/plain": [
       "<Figure size 1000x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "all_filtered_signals = data_helper.filter_data(example_data, filter_params)\n",
    "# Plot the original and denoised signal\n",
    "plt.figure(figsize=(10, 5))\n",
    "plt.plot(example_data.p_signal[:,0], label='Original signal')\n",
    "plt.plot(all_filtered_signals.p_signal[:,0], label='filtered signal')\n",
    "plt.xlabel('Time')\n",
    "plt.ylabel('Amplitude')\n",
    "plt.title('Signal with and without All Denoising')\n",
    "plt.legend()\n",
    "plt.grid(True)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 134152 characters]",
      "text/plain": [
       "<Figure size 640x480 with 12 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "wfdb.plot_wfdb(all_filtered_signals,title=\"Filtered Example for all Channels\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 115068 characters]",
      "text/plain": [
       "<Figure size 640x480 with 12 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "wfdb.plot_wfdb(example_data,title=\"Raw Example for all Channels\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
