{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Funktionen und Abhängigkeiten\n",
    "\n",
    "import time\n",
    "import os\n",
    "from ipywidgets import interact\n",
    "from scipy import signal\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "import soundfile as sf\n",
    "import pandas as pd\n",
    "\n",
    "# Soundfile laden\n",
    "def load_wav(filename):\n",
    "    y, fs = sf.read(filename, dtype='float32')\n",
    "    return fs, y.T\n",
    "\n",
    "# Sensitivätskurve Mikrofon laden (normiert auf 1000 Hz)\n",
    "def load_transfer_function(filename):\n",
    "    df = pd.read_csv(filename, skiprows=3, header=None, dtype=float, sep=\";\")\n",
    "    frequencies = df.iloc[:, 0]\n",
    "    gain = df.iloc[:, 1]\n",
    "    return frequencies, gain\n",
    "\n",
    "# Transferfunktion für frequenzabhängige Veränderung von Signal anlegen\n",
    "def apply_transfer_function_freq(signal, fs, frequencies, gain_dB):\n",
    "    # Signal fouriertransformieren, Frequenzbins berechnen, linearen Gain berechnen\n",
    "    N = len(signal)\n",
    "    freq_signal = np.fft.rfft(signal)\n",
    "    freq_bins = np.fft.rfftfreq(N, d=1/fs)\n",
    "    gain_linear = 10 ** (gain_dB / 20.0)    \n",
    "    # Gain Werte interpolieren auf die tatsächlichen Frequenzbins\n",
    "    # Signalfrequenzen modifizieren\n",
    "    # Signal wieder zurück in Zeitbereich\n",
    "    gain_interp = np.interp(freq_bins, frequencies, gain_linear)\n",
    "    modified_freq_signal = freq_signal * gain_interp \n",
    "    modified_signal = np.fft.irfft(modified_freq_signal, n=N)\n",
    "    return modified_signal\n",
    "\n",
    "# Transferfunktion für zeitliche Veränderung von Signal anlegen\n",
    "def apply_transfer_function_time(input, n):\n",
    "    continuous_decay = np.linspace(1.0, 0.05, n)\n",
    "    output = np.zeros(n) \n",
    "    output = input * continuous_decay\n",
    "    # for i in range(0, len(output)):\n",
    "    #     if i < len(output)/2:\n",
    "    #         output[i] = input[i] * continuous_decay[i]\n",
    "    #     else:\n",
    "    #         output[i] = 0\n",
    "    return output\n",
    "\n",
    "# ANR Algorithmmus\n",
    "def anr_function(input, ref_noise, coefficients, mu, adaption_step = 1):\n",
    "    coefficient_matrix = np.zeros((len(input), coefficients), dtype=np.float32)\n",
    "    output=np.zeros(input.shape[0], dtype=np.float32)\n",
    "    filter = np.zeros(coefficients, dtype=np.float32)\n",
    "    \n",
    "    for j in range(0, len(input) - len(filter)): \n",
    "        accumulator=0\n",
    "        for i in range(coefficients):\n",
    "            noise=ref_noise[j+i]\n",
    "            accumulator+=filter[i] * noise\n",
    "        output[j] = input[j] - accumulator\n",
    "        corrector = mu * output[j]\n",
    "        if (j % adaption_step) == 0:\n",
    "            for k in range(coefficients):\n",
    "                filter[k] += corrector*ref_noise[j+k]  \n",
    "        coefficient_matrix[j, :] = filter[:]\n",
    "    return output, coefficient_matrix\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\phangl\\AppData\\Local\\Temp\\ipykernel_6640\\4133530845.py:51: DeprecationWarning: `trapz` is deprecated. Use `trapezoid` instead, or one of the numerical integration functions in `scipy.integrate`.\n",
      "  nise = round(np.trapz(comparison**2, t2)/np.trapz(corrupted_signal**2, t),3)\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 484672 characters]",
      "text/plain": [
       "<Figure size 1500x1200 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 155384 characters]",
      "text/plain": [
       "<Figure size 1500x600 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#Plots für Simple Usecases\n",
    "\n",
    "SIMULATION = True\n",
    "AUDIO = False\n",
    "PLOT = False\n",
    "\n",
    "plot = 'sine_1'\n",
    "\n",
    "# Chirp Generator\n",
    "n=2000 #Sampleanzahl\n",
    "fs=20000 #Samplingrate\n",
    "f0=100 #Startfrequenz\n",
    "f1=1000 #Stopfrequenz\n",
    "t1=n/fs #Chirpdauer (Samples/Samplingrate)\n",
    "if plot == 'sine_1':\n",
    "    f_disturber=2000 #Störfrequenz\n",
    "else:\n",
    "    f_disturber=500 #Störfrequenz\n",
    "\n",
    "signal_amplitude=0.5\n",
    "disturber_amplitude=0.25\n",
    "\n",
    "# Parameter setzen\n",
    "coefficients = 16\n",
    "step_size = 0.01\n",
    "indices = [0, coefficients // 2, coefficients - 1]\n",
    "\n",
    "t = np.linspace(0, t1, n)\n",
    "\n",
    "# Zielsignal anlegen\n",
    "desired_signal = signal.chirp(t, f0=f0, f1=f1, t1=t1, method='linear')*signal_amplitude\n",
    "\n",
    "# Störsignal anlegen\n",
    "if plot == 'sine_1' or plot == 'sine_2':\n",
    "    noise_signal = np.sin(2*np.pi*f_disturber*t) * disturber_amplitude\n",
    "else:\n",
    "    noise_signal = np.random.normal(0, 1, n) * disturber_amplitude\n",
    "\n",
    "# Korruptes Zielsignal anlegen\n",
    "corrupted_signal = desired_signal + noise_signal\n",
    "\n",
    "# Zeitachse anlegen, ANR Algorithmus ausführen\n",
    "t = np.linspace(0, len(corrupted_signal), len(corrupted_signal))\n",
    "output, coefficient_matrix = anr_function(corrupted_signal, noise_signal, coefficients, step_size, adaption_step=1)\n",
    "\n",
    "# Koeffizientenmatrix und Vergleich um Koeffizientenanzahl kürzen, um Tail zu vermeiden, 2.te Zeitachse anlegen\n",
    "coefficient_matrix = coefficient_matrix[:-coefficients]\n",
    "comparison = (output - desired_signal)[:-coefficients]\n",
    "#MSE = round(np.square(np.subtract(desired_signal,output)).mean(),3)\n",
    "t2 = np.linspace(0, len(comparison), len(comparison))\n",
    "nise = round(np.trapz(comparison**2, t2)/np.trapz(corrupted_signal**2, t),3)\n",
    "\n",
    "if SIMULATION == True:\n",
    "    # Soundfiles zu 16 Bit skalieren und als .txt speichern für DSP Simulation\n",
    "    desired_signal_simulation = desired_signal*(2**(15)-1)\n",
    "    noise_signal_simulation = noise_signal*(2**(15)-1)\n",
    "    corrupted_signal_simulation = corrupted_signal*(2**(15)-1)\n",
    "    np.savetxt('simulation_data/simple_desired_signal.txt', desired_signal_simulation, fmt='%d')\n",
    "    np.savetxt('simulation_data/simple_corrupted_signal.txt', corrupted_signal_simulation, fmt='%d', delimiter=\"\\n\")\n",
    "    np.savetxt('simulation_data/simple_noise_signal.txt', noise_signal_simulation, fmt='%d', delimiter=\"\\n\")\n",
    "\n",
    "# Schriftgrößen für LaTeX-Dokument\n",
    "plt.rcParams.update({\n",
    "    'font.size': 16,          # Standardtext\n",
    "    'axes.titlesize': 18,     # Titel\n",
    "    'axes.labelsize': 17,     # Achsenbeschriftungen\n",
    "    'xtick.labelsize': 15,    # Tick-Beschriftungen\n",
    "    'ytick.labelsize': 15,\n",
    "    'legend.fontsize': 15     # Legende\n",
    "})\n",
    "\n",
    "# Plots des Filterprozesses\n",
    "figure1, (ax0, ax1, ax2, ax3) = plt.subplots(4, 1, figsize=(15, 12), sharex=True, sharey=True)\n",
    "ax0.set_ylim(min(corrupted_signal), max(corrupted_signal))\n",
    "ax0.plot(t, desired_signal, c='deepskyblue')\n",
    "ax1.plot(t, corrupted_signal, c='royalblue')\n",
    "ax2.plot(t, noise_signal, c='chocolate')\n",
    "ax3.plot(t, output, c='green')\n",
    "\n",
    "ax0.set_title('Desired signal')\n",
    "ax1.set_title('Corrupted signal')\n",
    "ax2.set_title('Reference noise signal')\n",
    "ax3.set_title('Filter output')\n",
    "\n",
    "ax3.set_xlabel('time(ms)')\n",
    "ax0.set_ylabel('Amplitude')\n",
    "ax1.set_ylabel('Amplitude')\n",
    "ax2.set_ylabel('Amplitude')\n",
    "ax3.set_ylabel('Amplitude')\n",
    "\n",
    "ax0.legend(['Desired signal'], loc='upper right')\n",
    "ax1.legend(['Corrupted signal'], loc='upper right')\n",
    "ax2.legend(['Reference noise signal'], loc='upper right')\n",
    "ax3.legend([f'{coefficients} Coefficients, {step_size} Stepsize'], loc='upper right')\n",
    "\n",
    "# Plots der Filterperfomanz\n",
    "figure2, (ax4, ax5) = plt.subplots(2, 1, figsize=(15, 6), sharex=True)\n",
    "ax4.set_ylim(min(corrupted_signal), max(corrupted_signal))\n",
    "ax4.plot(t2, comparison, c='purple')\n",
    "for i in indices:\n",
    "    ax5.plot(t2, coefficient_matrix[:,i])\n",
    "ax4.set_title('Error Desired signal / Filter output')\n",
    "ax5.set_title('Coeffcient convergence')\n",
    "\n",
    "ax5.set_xlabel('time(ms)')\n",
    "ax4.set_ylabel('Error')\n",
    "ax5.set_ylabel('Coeffcient value')\n",
    "ax4.legend([f'Normalized Integrated Squared Error = {nise}'], loc='upper right')\n",
    "ax5.legend(['First coeffcient','Medium coefficient','Last coefficient'], loc='upper right')\n",
    "\n",
    "figure1.tight_layout()\n",
    "figure2.tight_layout()\n",
    "if PLOT == True:\n",
    "    figure1.savefig(f'fig_plot_1_{plot}', dpi=600)\n",
    "    figure2.savefig(f'fig_plot_2_{plot}', dpi=600)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\phangl\\AppData\\Local\\Temp\\ipykernel_6640\\1714216909.py:43: DeprecationWarning: `trapz` is deprecated. Use `trapezoid` instead, or one of the numerical integration functions in `scipy.integrate`.\n",
      "  nise = round(np.trapz(comparison**2, t2)/np.trapz(corrupted_signal**2, t),3)\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 223176 characters]",
      "text/plain": [
       "<Figure size 1500x1200 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 107400 characters]",
      "text/plain": [
       "<Figure size 1500x600 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#Plots für intermediate Usecases\n",
    "\n",
    "SIMULATION = True\n",
    "AUDIO = False\n",
    "PLOT = False\n",
    "\n",
    "# Chirp Generator\n",
    "n=2000 #Sampleanzahl\n",
    "fs=20000 #Samplingrate\n",
    "f0=100 #Startfrequenz\n",
    "f1=1000 #Stopfrequenz\n",
    "t1=n/fs #Chirpdauer (Samples/Samplingrate)\n",
    "f_disturber=2000 #Störfrequenz\n",
    "\n",
    "# .wav File laden, Tonspuren den Signalen zuordnen, Corrputed Target Signal erstellen\n",
    "fs, data = load_wav(f'./audio_data/breathing_peak_01g_external_Speaker_80dBSPL_PDM.wav')\n",
    "\n",
    "# Signale laden und zuordnen\n",
    "desired_signal = data[1]\n",
    "noise_signal = data[0]\n",
    "corrupted_signal = desired_signal + noise_signal\n",
    "\n",
    "# Parameter setzen\n",
    "coefficients = 16\n",
    "step_size = 0.01\n",
    "indices = [0, coefficients // 2, coefficients - 1]\n",
    "\n",
    "# Zeitachse anlegen, ANR Algorithmus ausführen\n",
    "t = np.linspace(0, len(corrupted_signal), len(corrupted_signal))\n",
    "output, coefficient_matrix = anr_function(corrupted_signal, noise_signal, coefficients, step_size, adaption_step=1)\n",
    "output = output * max(desired_signal) / max(output)\n",
    "\n",
    "if AUDIO == True:\n",
    "    # Audiodateien zum Vergleich abspeichern\n",
    "    sf.write('corrupted_signal.wav', corrupted_signal, fs)\n",
    "    sf.write('filter_output.wav', output, fs)\n",
    "\n",
    "# Koeffizientenmatrix und Vergleich um Koeffizientenanzahl kürzen, um Tail zu vermeiden, 2.te Zeitachse anlegen\n",
    "coefficient_matrix = coefficient_matrix[:-coefficients]\n",
    "comparison = (output - desired_signal)[:-coefficients]\n",
    "#MSE = round(np.square(np.subtract(desired_signal,output)).mean(),3)\n",
    "t2 = np.linspace(0, len(comparison), len(comparison))\n",
    "nise = round(np.trapz(comparison**2, t2)/np.trapz(corrupted_signal**2, t),3)\n",
    "\n",
    "if SIMULATION == True:\n",
    "    # Soundfiles zu 16 Bit skalieren und als .txt speichern für DSP Simulation\n",
    "    desired_signal_simulation = desired_signal*(2**(15)-1)\n",
    "    noise_signal_simulation = noise_signal*(2**(15)-1)\n",
    "    corrupted_signal_simulation = corrupted_signal*(2**(15)-1)\n",
    "    np.savetxt('simulation_data/intermediate_desired_signal.txt', desired_signal_simulation, fmt='%d')\n",
    "    np.savetxt('simulation_data/intermediate_corrupted_signal.txt', corrupted_signal_simulation, fmt='%d', delimiter=\"\\n\")\n",
    "    np.savetxt('simulation_data/intermediate_noise_signal.txt', noise_signal_simulation, fmt='%d', delimiter=\"\\n\")\n",
    "\n",
    "# Schriftgrößen für LaTeX-Dokument\n",
    "plt.rcParams.update({\n",
    "    'font.size': 16,          # Standardtext\n",
    "    'axes.titlesize': 18,     # Titel\n",
    "    'axes.labelsize': 17,     # Achsenbeschriftungen\n",
    "    'xtick.labelsize': 15,    # Tick-Beschriftungen\n",
    "    'ytick.labelsize': 15,\n",
    "    'legend.fontsize': 15     # Legende\n",
    "})\n",
    "\n",
    "# Plots des Filterprozesses\n",
    "figure1, (ax0, ax1, ax2, ax3) = plt.subplots(4, 1, figsize=(15, 12), sharex=True, sharey=True)\n",
    "ax0.set_ylim(-0.2, 0.2)\n",
    "ax0.plot(t, desired_signal, c='deepskyblue')\n",
    "ax1.plot(t, corrupted_signal, c='royalblue')\n",
    "ax2.plot(t, noise_signal, c='chocolate')\n",
    "ax3.plot(t, output, c='green')\n",
    "\n",
    "ax0.set_title('Desired signal')\n",
    "ax1.set_title('Corrupted signal')\n",
    "ax2.set_title('Reference noise signal')\n",
    "ax3.set_title('Filter output')\n",
    "\n",
    "ax3.set_xlabel('time(ms)')\n",
    "ax0.set_ylabel('Amplitude')\n",
    "ax1.set_ylabel('Amplitude')\n",
    "ax2.set_ylabel('Amplitude')\n",
    "ax3.set_ylabel('Amplitude')\n",
    "\n",
    "ax0.legend(['Desired signal'], loc='upper right')\n",
    "ax1.legend(['Corrupted signal'], loc='upper right')\n",
    "ax2.legend(['Reference noise signal'], loc='upper right')\n",
    "ax3.legend([f'{coefficients} Coefficients, {step_size} Stepsize'], loc='upper right')\n",
    "\n",
    "# Plots der Filterperfomanz\n",
    "figure2, (ax4, ax5) = plt.subplots(2, 1, figsize=(15, 6), sharex=True)\n",
    "ax4.set_ylim(-0.2, 0.2)\n",
    "ax4.plot(t2, comparison, c='purple')\n",
    "for i in indices:\n",
    "    ax5.plot(t2, coefficient_matrix[:,i])\n",
    "ax4.set_title('Error Desired signal / Filter output')\n",
    "ax5.set_title('Coeffcient convergence')\n",
    "\n",
    "ax5.set_xlabel('time(ms)')\n",
    "ax4.set_ylabel('Error')\n",
    "ax5.set_ylabel('Coeffcient value')\n",
    "ax4.legend([f'Normalized Integrated Squared Error = {nise}'], loc='upper right')\n",
    "ax5.legend(['First coeffcient','Medium coefficient','Last coefficient'], loc='upper right')\n",
    "\n",
    "figure1.tight_layout()\n",
    "figure2.tight_layout()\n",
    "if PLOT == True:\n",
    "    figure1.savefig(f'plots/fig_plot_1_wav', dpi=600)\n",
    "    figure2.savefig(f'plots/fig_plot_2_wav', dpi=600)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\phangl\\AppData\\Local\\Temp\\ipykernel_6640\\48121329.py:50: DeprecationWarning: `trapz` is deprecated. Use `trapezoid` instead, or one of the numerical integration functions in `scipy.integrate`.\n",
      "  nise = round(np.trapz(comparison**2, t2)/np.trapz(corrupted_signal**2, t),3)\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 230044 characters]",
      "text/plain": [
       "<Figure size 1500x1200 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 100480 characters]",
      "text/plain": [
       "<Figure size 1500x600 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 85664 characters]",
      "text/plain": [
       "<Figure size 1500x600 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 150668 characters]",
      "text/plain": [
       "<Figure size 1500x900 with 3 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#Plots für komplexen Usecases\n",
    "\n",
    "SIMULATION = True\n",
    "AUDIO = False\n",
    "PLOT = False\n",
    "\n",
    "# Chirp Generator\n",
    "n=2000 #Sampleanzahl\n",
    "fs=20000 #Samplingrate\n",
    "f0=100 #Startfrequenz\n",
    "f1=1000 #Stopfrequenz\n",
    "t1=n/fs #Chirpdauer (Samples/Samplingrate)\n",
    "f_disturber=2000 #Störfrequenz\n",
    "\n",
    "# .wav File laden, Tonspuren den Signalen zuordnen, Corrputed Target Signal erstellen, Reduced Noise Signal erstellen\n",
    "fs, data = load_wav(f'./audio_data/breathing_peak_01g_external_Speaker_80dBSPL_PDM.wav')\n",
    "\n",
    "# Sensitivätskurve Mikrofon laden (normiert auf 1000 Hz)\n",
    "frequency_r11, gain_r11 = load_transfer_function('./transfer_functions/R11_normalized.csv')\n",
    "frequency_vpu, gain_vpu = load_transfer_function('./transfer_functions/VPU17BA01_normlized.csv')\n",
    "\n",
    "# Signale laden und zuordnen\n",
    "desired_signal = data[1]\n",
    "noise_signal = data[0]\n",
    "desired_signal_r11 = apply_transfer_function_freq(desired_signal, fs, frequency_r11, gain_r11)\n",
    "noise_signal_r11 = apply_transfer_function_freq(noise_signal, fs, frequency_r11, gain_r11)\n",
    "noise_signal_vpu = apply_transfer_function_freq(noise_signal, fs, frequency_vpu, gain_vpu)\n",
    "#noise_signal_time = apply_transfer_function_time(noise_signal, len(noise_signal))\n",
    "corrupted_signal = desired_signal_r11 + noise_signal_r11\n",
    "\n",
    "# Parameter setzen\n",
    "coefficients = 16\n",
    "step_size = 0.01\n",
    "indices = [0, coefficients // 2, coefficients - 1]\n",
    "\n",
    "# Zeitachse anlegen, ANR Algorithmus ausführen\n",
    "t = np.linspace(0, len(corrupted_signal), len(corrupted_signal))\n",
    "output, coefficient_matrix = anr_function(corrupted_signal, noise_signal_vpu, coefficients, step_size, adaption_step=1)\n",
    "\n",
    "if AUDIO == True:\n",
    "    # Audiodateien zum Vergleich abspeichern\n",
    "    sf.write('corrupted_signal.wav', corrupted_signal, fs)\n",
    "    sf.write('filter_output.wav', output, fs)\n",
    "\n",
    "# Koeffizientenmatrix und Vergleich um Koeffizientenanzahl kürzen, um Tail zu vermeiden, 2.te Zeitachse anlegen\n",
    "coefficient_matrix = coefficient_matrix[:-coefficients]\n",
    "comparison = (output - desired_signal)[:-coefficients]\n",
    "#MSE = round(np.square(np.subtract(desired_signal,output)).mean(),3)\n",
    "t2 = np.linspace(0, len(comparison), len(comparison))\n",
    "nise = round(np.trapz(comparison**2, t2)/np.trapz(corrupted_signal**2, t),3)\n",
    "\n",
    "if SIMULATION == True:\n",
    "    # Soundfiles zu 16 Bit skalieren und als .txt speichern für DSP Simulation\n",
    "    desired_signal_simulation = desired_signal*(2**(15)-1)\n",
    "    noise_signal_simulation = noise_signal*(2**(15)-1)\n",
    "    corrupted_signal_simulation = corrupted_signal*(2**(15)-1)\n",
    "    np.savetxt('simulation_data/complex_desired_signal.txt', desired_signal_simulation, fmt='%d')\n",
    "    np.savetxt('simulation_data/complex_corrupted_signal.txt', corrupted_signal_simulation, fmt='%d', delimiter=\"\\n\")\n",
    "    np.savetxt('simulation_data/complex_noise_signal.txt', noise_signal_simulation, fmt='%d', delimiter=\"\\n\")\n",
    "\n",
    "# Schriftgrößen für LaTeX-Dokument\n",
    "plt.rcParams.update({\n",
    "    'font.size': 16,          # Standardtext\n",
    "    'axes.titlesize': 18,     # Titel\n",
    "    'axes.labelsize': 17,     # Achsenbeschriftungen\n",
    "    'xtick.labelsize': 15,    # Tick-Beschriftungen\n",
    "    'ytick.labelsize': 15,\n",
    "    'legend.fontsize': 15     # Legende\n",
    "})\n",
    "\n",
    "# Plots des Filterprozesses\n",
    "figure1, (ax0, ax1, ax2, ax3) = plt.subplots(4, 1, figsize=(15, 12), sharex=True, sharey=True)\n",
    "ax0.set_ylim(-0.2, 0.2)\n",
    "ax0.plot(t, desired_signal, c='deepskyblue')\n",
    "ax1.plot(t, corrupted_signal, c='royalblue')\n",
    "ax2.plot(t, noise_signal_vpu, c='chocolate')\n",
    "ax3.plot(t, output, c='green')\n",
    "\n",
    "ax0.set_title('Desired signal')\n",
    "ax1.set_title('Corrupted signal')\n",
    "ax2.set_title('Reference noise signal')\n",
    "ax3.set_title('Filter output')\n",
    "\n",
    "ax3.set_xlabel('time(ms)')\n",
    "ax0.set_ylabel('Amplitude')\n",
    "ax1.set_ylabel('Amplitude')\n",
    "ax2.set_ylabel('Amplitude')\n",
    "ax3.set_ylabel('Amplitude')\n",
    "\n",
    "ax0.legend(['Desired signal'], loc='upper right')\n",
    "ax1.legend(['Corrupted signal'], loc='upper right')\n",
    "ax2.legend(['Reference noise signal'], loc='upper right')\n",
    "ax3.legend([f'{coefficients} Coefficients, {step_size} Stepsize'], loc='upper right')\n",
    "\n",
    "# Plots der Filterperfomanz\n",
    "figure2, (ax4, ax5) = plt.subplots(2, 1, figsize=(15, 6), sharex=True)\n",
    "ax4.set_ylim(-0.2, 0.2)\n",
    "ax4.plot(t2, comparison, c='purple')\n",
    "for i in indices:\n",
    "    ax5.plot(t2, coefficient_matrix[:,i])\n",
    "ax4.set_title('Error Desired signal / Filter output')\n",
    "ax5.set_title('Coeffcient convergence')\n",
    "\n",
    "ax5.set_xlabel('time(ms)')\n",
    "ax4.set_ylabel('Error')\n",
    "ax5.set_ylabel('Coeffcient value')\n",
    "ax4.legend([f'Normalized Integrated Squared Error = {nise}'], loc='upper right')\n",
    "ax5.legend(['First coeffcient','Medium coefficient','Last coefficient'], loc='upper right')\n",
    "\n",
    "# Plot Sensitivitätskurve\n",
    "figure3, (ax6, ax7) = plt.subplots(2, 1, figsize=(15, 6), sharex=True)\n",
    "ax6.set_ylim(min(gain_r11), max(gain_r11))\n",
    "ax7.set_ylim(min(gain_vpu), max(gain_vpu))\n",
    "ax6.plot(frequency_r11, gain_r11, c='indianred')\n",
    "ax7.plot(frequency_vpu, gain_vpu, c='orangered')\n",
    "\n",
    "ax6.set_title('Sensitivity Curve (Primary sensor)')\n",
    "ax7.set_title('Sensitivity Curve (Secondary sensor)')\n",
    "\n",
    "ax6.set_xlabel('Frequency (Hz)')\n",
    "ax6.set_ylabel('Gain (dB)')\n",
    "ax7.set_ylabel('Gain (dB)')\n",
    "\n",
    "# Plot für Störsignalvergleich\n",
    "figure4, (ax8, ax9, ax10) = plt.subplots(3, 1, figsize=(15, 9), sharex=True, sharey=True)\n",
    "ax8.set_ylim(min(noise_signal), max(noise_signal))\n",
    "ax8.plot(t, noise_signal, c='orange')\n",
    "ax9.plot(t, noise_signal_r11, c='darkorange')\n",
    "ax10.plot(t, noise_signal_vpu, c='peru')\n",
    "\n",
    "ax8.set_title('Noise signal')\n",
    "ax9.set_title('Corruption noise signal (Primary sensor)')\n",
    "ax10.set_title('Reference noise signal (Secondary sensor)')\n",
    "\n",
    "ax8.set_xlabel('time(ms)')\n",
    "ax8.set_ylabel('Amplitude')\n",
    "ax9.set_ylabel('Amplitude')\n",
    "ax10.set_ylabel('Amplitude')\n",
    "\n",
    "figure1.tight_layout()\n",
    "figure2.tight_layout()\n",
    "figure3.tight_layout()\n",
    "figure4.tight_layout()\n",
    "if PLOT == True:\n",
    "    figure1.savefig(f'plots/fig_plot_1_wav_complex', dpi=600)\n",
    "    figure2.savefig(f'plots/fig_plot_2_wav_complex', dpi=600)\n",
    "    figure3.savefig(f'plots/fig_plot_3_wav_complex', dpi=600)\n",
    "    figure4.savefig(f'plots/fig_plot_4_wav_complex', dpi=600)\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "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.9.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
