{
 "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",
    "import csv\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, delay_seconds=0):\n",
    "    # Signal in Frequenzbereich 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",
    "    # Phasenshift für die Verzögerung berechnen\n",
    "    # Signalfrequenzen modifizieren. \n",
    "    # Signal wieder zurück in Zeitbereich\n",
    "    gain_interp = np.interp(freq_bins, frequencies, gain_linear)\n",
    "    phase_shift = np.exp(-1j * 2 * np.pi * freq_bins * delay_seconds)\n",
    "    modified_freq_signal = freq_signal * gain_interp * phase_shift \n",
    "    modified_signal = np.fft.irfft(modified_freq_signal, n=N)\n",
    "    return modified_signal\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": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\phangl\\AppData\\Local\\Temp\\ipykernel_8624\\4018988943.py:52: DeprecationWarning: `trapz` is deprecated. Use `trapezoid` instead, or one of the numerical integration functions in `scipy.integrate`.\n",
      "  snr_before = 10 * np.log10(np.trapz(desired_signal**2, t) / np.trapz(noise_signal**2, t))\n",
      "C:\\Users\\phangl\\AppData\\Local\\Temp\\ipykernel_8624\\4018988943.py:53: DeprecationWarning: `trapz` is deprecated. Use `trapezoid` instead, or one of the numerical integration functions in `scipy.integrate`.\n",
      "  snr_after = 10 * np.log10(np.trapz(desired_signal**2, t) / np.trapz(error_signal**2, t2))\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 469056 characters]",
      "text/plain": [
       "<Figure size 1500x1200 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 154216 characters]",
      "text/plain": [
       "<Figure size 1500x600 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#Plots für Simple Usecases\n",
    "\n",
    "SIMULATION = False\n",
    "AUDIO = False\n",
    "PLOT = False\n",
    "\n",
    "plot = 'noise'\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",
    "error_signal = (output - desired_signal)[:-coefficients]\n",
    "t2 = np.linspace(0, len(error_signal), len(error_signal))\n",
    "\n",
    "# SNR davor/danach in dB berechnen, SNR Ratio berechnen, \n",
    "snr_before = 10 * np.log10(np.trapz(desired_signal**2, t) / np.trapz(noise_signal**2, t))\n",
    "snr_after = 10 * np.log10(np.trapz(desired_signal**2, t) / np.trapz(error_signal**2, t2))\n",
    "delta_snr = round(snr_after - snr_before, 2)\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(-1.0, 1.0)\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'SNR Gain = {delta_snr} dB'], 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(-1.0, 1.0)\n",
    "ax4.plot(t2, error_signal, 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'Error Amplitude'], 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_{plot}', dpi=600)\n",
    "    figure2.savefig(f'plots/fig_plot_2_{plot}', dpi=600)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\phangl\\AppData\\Local\\Temp\\ipykernel_8624\\2064450574.py:45: DeprecationWarning: `trapz` is deprecated. Use `trapezoid` instead, or one of the numerical integration functions in `scipy.integrate`.\n",
      "  snr_before = 10 * np.log10(np.trapz(desired_signal**2, t) / np.trapz(noise_signal**2, t))\n",
      "C:\\Users\\phangl\\AppData\\Local\\Temp\\ipykernel_8624\\2064450574.py:46: DeprecationWarning: `trapz` is deprecated. Use `trapezoid` instead, or one of the numerical integration functions in `scipy.integrate`.\n",
      "  snr_after = 10 * np.log10(np.trapz(desired_signal**2, t) / np.trapz(error_signal**2, t2))\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 199752 characters]",
      "text/plain": [
       "<Figure size 1500x1200 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 89052 characters]",
      "text/plain": [
       "<Figure size 1500x600 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#Plots für intermediate Usecases\n",
    "\n",
    "SIMULATION = False\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_1 = load_wav(f'./audio_data/Nutzsignal/male.wav')\n",
    "fs, data_2 = load_wav(f'./audio_data/Störsignal/breathing.wav')\n",
    "\n",
    "# Signale laden und zuordnen\n",
    "desired_signal = data_1\n",
    "noise_signal = data_2\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",
    "error_signal = (output - desired_signal)[:-coefficients]\n",
    "t2 = np.linspace(0, len(error_signal), len(error_signal))\n",
    "\n",
    "# SNR davor/danach in dB berechnen, SNR Ratio berechnen, \n",
    "snr_before = 10 * np.log10(np.trapz(desired_signal**2, t) / np.trapz(noise_signal**2, t))\n",
    "snr_after = 10 * np.log10(np.trapz(desired_signal**2, t) / np.trapz(error_signal**2, t2))\n",
    "delta_snr = round(snr_after - snr_before, 2)\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(-1.0, 1.0)\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'SNR Gain = {delta_snr} dB'], 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(-1.0, 1.0)\n",
    "ax4.plot(t2, error_signal, 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'Error Amplitude'], 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": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "C:\\Users\\phangl\\AppData\\Local\\Temp\\ipykernel_24644\\658311717.py:63: DeprecationWarning: `trapz` is deprecated. Use `trapezoid` instead, or one of the numerical integration functions in `scipy.integrate`.\n",
      "  snr_before = 10 * np.log10(np.trapz(desired_signal_r11**2, t) / np.trapz(noise_signal_vpu**2, t))\n",
      "C:\\Users\\phangl\\AppData\\Local\\Temp\\ipykernel_24644\\658311717.py:64: DeprecationWarning: `trapz` is deprecated. Use `trapezoid` instead, or one of the numerical integration functions in `scipy.integrate`.\n",
      "  snr_after = 10 * np.log10(np.trapz(desired_signal_r11**2, t) / np.trapz(error_signal**2, t2))\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 202800 characters]",
      "text/plain": [
       "<Figure size 1500x1200 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 104984 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, 154004 characters]",
      "text/plain": [
       "<Figure size 1500x900 with 3 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "#Plots für komplexen Usecases\n",
    "\n",
    "from pandas import Series\n",
    "\n",
    "\n",
    "SIMULATION = True\n",
    "AUDIO = False\n",
    "PLOT = True\n",
    "SERIES = 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",
    "# Parameter setzen\n",
    "coefficients = 16\n",
    "step_size = 0.01\n",
    "delay_r11 = 0.000\n",
    "delay_vpu = 0.002\n",
    "indices = [0, coefficients // 2, coefficients - 1]\n",
    "\n",
    "# .wav File laden, Tonspuren den Signalen zuordnen, Corrputed Target Signal erstellen, Reduced Noise Signal erstellen\n",
    "fs, data_1 = load_wav(f'./audio_data/Nutzsignal/male.wav')\n",
    "fs, data_2 = load_wav(f'./audio_data/Störsignal/breathing.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_2\n",
    "desired_signal_r11 = apply_transfer_function_freq(desired_signal, fs, frequency_r11, gain_r11, delay_r11)\n",
    "noise_signal_r11 = apply_transfer_function_freq(noise_signal, fs, frequency_r11, gain_r11, delay_r11)\n",
    "noise_signal_vpu = apply_transfer_function_freq(noise_signal, fs, frequency_vpu, gain_vpu, delay_vpu)\n",
    "corrupted_signal = desired_signal_r11 + noise_signal_r11\n",
    "\n",
    "# Zeitachse anlegen, ANR Algorithmus ausführen\n",
    "t = np.linspace(0, len(corrupted_signal), len(corrupted_signal))\n",
    "\n",
    "if Series == True:\n",
    "    for i in range(len(coefficients)):\n",
    "        i = 16\n",
    "        output, coefficient_matrix = anr_function(corrupted_signal, noise_signal_vpu, i, step_size, adaption_step=1)\n",
    "        i = i+2\n",
    "\n",
    "        # Koeffizientenmatrix und Vergleich um Koeffizientenanzahl kürzen, um Tail zu vermeiden, 2.te Zeitachse anlegen\n",
    "        coefficient_matrix = coefficient_matrix[:-coefficients]\n",
    "        error_signal = (output - desired_signal_r11)[:-coefficients]\n",
    "        t2 = np.linspace(0, len(error_signal), len(error_signal))\n",
    "\n",
    "        # SNR davor/danach in dB berechnen, SNR Ratio berechnen, \n",
    "        snr_before = 10 * np.log10(np.trapz(desired_signal_r11**2, t) / np.trapz(noise_signal_vpu**2, t))\n",
    "        snr_after = 10 * np.log10(np.trapz(desired_signal_r11**2, t) / np.trapz(error_signal**2, t2))\n",
    "        delta_snr = round(snr_after - snr_before, 2)\n",
    "\n",
    "        with open('csv_file', 'a') as f:\n",
    "            writer = csv.writer(f)\n",
    "            writer.writerow([i, delta_snr])\n",
    "else:\n",
    "        output, coefficient_matrix = anr_function(corrupted_signal, noise_signal_vpu, coefficients, step_size, adaption_step=1)\n",
    "\n",
    "\n",
    "\n",
    "# Koeffizientenmatrix und Vergleich um Koeffizientenanzahl kürzen, um Tail zu vermeiden, 2.te Zeitachse anlegen\n",
    "coefficient_matrix = coefficient_matrix[:-coefficients]\n",
    "error_signal = (output - desired_signal_r11)[:-coefficients]\n",
    "t2 = np.linspace(0, len(error_signal), len(error_signal))\n",
    "\n",
    "# SNR davor/danach in dB berechnen, SNR Ratio berechnen, \n",
    "snr_before = 10 * np.log10(np.trapz(desired_signal_r11**2, t) / np.trapz(noise_signal_vpu**2, t))\n",
    "snr_after = 10 * np.log10(np.trapz(desired_signal_r11**2, t) / np.trapz(error_signal**2, t2))\n",
    "delta_snr = round(snr_after - snr_before, 2)\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",
    "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(-1, 1)\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'SNR Gain = {delta_snr} dB'], 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(-1, 1)\n",
    "ax4.plot(t2, error_signal, 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'Error Amplitude'], 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
}
