{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "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",
    "from scipy.signal import savgol_filter\n",
    "from scipy.stats import pearsonr\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):\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",
    "    modified_freq_signal = freq_signal * gain_interp\n",
    "    modified_signal = np.fft.irfft(modified_freq_signal, n=N)\n",
    "    return modified_signal\n",
    "\n",
    "# High-Level ANR Algorithmmus - nicht deterministisch, daher nicht gleiche Ergebnisse wie in C\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",
    "    adaption_step = 10\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) != 4:\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",
    "# Low-Level ANR Algorithmmus (wie in C)\n",
    "def anr_function_c(input, ref_noise, coefficients, mu, adaption_step = 1):\n",
    "    counter = 0\n",
    "    sample_count = len(input)\n",
    "    filter_line = np.zeros(coefficients)\n",
    "    sample_line = np.zeros(coefficients)\n",
    "    output = np.zeros(sample_count)\n",
    "    coeffient_matrix = np.zeros((sample_count, coefficients))\n",
    "    adaption_step = 1\n",
    "    \n",
    "    for n in range(sample_count):\n",
    "        # Reference Noise Signal in Sample Line\n",
    "        sample_line = np.roll(sample_line, 1)\n",
    "        sample_line[0] = ref_noise[n]\n",
    "        # apply_fir_filter: Akkumulator berechnen\n",
    "        accumulator = np.dot(filter_line, sample_line)\n",
    "        # update_output: Output/Error berechnen\n",
    "        error = input[n] - accumulator\n",
    "        output[n] = error\n",
    "        # update_filter_coeffcients: Filterkoeffizienten adaptieren\n",
    "        #if (n % adaption_step) == 0:     # bei Rate x/adatpion_step:  if (n % adaption_step) < x:\n",
    "        if (abs(error)*ref_noise[n]) > 0.000001:  # nur adaptieren wenn Fehler über Schwellwert\n",
    "            counter += 1\n",
    "            filter_line += mu * error * sample_line\n",
    "        # Filterkoeffizienten expoertieren\n",
    "        coeffient_matrix[n, :] = filter_line\n",
    "    print(f\"Anpassungen: {counter}\")\n",
    "    return output, coeffient_matrix\n",
    "    \n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Plots für Simple Usecases\n",
    "\n",
    "SIMULATION = False\n",
    "AUDIO = False\n",
    "PLOT = False\n",
    "COMPLEX = 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",
    "noise_delay = 0.000\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",
    "# 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",
    "if COMPLEX == True:\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",
    "else:\n",
    "    desired_signal_r11 = desired_signal\n",
    "    noise_signal_r11 = noise_signal\n",
    "    noise_signal_vpu = noise_signal\n",
    "\n",
    "# Noise Delay bedeutet, dass das Corruption Noise Signal im Corrupted Signal verzögert ist (zum Reference Noise Signal)\n",
    "if noise_delay != 0:\n",
    "    # Delay von ms in Samples umrechnen, 0-Array erzeugen\n",
    "    delay_samples = int(noise_delay * fs)\n",
    "    noise_signal_r11_delayed = np.zeros_like(noise_signal_r11)\n",
    "    # Schneided die Delay Samples vom ursprünglichen Array ab und schreibt sie nach entsprechend vielen Nullen ins neue Array\n",
    "    noise_signal_r11_delayed[delay_samples:] = noise_signal_r11[:-delay_samples]\n",
    "    # Corrupted Signal mit verzögertem Noise\n",
    "    corrupted_signal = desired_signal_r11 + noise_signal_r11_delayed\n",
    "else:\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))/1000\n",
    "output, coefficient_matrix = anr_function_c(corrupted_signal, noise_signal_vpu, 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_r11)[:-coefficients]\n",
    "t2 = np.linspace(0, len(error_signal), len(error_signal))/20000\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_r11**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 SIMULATION == True:\n",
    "    # Soundfiles zu 16 Bit skalieren und als .txt speichern für DSP Simulation\n",
    "    dsp_desired_signal_r11 = desired_signal_r11*(2**(15)-1)\n",
    "    dsp_noise_signal_r11 = noise_signal_r11*(2**(15)-1)\n",
    "    dsp_noise_signal_vpu = noise_signal_vpu*(2**(15)-1)\n",
    "    dsp_corrupted_signal = corrupted_signal*(2**(15)-1)\n",
    "    python_output = output*(2**(15)-1)\n",
    "    np.savetxt('simulation_data/simple_dsp_desired_signal_r11.txt', dsp_desired_signal_r11, fmt='%d')\n",
    "    np.savetxt('simulation_data/simple_dsp_noise_signal_r11.txt', dsp_noise_signal_r11, fmt='%d')\n",
    "    np.savetxt('simulation_data/simple_dsp_noise_signal_vpu.txt', dsp_noise_signal_vpu, fmt='%d', delimiter=\"\\n\")\n",
    "    np.savetxt('simulation_data/simple_dsp_corrupted_signal.txt', dsp_corrupted_signal, fmt='%d', delimiter=\"\\n\")\n",
    "    np.savetxt('filter_output/simple_python_output.txt', python_output, fmt='%d', delimiter=\"\\n\")\n",
    "    np.savetxt('filter_output/simple_python_filter_coefficients.txt', coefficient_matrix, fmt='%.4f', delimiter=\",\")\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', label='Desired signal')\n",
    "ax1.plot(t, corrupted_signal, c='royalblue', label='Corrupted signal')\n",
    "ax2.plot(t, noise_signal, c='chocolate', label='Reference noise signal')\n",
    "ax3.plot(t, output, c='green', label=f'SNR Gain = {delta_snr} dB')\n",
    "\n",
    "ax0.text(0.5, -0.3, '(a) Desired signal',\n",
    "         transform=ax0.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax1.text(0.5, -0.3, '(b) Corrupted signal',\n",
    "         transform=ax1.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax2.text(0.5, -0.3, '(c) Reference noise signal',\n",
    "         transform=ax2.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax3.text(0.5, -0.5, f'(d) Filter output (SNR Gain = {delta_snr} dB)',\n",
    "         transform=ax3.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax3.set_xlabel('time(s)', x=0.05)\n",
    "ax0.set_ylabel('Amplitude')\n",
    "ax1.set_ylabel('Amplitude')\n",
    "ax2.set_ylabel('Amplitude')\n",
    "ax3.set_ylabel('Amplitude')\n",
    "\n",
    "# Plots der Filterperfomanz\n",
    "figure2, (ax4, ax5) = plt.subplots(2, 1, figsize=(15, 7), sharex=True)\n",
    "ax4.set_ylim(-1, 1)\n",
    "ax4.plot(t2, error_signal, c='purple', label='Error (Desired signal - Filter output)')\n",
    "for i in indices:\n",
    "    ax5.plot(t2, coefficient_matrix[:,i], label=f'Coefficient {i+1}')\n",
    "\n",
    "ax4.text(0.5, -0.3, '(a) Error signal',\n",
    "         transform=ax4.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax5.text(0.5, -0.5, '(b) Coefficient values (1st, 8th, 16th)',\n",
    "         transform=ax5.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax5.set_xlabel('time(s)', x=0.05)\n",
    "ax4.set_ylabel('Amplitude')\n",
    "ax5.set_ylabel('Coeffcient value')\n",
    "\n",
    "#Grids direkt auf Subplots anwenden\n",
    "ax0.grid(True, linestyle='--', alpha=0.4)\n",
    "ax1.grid(True, linestyle='--', alpha=0.4)\n",
    "ax2.grid(True, linestyle='--', alpha=0.4)\n",
    "ax3.grid(True, linestyle='--', alpha=0.4)\n",
    "ax4.grid(True, linestyle='--', alpha=0.4)\n",
    "ax5.grid(True, linestyle='--', alpha=0.4)\n",
    "\n",
    "#Spines direkt auf Subplots anwenden\n",
    "ax0.spines['top'].set_visible(False)\n",
    "ax1.spines['top'].set_visible(False)\n",
    "ax2.spines['top'].set_visible(False)\n",
    "ax3.spines['top'].set_visible(False)\n",
    "ax4.spines['top'].set_visible(False)\n",
    "ax5.spines['top'].set_visible(False)\n",
    "ax0.spines['right'].set_visible(False)\n",
    "ax1.spines['right'].set_visible(False)\n",
    "ax2.spines['right'].set_visible(False)\n",
    "ax3.spines['right'].set_visible(False)\n",
    "ax4.spines['right'].set_visible(False)\n",
    "ax5.spines['right'].set_visible(False)\n",
    "\n",
    "# Schriftgrößen für LaTeX-Dokument\n",
    "plt.rcParams.update({\n",
    "    \"text.usetex\": True,\n",
    "    \"font.family\": \"serif\",\n",
    "    'font.size': 16,          # Standardtext\n",
    "    'axes.labelsize': 30,     # Achsenbeschriftungen\n",
    "    'xtick.labelsize': 25,    # Tick-Beschriftungen\n",
    "    'ytick.labelsize': 25,\n",
    "    'legend.fontsize': 15     # Legende\n",
    "})\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": [],
   "source": [
    "#Plots für intermediate/komplexen Usecases\n",
    "\n",
    "from pandas import Series\n",
    "\n",
    "COMPLEX= True\n",
    "SIMULATION = False\n",
    "AUDIO = False\n",
    "PLOT = False\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 = 45\n",
    "step_size = 0.01\n",
    "noise_delay = 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",
    "if COMPLEX == True:\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",
    "else:\n",
    "    desired_signal_r11 = desired_signal\n",
    "    noise_signal_r11 = noise_signal\n",
    "    noise_signal_vpu = noise_signal\n",
    "\n",
    "# Noise Delay bedeutet, dass das Corruption Noise Signal im Corrupted Signal verzögert ist (zum Reference Noise Signal)\n",
    "if noise_delay != 0:\n",
    "    # Delay von ms in Samples umrechnen, 0-Array erzeugen\n",
    "    delay_samples = int(noise_delay * fs)\n",
    "    noise_signal_r11_delayed = np.zeros_like(noise_signal_r11)\n",
    "    # Schneided die Delay Samples vom ursprünglichen Array ab und schreibt sie nach entsprechend vielen Nullen ins neue Array\n",
    "    noise_signal_r11_delayed[delay_samples:] = noise_signal_r11[:-delay_samples]\n",
    "    # Corrupted Signal mit verzögertem Noise\n",
    "    corrupted_signal = desired_signal_r11 + noise_signal_r11_delayed\n",
    "else:\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))/20000\n",
    "\n",
    "if SERIES == True:\n",
    "    for i in range(16, coefficients+2, 2):\n",
    "        output, coefficient_matrix = anr_function_c(corrupted_signal, noise_signal_vpu, i, 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_r11)[:-coefficients]\n",
    "        t2 = np.linspace(0, len(error_signal), len(error_signal))/20000\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_r11**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('snr_evaluation/male+breathing', 'a', newline='') as f:\n",
    "            writer = csv.writer(f)\n",
    "            writer.writerow([i, delta_snr])\n",
    "else:\n",
    "        output, coefficient_matrix = anr_function_c(corrupted_signal, noise_signal_vpu, 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_r11)[:-coefficients]\n",
    "t2 = np.linspace(0, len(error_signal), len(error_signal))/20000\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_r11**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",
    "    dsp_desired_signal_r11 = desired_signal_r11*(2**(15)-1)\n",
    "    dsp_noise_signal_r11 = noise_signal_r11*(2**(15)-1)\n",
    "    dsp_noise_signal_vpu = noise_signal_vpu*(2**(15)-1)\n",
    "    dsp_corrupted_signal = corrupted_signal*(2**(15)-1)\n",
    "    python_output = output*(2**(15)-1)\n",
    "    python_coefficient_matrix = coefficient_matrix*(2**(15)-1)\n",
    "    np.savetxt('simulation_data/complex_dsp_desired_signal_r11.txt', dsp_desired_signal_r11, fmt='%d')\n",
    "    np.savetxt('simulation_data/complex_dsp_noise_signal_r11.txt', dsp_noise_signal_r11, fmt='%d')\n",
    "    np.savetxt('simulation_data/complex_dsp_noise_signal_vpu.txt', dsp_noise_signal_vpu, fmt='%d', delimiter=\"\\n\")\n",
    "    np.savetxt('simulation_data/complex_dsp_corrupted_signal.txt', dsp_corrupted_signal, fmt='%d', delimiter=\"\\n\")\n",
    "    np.savetxt('filter_output/complex_python_output.txt', python_output, fmt='%d', delimiter=\"\\n\")\n",
    "    np.savetxt('filter_output/complex_python_filter_coefficients.txt', python_coefficient_matrix, fmt='%d', delimiter=\",\")\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', label='Desired signal')\n",
    "ax1.plot(t, corrupted_signal, c='royalblue', label='Corrupted signal')\n",
    "ax2.plot(t, noise_signal_vpu, c='chocolate', label='Reference noise signal')\n",
    "ax3.plot(t, output, c='green', label=f'SNR Gain = {delta_snr} dB')\n",
    "\n",
    "ax0.text(0.5, -0.3, '(a) Desired signal',\n",
    "         transform=ax0.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax1.text(0.5, -0.3, '(b) Corrupted signal',\n",
    "         transform=ax1.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax2.text(0.5, -0.3, '(c) Reference noise signal',\n",
    "         transform=ax2.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax3.text(0.5, -0.5, f'(d) Filter output (SNR Gain = {delta_snr} dB)',\n",
    "         transform=ax3.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax3.set_xlabel('time(s)', x=0.05)\n",
    "ax0.set_ylabel('Amplitude')\n",
    "ax1.set_ylabel('Amplitude')\n",
    "ax2.set_ylabel('Amplitude')\n",
    "ax3.set_ylabel('Amplitude')\n",
    "\n",
    "# Plots der Filterperfomanz\n",
    "figure2, (ax4, ax5) = plt.subplots(2, 1, figsize=(15, 7), sharex=True)\n",
    "ax4.set_ylim(-1, 1)\n",
    "ax4.plot(t2, error_signal, c='purple', label='Error (Desired signal - Filter output)')\n",
    "for i in indices:\n",
    "    ax5.plot(t2, coefficient_matrix[:,i], label=f'Coefficient {i+1}')\n",
    "\n",
    "ax4.text(0.5, -0.3, '(a) Error signal',\n",
    "         transform=ax4.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax5.text(0.5, -0.5, '(b) Coefficient values (1st, 8th, 16th)',\n",
    "         transform=ax5.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax5.set_xlabel('time(s)', x=0.05)\n",
    "ax4.set_ylabel('Amplitude')\n",
    "ax5.set_ylabel('Coeffcient value')\n",
    "\n",
    "# Plot Sensitivitätskurve\n",
    "figure3, (ax6, ax7) = plt.subplots(2, 1, figsize=(15, 7), 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', label='Sensitivity Curve (Primary sensor)' )\n",
    "ax7.plot(frequency_vpu, gain_vpu, c='orangered', label='Sensitivity Curve (Secondary sensor)')\n",
    "\n",
    "ax6.text(0.5, -0.3, '(a) Sensitivity Curve (Primary sensor)',\n",
    "         transform=ax6.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "ax7.text(0.5, -0.5, '(b) Sensitivity Curve (Secondary sensor)',\n",
    "         transform=ax7.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax7.set_xlabel('Frequency (Hz)', x=0.1)\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, 10), sharex=True, sharey=True)\n",
    "ax8.set_ylim(1.0, -1.0)\n",
    "ax8.plot(t, noise_signal, c='orange', label='Noise signal')\n",
    "ax9.plot(t, noise_signal_r11, c='darkorange', label='Corruption noise signal (Primary sensor)')\n",
    "ax10.plot(t, noise_signal_vpu, c='peru', label='Reference noise signal (Secondary sensor)')\n",
    "\n",
    "ax8.text(0.5, -0.3, '(a) Noise signal',\n",
    "         transform=ax8.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax9.text(0.5, -0.3, '(b) Corruption noise signal (Primary sensor)',\n",
    "         transform=ax9.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax10.text(0.5, -0.5, '(c) Reference noise signal (Secondary sensor)',\n",
    "         transform=ax10.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax10.set_xlabel('time(s)', x=0.05)\n",
    "ax8.set_ylabel('Amplitude')\n",
    "ax9.set_ylabel('Amplitude')\n",
    "ax10.set_ylabel('Amplitude')\n",
    "\n",
    "#Grids direkt auf Subplots anwenden\n",
    "ax0.grid(True, linestyle='--', alpha=0.4)\n",
    "ax1.grid(True, linestyle='--', alpha=0.4)\n",
    "ax2.grid(True, linestyle='--', alpha=0.4)\n",
    "ax3.grid(True, linestyle='--', alpha=0.4)\n",
    "ax4.grid(True, linestyle='--', alpha=0.4)\n",
    "ax5.grid(True, linestyle='--', alpha=0.4)\n",
    "ax6.grid(True, linestyle='--', alpha=0.4)\n",
    "ax7.grid(True, linestyle='--', alpha=0.4)\n",
    "ax8.grid(True, linestyle='--', alpha=0.4)\n",
    "ax9.grid(True, linestyle='--', alpha=0.4)\n",
    "ax10.grid(True, linestyle='--', alpha=0.4)\n",
    "\n",
    "#Spines direkt auf Subplots anwenden\n",
    "ax0.spines['top'].set_visible(False)\n",
    "ax1.spines['top'].set_visible(False)\n",
    "ax2.spines['top'].set_visible(False)\n",
    "ax3.spines['top'].set_visible(False)\n",
    "ax4.spines['top'].set_visible(False)\n",
    "ax5.spines['top'].set_visible(False)\n",
    "ax6.spines['top'].set_visible(False)\n",
    "ax7.spines['top'].set_visible(False)\n",
    "ax8.spines['top'].set_visible(False)\n",
    "ax9.spines['top'].set_visible(False)\n",
    "ax10.spines['top'].set_visible(False)\n",
    "ax0.spines['right'].set_visible(False)\n",
    "ax1.spines['right'].set_visible(False)\n",
    "ax2.spines['right'].set_visible(False)\n",
    "ax3.spines['right'].set_visible(False)\n",
    "ax4.spines['right'].set_visible(False)\n",
    "ax5.spines['right'].set_visible(False)\n",
    "ax6.spines['right'].set_visible(False)\n",
    "ax7.spines['right'].set_visible(False)\n",
    "ax8.spines['right'].set_visible(False)\n",
    "ax9.spines['right'].set_visible(False)\n",
    "ax10.spines['right'].set_visible(False)\n",
    "\n",
    "# Schriftgrößen für LaTeX-Dokument\n",
    "plt.rcParams.update({\n",
    "    \"text.usetex\": True,\n",
    "    \"font.family\": \"serif\",\n",
    "    'font.size': 16,          # Standardtext\n",
    "    'axes.labelsize': 30,     # Achsenbeschriftungen\n",
    "    'xtick.labelsize': 25,    # Tick-Beschriftungen\n",
    "    'ytick.labelsize': 25,\n",
    "    'legend.fontsize': 15     # Legende\n",
    "})\n",
    "\n",
    "figure1.tight_layout()\n",
    "figure2.tight_layout()\n",
    "figure3.tight_layout()\n",
    "figure4.tight_layout()\n",
    "if PLOT == True:\n",
    "    if COMPLEX == 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",
    "    else:\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": [],
   "source": [
    "#Plots für SNR Vergleich\n",
    "\n",
    "PLOT = False\n",
    "\n",
    "# Daten aus .csv laden\n",
    "data_male_breathing = np.loadtxt('snr_evaluation/male+breathing', delimiter=\",\")\n",
    "data_male_chewing = np.loadtxt('snr_evaluation/male+chewing', delimiter=\",\")\n",
    "data_male_scratching = np.loadtxt('snr_evaluation/male+scratching', delimiter=\",\")\n",
    "data_male_drinking = np.loadtxt('snr_evaluation/male+drinking', delimiter=\",\")\n",
    "data_male_coughing = np.loadtxt('snr_evaluation/male+coughing', delimiter=\",\")\n",
    "\n",
    "\n",
    "# Daten laden\n",
    "x = data_male_breathing[:, 0]\n",
    "male_breathing = savgol_filter(data_male_breathing[:, 1], 10, 3)\n",
    "male_chewing = savgol_filter(data_male_chewing[:, 1], 10, 3)\n",
    "male_scratching = savgol_filter(data_male_scratching[:, 1], 10, 3)\n",
    "male_drinking = savgol_filter(data_male_drinking[:, 1], 10, 3)\n",
    "male_coughing = savgol_filter(data_male_coughing[:, 1], 10, 3)\n",
    "\n",
    "# Alle Kurven in ein Array stapeln\n",
    "all_curves = np.vstack([\n",
    "    male_breathing,\n",
    "    male_chewing,\n",
    "    male_scratching,\n",
    "    male_drinking,\n",
    "    male_coughing\n",
    "])\n",
    "\n",
    "# Punktweiser Mittelwert\n",
    "mean_gain = np.mean(all_curves, axis=0)\n",
    "\n",
    "# Plot\n",
    "plt.figure(figsize=(15, 7))\n",
    "plt.plot(x, male_breathing, linestyle='-',  linewidth=1.5, alpha=0.7, label='Breathing Noise')\n",
    "plt.plot(x, male_chewing, linestyle='--', linewidth=1.5, alpha=0.7, label='Chewing Noise')\n",
    "plt.plot(x, male_scratching, linestyle='-.', linewidth=1.5, alpha=0.7, label='Scratching Noise')\n",
    "plt.plot(x, male_drinking, linestyle=':',  linewidth=1.5, alpha=0.7, label='Drinking Noise')\n",
    "plt.plot(x, male_coughing, linestyle=(0, (3, 1, 1, 1)), linewidth=1.5, alpha=0.7, label='Coughing Noise')\n",
    "plt.plot(x, mean_gain, linestyle='--', color='red', linewidth=2.5, label='Mean SNR-Gain')\n",
    "\n",
    "plt.rcParams.update({\n",
    "    \"text.usetex\": True,\n",
    "    \"font.family\": \"serif\",\n",
    "    'font.size': 16,          # Standardtext\n",
    "    'axes.labelsize': 30,     # Achsenbeschriftungen\n",
    "    'xtick.labelsize': 25,    # Tick-Beschriftungen\n",
    "    'ytick.labelsize': 25,\n",
    "    'legend.fontsize': 25     # Legende\n",
    "})\n",
    "\n",
    "plt.xlabel(\"Filter length\")\n",
    "plt.ylabel(\"SNR-Gain (dB)\")\n",
    "plt.grid(True, linestyle='--', alpha=0.4)\n",
    "#Spines auf ganzen Plot anwenden\n",
    "plt.gca().spines['top'].set_visible(False)\n",
    "plt.gca().spines['right'].set_visible(False)\n",
    "plt.legend(frameon=False, loc='upper left')\n",
    "plt.tight_layout()\n",
    "if PLOT == True:\n",
    "    plt.savefig(f'plots/fig_snr_comparison', dpi=600)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Plots der Störsignale\n",
    "\n",
    "PLOT = True\n",
    "\n",
    "fs, data_1 = load_wav(f'./audio_data/Störsignal/breathing.wav')\n",
    "fs, data_2 = load_wav(f'./audio_data/Störsignal/coughing.wav')\n",
    "fs, data_3 = load_wav(f'./audio_data/Störsignal/scratching.wav')\n",
    "fs, data_4 = load_wav(f'./audio_data/Störsignal/drinking.wav')\n",
    "fs, data_5 = load_wav(f'./audio_data/Störsignal/chewing.wav')\n",
    "\n",
    "t = np.linspace(0, len(data_1), len(data_1))/20000\n",
    "\n",
    "figure1, (ax1, ax2, ax3, ax4, ax5) = plt.subplots(5, 1, figsize=(15, 15), sharex=True, sharey=True)\n",
    "ax1.set_ylim(1.0, -1.0)\n",
    "ax1.plot(t, data_1, c='darkorange', label='Breathing Noise')\n",
    "ax2.plot(t, data_2, c='indianred', label='Coughing Noise')\n",
    "ax3.plot(t, data_3, c='deepskyblue', label='Scratching Noise')\n",
    "ax4.plot(t, data_4, c='forestgreen', label='Drinking Noise')\n",
    "ax5.plot(t, data_5, c='darkorchid', label='Chewing Noise')\n",
    "\n",
    "ax1.text(0.5, -0.3, '(a) Breathing Noise',\n",
    "         transform=ax1.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax2.text(0.5, -0.3, '(b) Coughing Noise',\n",
    "         transform=ax2.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax3.text(0.5, -0.3, '(c) Scratching Noise',\n",
    "         transform=ax3.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax4.text(0.5, -0.3, '(d) Drinking Noise',\n",
    "         transform=ax4.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax5.text(0.5, -0.5, '(e) Chewing Noise',\n",
    "         transform=ax5.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax5.set_xlabel(\"time (s)\", x=0.05)\n",
    "ax1.set_ylabel(\"Amplitude\")\n",
    "ax2.set_ylabel(\"Amplitude\")\n",
    "ax3.set_ylabel(\"Amplitude\")\n",
    "ax4.set_ylabel(\"Amplitude\")\n",
    "ax5.set_ylabel(\"Amplitude\")\n",
    "#ax5.xaxis.set_label_coords(0.5, -0.4)\n",
    "\n",
    "ax1.grid(True, linestyle='--', alpha=0.4)\n",
    "ax2.grid(True, linestyle='--', alpha=0.4)\n",
    "ax3.grid(True, linestyle='--', alpha=0.4)\n",
    "ax4.grid(True, linestyle='--', alpha=0.4)\n",
    "ax5.grid(True, linestyle='--', alpha=0.4)\n",
    "\n",
    "#Spines direkt auf Subplots anwenden\n",
    "ax1.spines['top'].set_visible(False)\n",
    "ax2.spines['top'].set_visible(False)\n",
    "ax3.spines['top'].set_visible(False)\n",
    "ax4.spines['top'].set_visible(False)\n",
    "ax5.spines['top'].set_visible(False)\n",
    "ax1.spines['right'].set_visible(False)\n",
    "ax2.spines['right'].set_visible(False)\n",
    "ax3.spines['right'].set_visible(False)\n",
    "ax4.spines['right'].set_visible(False)\n",
    "ax5.spines['right'].set_visible(False)\n",
    "\n",
    "# Schriftgrößen für LaTeX-Dokument\n",
    "plt.rcParams.update({\n",
    "    \"text.usetex\": True,\n",
    "    \"font.family\": \"serif\",\n",
    "    'font.size': 16,          # Standardtext\n",
    "    'axes.labelsize': 30,     # Achsenbeschriftungen\n",
    "    'xtick.labelsize': 25,    # Tick-Beschriftungen\n",
    "    'ytick.labelsize': 25,\n",
    "    'legend.fontsize': 15     # Legende\n",
    "})\n",
    "\n",
    "figure1.tight_layout()\n",
    "if PLOT == True:\n",
    "    plt.savefig(f'plots/fig_noise_signals', dpi=600)\n",
    "figure1.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Filterlänge und Update-Schritte Vergleich\n",
    "\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "\n",
    "PLOT = False\n",
    "\n",
    "# Filterlänge\n",
    "N = np.arange(1, 128)\n",
    "# Verschiedene Updateschritte\n",
    "U_values = [1, 0.5, 0.25]\n",
    "\n",
    "C_total_1 = N + (6*N + 8)*U_values[0] + 34\n",
    "C_total_2 = N + (6*N + 8)*U_values[1] + 34\n",
    "C_total_3 = N + (6*N + 8)*U_values[2] + 34\n",
    "\n",
    "plt.figure(figsize=(15, 7))\n",
    "plt.plot(N, C_total_1, linestyle='-',  linewidth=1.5, alpha=0.7, label=f'1/U = {U_values[0]}')\n",
    "plt.plot(N, C_total_2, linestyle='--', linewidth=1.5, alpha=0.7, label=f'1/U = {U_values[1]}')\n",
    "plt.plot(N, C_total_3, linestyle='-.', linewidth=1.5, alpha=0.7, label=f'1/U = {U_values[2]}')\n",
    "\n",
    "plt.rcParams.update({\n",
    "    \"text.usetex\": True,\n",
    "    \"font.family\": \"serif\",\n",
    "    'font.size': 16,          # Standardtext\n",
    "    'axes.labelsize': 30,     # Achsenbeschriftungen\n",
    "    'xtick.labelsize': 25,    # Tick-Beschriftungen\n",
    "    'ytick.labelsize': 25,\n",
    "    'legend.fontsize': 25     # Legende\n",
    "})\n",
    "\n",
    "plt.xlabel(\"Filter length\")\n",
    "plt.ylabel(\"Cycles/Sample\")\n",
    "plt.grid(True, linestyle='--', alpha=0.4)\n",
    "#Spines auf ganzen Plot anwenden\n",
    "plt.gca().spines['top'].set_visible(False)\n",
    "plt.gca().spines['right'].set_visible(False)\n",
    "plt.legend(frameon=False, loc='lower right')\n",
    "plt.tight_layout()\n",
    "if PLOT == True:\n",
    "    plt.savefig(f'plots/fig_c_total', dpi=600)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Vergleich Output High/Low-Level\n",
    "\n",
    "PLOT = False\n",
    "COMPLEX = True\n",
    "\n",
    "if COMPLEX == True:\n",
    "    python_output = np.loadtxt('filter_output/complex_python_output.txt', delimiter=\",\")/(2**(15)-1)\n",
    "    dsp_output = np.loadtxt('filter_output/complex_dsp_output.txt', delimiter=\",\")[:-1]/(2**(15)-1)\n",
    "else:\n",
    "    python_output = np.loadtxt('filter_output/simple_python_output.txt', delimiter=\",\")/(2**(15)-1)\n",
    "    dsp_output = np.loadtxt('filter_output/simple_dsp_output.txt', delimiter=\",\")[:-1]/(2**(15)-1)\n",
    "\n",
    "diff = python_output - dsp_output\n",
    "\n",
    "if COMPLEX == True:\n",
    "    t = np.linspace(0, 200000, 200000)/20000\n",
    "else:\n",
    "    t = np.linspace(0, 2000, 2000)/200\n",
    "\n",
    "figure1, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(15, 9), sharex=True, sharey=True)\n",
    "ax1.set_ylim(1.0, -1.0)\n",
    "ax1.plot(t, python_output, linestyle='-', c='deepskyblue',  linewidth=1, alpha=1, label='High Level Simulation')\n",
    "ax2.plot(t, dsp_output, linestyle='-', c='indianred', linewidth=1, alpha=1, label='Low Level Simulation')\n",
    "ax3.plot(t, python_output, linestyle='-', c='deepskyblue',  linewidth=1, alpha=1)\n",
    "ax3.plot(t, dsp_output, linestyle='-', c='indianred', linewidth=1, alpha=0.7)\n",
    "ax3.plot(t, diff, linestyle='-', c='green', linewidth=2, alpha=0.7, label=f'Error Amplitude')\n",
    "\n",
    "figure2, ax4 = plt.subplots(1, 1, figsize=(15, 7))\n",
    "ax4.hist(diff, bins=100, density=True, color='green',edgecolor='black', alpha=0.7)\n",
    "ax4.set_yscale('log')\n",
    "\n",
    "mean = np.mean(diff)\n",
    "std = np.std(diff)\n",
    "ax4.axvline(mean, linestyle='-', linewidth=3, label='Mean')\n",
    "ax4.axvline(mean + std, linestyle='--', linewidth=2, label='+1 Sigma')\n",
    "ax4.axvline(mean - std, linestyle='--', linewidth=2, label='-1 Sigma')\n",
    "\n",
    "\n",
    "plt.rcParams.update({\n",
    "    \"text.usetex\": True,\n",
    "    \"font.family\": \"serif\",\n",
    "    'font.size': 16,          # Standardtext\n",
    "    'axes.labelsize': 30,     # Achsenbeschriftungen\n",
    "    'xtick.labelsize': 25,    # Tick-Beschriftungen\n",
    "    'ytick.labelsize': 25,\n",
    "    'legend.fontsize': 25     # Legende\n",
    "})\n",
    "\n",
    "ax1.text(0.5, -0.3, '(a) High Level Simulation',\n",
    "         transform=ax1.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax2.text(0.5, -0.3, '(b) Low Level Simulation',\n",
    "         transform=ax2.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax3.text(0.5, -0.5, f'(c) Comparision High/Low Level Simulation',\n",
    "         transform=ax3.transAxes,\n",
    "         fontsize=25,\n",
    "         fontweight='normal',\n",
    "         ha='center',\n",
    "         va='bottom')\n",
    "\n",
    "ax3.set_xlabel(\"time (s)\", x=0.05)\n",
    "ax1.set_ylabel(\"Amplitude\")\n",
    "ax2.set_ylabel(\"Amplitude\")\n",
    "ax3.set_ylabel(\"Amplitude\")\n",
    "ax3.set_ylabel(\"Amplitude\")\n",
    "\n",
    "ax4.set_xlabel(\"Error Amplitude\")\n",
    "ax4.set_ylabel(\"Samples\")\n",
    "\n",
    "ax1.grid(True, linestyle='--', alpha=0.4)\n",
    "ax2.grid(True, linestyle='--', alpha=0.4)\n",
    "ax3.grid(True, linestyle='--', alpha=0.4)\n",
    "ax4.grid(True, linestyle='--', alpha=0.4)\n",
    "\n",
    "#Spines direkt auf Subplots anwenden\n",
    "ax1.spines['top'].set_visible(False)\n",
    "ax2.spines['top'].set_visible(False)\n",
    "ax3.spines['top'].set_visible(False)\n",
    "ax4.spines['top'].set_visible(False)\n",
    "ax1.spines['right'].set_visible(False)\n",
    "ax2.spines['right'].set_visible(False)\n",
    "ax3.spines['right'].set_visible(False)\n",
    "ax4.spines['right'].set_visible(False)\n",
    "ax3.legend(frameon=False, loc='upper right')\n",
    "ax4.legend(frameon=False, loc='upper right')\n",
    "\n",
    "figure1.tight_layout()\n",
    "figure2.tight_layout()\n",
    "if PLOT == True:\n",
    "    figure1.savefig(f'plots/fig_high_low_comparison', dpi=600)\n",
    "    figure2.savefig(f'plots/fig_high_low_comparison_hist', dpi=600)\n",
    "figure1.show()\n",
    "figure2.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Single Reduced Update Plot\n",
    "\n",
    "import matplotlib.ticker as mtick\n",
    "from scipy.interpolate import make_interp_spline\n",
    "\n",
    "PLOT = False\n",
    "\n",
    "# Daten aus .csv laden\n",
    "update_rate_breathing = np.loadtxt('update_rate_evaluation/update_rate_breathing.csv', delimiter=\";\", skiprows=1)\n",
    "\n",
    "# Daten laden\n",
    "x = update_rate_breathing[:, 0]\n",
    "update_gain_breathing = update_rate_breathing[:, 2]\n",
    "update_cycles_breathing = update_rate_breathing[:, 4]\n",
    "update_load_breathing = update_rate_breathing[:, 5]\n",
    "update_cycles_breathing_new = update_rate_breathing[:, 7]\n",
    "update_load_breathing_new = update_rate_breathing[:, 8]\n",
    "\n",
    "# Sortieren\n",
    "idx = np.argsort(x)\n",
    "x = x[idx]\n",
    "update_gain_breathing = update_gain_breathing[idx]\n",
    "update_cycles_breathing = update_cycles_breathing[idx]\n",
    "update_load_breathing = update_load_breathing[idx]\n",
    "update_cycles_breathing_new = update_cycles_breathing_new[idx]\n",
    "update_load_breathing_new = update_load_breathing_new[idx]\n",
    "\n",
    "# Smoothing\n",
    "x_smooth = np.linspace(x.min(), x.max(), 300)\n",
    "\n",
    "update_gain_smooth = make_interp_spline(x, update_gain_breathing)(x_smooth)\n",
    "update_cycles_smooth = make_interp_spline(x, update_cycles_breathing)(x_smooth)\n",
    "update_load_smooth = make_interp_spline(x, update_load_breathing)(x_smooth)\n",
    "update_cycles_smooth_new = make_interp_spline(x, update_cycles_breathing_new)(x_smooth)\n",
    "update_load_smooth_new = make_interp_spline(x, update_load_breathing_new)(x_smooth)\n",
    "\n",
    "diff_smooth = np.abs(update_gain_smooth - update_cycles_smooth)\n",
    "idx_max = np.argmax(diff_smooth)\n",
    "x_max = x_smooth[idx_max]\n",
    "y1_max = update_gain_smooth[idx_max]\n",
    "y2_max = update_cycles_smooth[idx_max]\n",
    "\n",
    "# Plot\n",
    "figure1, ax1 = plt.subplots(figsize=(15, 7))\n",
    "ax1.plot(x_smooth, update_gain_smooth, linestyle='--', color='indianred', linewidth=2, alpha=0.9, label='SNR-Gain')\n",
    "ax1.plot(x_smooth, update_cycles_smooth, linestyle='-.', color='skyblue', linewidth=2, alpha=0.9, label='Cycles/Sample')\n",
    "ax1.plot(x_smooth, update_load_smooth, linestyle=':', color='forestgreen', linewidth=2, alpha=0.9, label='DSP Load')\n",
    "ax1.plot([x_max, x_max], [y1_max, y2_max], color='black', linestyle=':', linewidth=2)\n",
    "\n",
    "ax1.scatter(x, update_gain_breathing, color='indianred', s=40)\n",
    "ax1.scatter(x, update_cycles_breathing, color='skyblue', s=40)\n",
    "ax1.scatter(x, update_load_breathing, color='forestgreen', s=40)\n",
    "\n",
    "# Plot\n",
    "figure2, ax2 = plt.subplots(figsize=(15, 7))\n",
    "ax2.plot(x_smooth, update_gain_smooth, linestyle='--', color='indianred', linewidth=2, alpha=0.9, label='SNR-Gain')\n",
    "ax2.plot(x_smooth, update_cycles_smooth, linestyle='-.', color='skyblue', linewidth=2, alpha=0.3)\n",
    "ax2.plot(x_smooth, update_load_smooth, linestyle=':', color='forestgreen', linewidth=2, alpha=0.3)\n",
    "ax2.plot(x_smooth, update_cycles_smooth_new, linestyle='-', color='skyblue', linewidth=2, alpha=0.9, label='Cycles/Sample (New)')\n",
    "ax2.plot(x_smooth, update_load_smooth_new, linestyle='-', color='forestgreen', linewidth=2, alpha=0.9, label='DSP Load (New)')\n",
    "\n",
    "ax2.scatter(x, update_gain_breathing, color='indianred', s=40)\n",
    "ax2.scatter(x, update_cycles_breathing, color='skyblue', s=40, alpha=0.3)\n",
    "ax2.scatter(x, update_load_breathing, color='forestgreen', s=40, alpha=0.3)\n",
    "ax2.scatter(x, update_cycles_breathing_new, color='skyblue', s=40)\n",
    "ax2.scatter(x, update_load_breathing_new, color='forestgreen', s=40)\n",
    "\n",
    "ax1.text(x_max, (y1_max + y2_max)/2+0.1,\n",
    "         f'Max. offset at update rate {x_max:.2f}',\n",
    "         fontsize=20,\n",
    "         ha='left')\n",
    "\n",
    "plt.rcParams.update({\n",
    "    \"text.usetex\": True,\n",
    "    \"font.family\": \"serif\",\n",
    "    'font.size': 16,          # Standardtext\n",
    "    'axes.labelsize': 30,     # Achsenbeschriftungen\n",
    "    'xtick.labelsize': 25,    # Tick-Beschriftungen\n",
    "    'ytick.labelsize': 25,\n",
    "    'legend.fontsize': 25     # Legende\n",
    "})\n",
    "\n",
    "\n",
    "ax1.set_xlabel(\"Update Rate\")\n",
    "ax1.set_ylabel(\"Relative Performance\")\n",
    "ax2.set_xlabel(\"Update Rate\")\n",
    "ax2.set_ylabel(\"Relative Performance\")\n",
    "ax1.grid(True, linestyle='-.', alpha=0.4)\n",
    "ax2.grid(True, linestyle='-.', alpha=0.4)\n",
    "#Spines auf ganzen Plot anwenden\n",
    "ax1.yaxis.set_major_formatter(mtick.PercentFormatter(1.0))\n",
    "ax2.yaxis.set_major_formatter(mtick.PercentFormatter(1.0))\n",
    "ax1.spines['top'].set_visible(False)\n",
    "ax1.spines['right'].set_visible(False)\n",
    "ax2.spines['top'].set_visible(False)\n",
    "ax2.spines['right'].set_visible(False)\n",
    "ax1.invert_xaxis()\n",
    "ax2.invert_xaxis()\n",
    "ax1.legend(frameon=False, loc='upper right')\n",
    "ax2.legend(frameon=False, loc='upper right')\n",
    "figure1.tight_layout()\n",
    "figure2.tight_layout()\n",
    "if PLOT == True:\n",
    "    figure1.savefig(f'plots/fig_snr_update_rate', dpi=600)\n",
    "    figure2.savefig(f'plots/fig_snr_update_rate_new', dpi=600)\n",
    "figure1.show()\n",
    "figure2.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Multi Reduced Update Plot\n",
    "\n",
    "import matplotlib.ticker as mtick\n",
    "from scipy.interpolate import make_interp_spline\n",
    "\n",
    "PLOT = False\n",
    "\n",
    "# Daten aus .csv laden\n",
    "update_rate_breathing = np.loadtxt('update_rate_evaluation/update_rate_breathing.csv', delimiter=\";\", skiprows=1)\n",
    "update_rate_chewing = np.loadtxt('update_rate_evaluation/update_rate_chewing.csv', delimiter=\";\", skiprows=1)\n",
    "update_rate_coughing = np.loadtxt('update_rate_evaluation/update_rate_coughing.csv', delimiter=\";\", skiprows=1)\n",
    "update_rate_drinking = np.loadtxt('update_rate_evaluation/update_rate_drinking.csv', delimiter=\";\", skiprows=1)\n",
    "update_rate_scratching = np.loadtxt('update_rate_evaluation/update_rate_scratching.csv', delimiter=\";\", skiprows=1)\n",
    "\n",
    "# Daten laden\n",
    "x = update_rate_breathing[:, 0]\n",
    "update_gain_breathing = update_rate_breathing[:, 2]\n",
    "update_cycles_breathing = update_rate_breathing[:, 4]\n",
    "update_load_breathing = update_rate_breathing[:, 5]\n",
    "update_gain_chewing = update_rate_chewing[:, 2]\n",
    "update_cycles_chewing = update_rate_chewing[:, 4]\n",
    "update_load_chewing = update_rate_chewing[:, 5]\n",
    "update_gain_coughing = update_rate_coughing[:, 2]\n",
    "update_cycles_coughing = update_rate_coughing[:, 4]\n",
    "update_load_coughing = update_rate_coughing[:, 5]\n",
    "update_gain_drinking = update_rate_drinking[:, 2]\n",
    "update_cycles_drinking = update_rate_drinking[:, 4]\n",
    "update_load_drinking = update_rate_drinking[:, 5]\n",
    "update_gain_scratching = update_rate_scratching[:, 2]\n",
    "update_cycles_scratching = update_rate_scratching[:, 4]  \n",
    "update_load_scratching = update_rate_scratching[:, 5] \n",
    "\n",
    "# Sortieren\n",
    "idx = np.argsort(x)\n",
    "x = x[idx]\n",
    "update_gain_breathing = update_gain_breathing[idx]\n",
    "update_cycles_breathing = update_cycles_breathing[idx]\n",
    "update_load_breathing = update_load_breathing[idx]\n",
    "update_gain_chewing = update_gain_chewing[idx]\n",
    "update_cycles_chewing = update_cycles_chewing[idx]\n",
    "update_load_chewing = update_load_chewing[idx]\n",
    "update_gain_coughing = update_gain_coughing[idx]\n",
    "update_cycles_coughing = update_cycles_coughing[idx]\n",
    "update_load_coughing = update_load_coughing[idx]\n",
    "update_gain_drinking = update_gain_drinking[idx]\n",
    "update_cycles_drinking = update_cycles_drinking[idx]\n",
    "update_load_drinking = update_load_drinking[idx]\n",
    "update_gain_scratching = update_gain_scratching[idx]\n",
    "update_cycles_scratching = update_cycles_scratching[idx]\n",
    "update_load_scratching = update_load_scratching[idx]\n",
    "\n",
    "# Smoothing\n",
    "x_smooth = np.linspace(x.min(), x.max(), 300)\n",
    "\n",
    "gain_smooth_breathing = make_interp_spline(x, update_gain_breathing)(x_smooth)\n",
    "cycles_smooth_breathing = make_interp_spline(x, update_cycles_breathing)(x_smooth)\n",
    "load_smooth_breathing = make_interp_spline(x, update_load_breathing)(x_smooth)\n",
    "gain_smooth_chewing = make_interp_spline(x, update_gain_chewing)(x_smooth)\n",
    "cycles_smooth_chewing = make_interp_spline(x, update_cycles_chewing)(x_smooth)\n",
    "load_smooth_chewing = make_interp_spline(x, update_load_chewing)(x_smooth)\n",
    "gain_smooth_coughing = make_interp_spline(x, update_gain_coughing)(x_smooth)\n",
    "cycles_smooth_coughing = make_interp_spline(x, update_cycles_coughing)(x_smooth)\n",
    "load_smooth_coughing = make_interp_spline(x, update_load_coughing)(x_smooth)\n",
    "gain_smooth_drinking = make_interp_spline(x, update_gain_drinking)(x_smooth)\n",
    "cycles_smooth_drinking = make_interp_spline(x, update_cycles_drinking)(x_smooth)\n",
    "load_smooth_drinking = make_interp_spline(x, update_load_drinking)(x_smooth)\n",
    "gain_smooth_scratching = make_interp_spline(x, update_gain_scratching)(x_smooth)\n",
    "cycles_smooth_scratching = make_interp_spline(x, update_cycles_scratching)(x_smooth)\n",
    "load_smooth_scratching = make_interp_spline(x, update_load_scratching)(x_smooth)\n",
    "\n",
    "diff_smooth_breathing = gain_smooth_breathing - cycles_smooth_breathing\n",
    "diff_smooth_chewing = gain_smooth_chewing - cycles_smooth_chewing\n",
    "diff_smooth_coughing = gain_smooth_coughing - cycles_smooth_coughing\n",
    "diff_smooth_drinking = gain_smooth_drinking - cycles_smooth_drinking\n",
    "diff_smooth_scratching = gain_smooth_scratching - cycles_smooth_scratching\n",
    "\n",
    "# Alle Kurven in ein Array stapeln\n",
    "stack_difference = np.vstack([\n",
    "    diff_smooth_breathing,\n",
    "    diff_smooth_chewing,\n",
    "    diff_smooth_coughing,\n",
    "    diff_smooth_drinking,\n",
    "    diff_smooth_scratching\n",
    "])\n",
    "\n",
    "# Alle Kurven in ein Array stapeln\n",
    "stack_load = np.vstack([\n",
    "    load_smooth_breathing,\n",
    "    load_smooth_chewing,\n",
    "    load_smooth_coughing,\n",
    "    load_smooth_drinking,\n",
    "    load_smooth_scratching\n",
    "])\n",
    "\n",
    "# Punktweiser Mittelwert\n",
    "mean_gain = np.mean(stack_difference, axis=0)\n",
    "mean_load = np.mean(stack_load, axis=0)   \n",
    "\n",
    "idx_max_gain = np.argmax(mean_gain)\n",
    "x_max_gain = x_smooth[idx_max_gain]\n",
    "y_max_gain = mean_gain[idx_max_gain]\n",
    "x_max_load = x_smooth[idx_max_gain]\n",
    "y_max_load = mean_load[idx_max_gain]\n",
    "\n",
    "\n",
    "# Plot\n",
    "figure1, ax1 = plt.subplots(figsize=(15, 7))\n",
    "ax1.plot(x_smooth, diff_smooth_breathing, linestyle='--', color='indianred', linewidth=1.5, alpha=0.7, label='Breathing Noise')\n",
    "ax1.plot(x_smooth, diff_smooth_chewing, linestyle='-.', color='skyblue', linewidth=1.5, alpha=0.7, label='Chewing Noise')\n",
    "ax1.plot(x_smooth, diff_smooth_coughing, linestyle=':', color='forestgreen', linewidth=1.5, alpha=0.7, label='Coughing Noise')\n",
    "ax1.plot(x_smooth, diff_smooth_drinking, linestyle='--', color='darkorange', linewidth=1.5, alpha=0.7, label='Drinking Noise')\n",
    "ax1.plot(x_smooth, diff_smooth_scratching, linestyle='-.', color='darkorchid', linewidth=1.5, alpha=0.7, label='Scratching Noise')\n",
    "ax1.plot(x_smooth, mean_gain, linestyle='--', color='red', linewidth=2.5, alpha=1, label='Mean Performance Gain')\n",
    "ax1.plot([x_max_gain, x_max_gain], [y_max_gain, 0], color='black', linestyle=':', linewidth=2)\n",
    "\n",
    "ax1.text(x_max_gain+0.38, y_max_gain+0.03,\n",
    "         f'{y_max_gain*100:.1f} \\% mean performance gain at update rate {x_max_gain:.2f}',\n",
    "         fontsize=20,\n",
    "         ha='left')\n",
    "\n",
    "figure2, ax2 = plt.subplots(figsize=(15, 7))\n",
    "ax2.plot(x_smooth, load_smooth_breathing, linestyle='--', color='indianred', linewidth=1.5, alpha=0.7, label='Breathing Noise')\n",
    "ax2.plot(x_smooth, load_smooth_chewing, linestyle='-.', color='skyblue', linewidth=1.5, alpha=0.7, label='Chewing Noise')\n",
    "ax2.plot(x_smooth, load_smooth_coughing, linestyle=':', color='forestgreen', linewidth=1.5, alpha=0.7, label='Coughing Noise')\n",
    "ax2.plot(x_smooth, load_smooth_drinking, linestyle='--', color='darkorange', linewidth=1.5, alpha=0.7, label='Drinking Noise')\n",
    "ax2.plot(x_smooth, load_smooth_scratching, linestyle='-.', color='darkorchid', linewidth=1.5, alpha=0.7, label='Scratching Noise')\n",
    "ax2.plot(x_smooth, mean_load, linestyle='--', color='blue', linewidth=2.5, alpha=1, label='Mean DSP Load')\n",
    "ax2.plot([x_max_load, x_max_load], [y_max_load, 0], color='black', linestyle=':', linewidth=2)\n",
    "\n",
    "ax2.text(x_max_load+0.32, y_max_load-0.04,\n",
    "         f'{y_max_load*100:.1f} \\% mean DSP load at update rate {x_max_load:.2f}',\n",
    "         fontsize=20,\n",
    "         ha='left')\n",
    "\n",
    "plt.rcParams.update({\n",
    "    \"text.usetex\": True,\n",
    "    \"font.family\": \"serif\",\n",
    "    'font.size': 16,          # Standardtext\n",
    "    'axes.labelsize': 30,     # Achsenbeschriftungen\n",
    "    'xtick.labelsize': 25,    # Tick-Beschriftungen\n",
    "    'ytick.labelsize': 25,\n",
    "    'legend.fontsize': 25     # Legende\n",
    "})\n",
    "\n",
    "ax1.set_xlabel(\"Update Rate\")\n",
    "ax2.set_xlabel(\"Update Rate\")\n",
    "ax1.set_ylabel(\"Performance Gain\")\n",
    "ax2.set_ylabel(\"DSP Load\")\n",
    "ax1.grid(True, linestyle='-.', alpha=0.4)\n",
    "ax2.grid(True, linestyle='-.', alpha=0.4)\n",
    "ax1.set_ylim(0, 1)\n",
    "ax2.set_ylim(0, 0.7)\n",
    "#Spines auf ganzen Plot anwenden\n",
    "ax1.yaxis.set_major_formatter(mtick.PercentFormatter(1.0))\n",
    "ax2.yaxis.set_major_formatter(mtick.PercentFormatter(1.0))\n",
    "ax1.spines['top'].set_visible(False)\n",
    "ax2.spines['top'].set_visible(False)\n",
    "ax1.spines['right'].set_visible(False)\n",
    "ax2.spines['right'].set_visible(False)\n",
    "ax1.legend(frameon=False, loc='upper right')\n",
    "ax2.legend(frameon=False, loc='upper right')\n",
    "ax1.invert_xaxis()\n",
    "ax2.invert_xaxis()\n",
    "figure1.tight_layout()\n",
    "figure2.tight_layout()\n",
    "if PLOT == True:\n",
    "    figure1.savefig(f'plots/fig_gain_update_rate', dpi=600)\n",
    "    figure2.savefig(f'plots/fig_load_update_rate', dpi=600)\n",
    "figure1.show()\n",
    "figure2.show()\n",
    "\n",
    "\n",
    "\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Single Error Threshold Plot\n",
    "\n",
    "import matplotlib.ticker as mtick\n",
    "from scipy.interpolate import make_interp_spline\n",
    "\n",
    "PLOT = False\n",
    "\n",
    "# Daten aus .csv laden\n",
    "data_error_threshold = np.loadtxt('threshold_evaluation/error_threshold_breathing.csv', delimiter=\";\", skiprows=1)\n",
    "\n",
    "# Daten laden\n",
    "x = data_error_threshold[:, 0]\n",
    "error_gain = data_error_threshold[:, 2]\n",
    "error_cycles = data_error_threshold[:, 6]\n",
    "error_load = data_error_threshold[:, 7]\n",
    "error_cycles_new = data_error_threshold[:, 9]\n",
    "error_load_new = data_error_threshold[:, 10]\n",
    "\n",
    "# Sortieren\n",
    "idx = np.argsort(x)\n",
    "x = x[idx]\n",
    "error_gain = error_gain[idx]\n",
    "error_cycles = error_cycles[idx]\n",
    "error_load = error_load[idx]\n",
    "error_cycles_new = error_cycles_new[idx]\n",
    "error_load_new = error_load_new[idx]\n",
    "# Smoothing\n",
    "x_smooth = np.linspace(x.min(), x.max(), 300)\n",
    "\n",
    "gain_smooth = make_interp_spline(x, error_gain)(x_smooth)\n",
    "cycles_smooth = make_interp_spline(x, error_cycles)(x_smooth)\n",
    "load_smooth = make_interp_spline(x, error_load)(x_smooth)\n",
    "cycles_smooth_new = make_interp_spline(x, error_cycles_new)(x_smooth)\n",
    "load_smooth_new = make_interp_spline(x, error_load_new)(x_smooth)\n",
    "\n",
    "diff_smooth = np.abs(gain_smooth - cycles_smooth)\n",
    "idx_max = np.argmax(diff_smooth)\n",
    "x_max = x_smooth[idx_max]\n",
    "y1_max = gain_smooth[idx_max]\n",
    "y2_max = cycles_smooth[idx_max]\n",
    "\n",
    "# Plot\n",
    "figure1, ax1 = plt.subplots(figsize=(15, 7))\n",
    "ax1.plot(x_smooth, gain_smooth, linestyle='--', color='indianred', linewidth=2, alpha=0.9, label='SNR-Gain')\n",
    "ax1.plot(x_smooth, cycles_smooth, linestyle='-.', color='skyblue', linewidth=2, alpha=0.9, label='Cycles/Sample')\n",
    "ax1.plot(x_smooth, load_smooth, linestyle=':', color='forestgreen', linewidth=2, alpha=0.9, label='DSP Load')\n",
    "ax1.plot([x_max, x_max], [y1_max, y2_max], color='black', linestyle=':', linewidth=2)\n",
    "\n",
    "ax1.scatter(x, error_gain, color='indianred', s=40)\n",
    "ax1.scatter(x, error_cycles, color='skyblue', s=40)\n",
    "ax1.scatter(x, error_load, color='forestgreen', s=40)\n",
    "\n",
    "figure2, ax2 = plt.subplots(figsize=(15, 7))\n",
    "ax2.plot(x_smooth, gain_smooth, linestyle='--', color='indianred', linewidth=2, alpha=0.9, label='SNR-Gain')\n",
    "ax2.plot(x_smooth, cycles_smooth, linestyle='-.', color='skyblue', linewidth=2, alpha=0.3)\n",
    "ax2.plot(x_smooth, load_smooth, linestyle=':', color='forestgreen', linewidth=2, alpha=0.3)\n",
    "ax2.plot(x_smooth, cycles_smooth_new, linestyle='-', color='skyblue', linewidth=2, alpha=0.9, label='Cycles/Sample (New)')\n",
    "ax2.plot(x_smooth, load_smooth_new, linestyle='-', color='forestgreen', linewidth=2, alpha=0.9, label='DSP Load (New)')\n",
    "\n",
    "\n",
    "ax2.scatter(x, error_gain, color='indianred', s=40)\n",
    "ax2.scatter(x, error_cycles, color='skyblue', s=40, alpha=0.3)\n",
    "ax2.scatter(x, error_load, color='forestgreen', s=40, alpha=0.3)\n",
    "ax2.scatter(x, error_cycles_new, color='skyblue', s=40,)\n",
    "ax2.scatter(x, error_load_new, color='forestgreen', s=40)\n",
    "\n",
    "ax1.text(x_max, (y1_max + y2_max)/2+0.21,\n",
    "         f'Max. offset at threshold {x_max:.2f}',\n",
    "         fontsize=20,\n",
    "         ha='left')\n",
    "\n",
    "plt.rcParams.update({\n",
    "    \"text.usetex\": True,\n",
    "    \"font.family\": \"serif\",\n",
    "    'font.size': 16,          # Standardtext\n",
    "    'axes.labelsize': 30,     # Achsenbeschriftungen\n",
    "    'xtick.labelsize': 25,    # Tick-Beschriftungen\n",
    "    'ytick.labelsize': 25,\n",
    "    'legend.fontsize': 25     # Legende\n",
    "})\n",
    "\n",
    "ax1.set_xlabel(\"Error Threshold\")\n",
    "ax1.set_ylabel(\"Relative Performance\")\n",
    "ax2.set_xlabel(\"Error Threshold\")\n",
    "ax2.set_ylabel(\"Relative Performance\")\n",
    "ax1.grid(True, linestyle='-.', alpha=0.4)\n",
    "ax2.grid(True, linestyle='-.', alpha=0.4)\n",
    "#Spines auf ganzen Plot anwenden\n",
    "ax1.yaxis.set_major_formatter(mtick.PercentFormatter(1.0))\n",
    "ax2.yaxis.set_major_formatter(mtick.PercentFormatter(1.0))\n",
    "ax1.spines['top'].set_visible(False)\n",
    "ax1.spines['right'].set_visible(False)\n",
    "ax2.spines['top'].set_visible(False)\n",
    "ax2.spines['right'].set_visible(False)\n",
    "ax1.legend(frameon=False, loc='upper right')\n",
    "ax2.legend(frameon=False, loc='upper right')\n",
    "figure1.tight_layout()\n",
    "figure2.tight_layout()\n",
    "if PLOT == True:\n",
    "    figure1.savefig(f'plots/fig_snr_error_threshold', dpi=600)\n",
    "    figure2.savefig(f'plots/fig_snr_error_threshold_new', dpi=600)\n",
    "figure1.show()\n",
    "figure2.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "#Multi Error Threshold Plot\n",
    "\n",
    "import matplotlib.ticker as mtick\n",
    "from scipy.interpolate import make_interp_spline\n",
    "\n",
    "PLOT = False\n",
    "\n",
    "# Daten aus .csv laden\n",
    "error_threshold_breathing = np.loadtxt('threshold_evaluation/error_threshold_breathing.csv', delimiter=\";\", skiprows=1)\n",
    "error_threshold_chewing = np.loadtxt('threshold_evaluation/error_threshold_chewing.csv', delimiter=\";\", skiprows=1)\n",
    "error_threshold_coughing = np.loadtxt('threshold_evaluation/error_threshold_coughing.csv', delimiter=\";\", skiprows=1)\n",
    "error_threshold_drinking = np.loadtxt('threshold_evaluation/error_threshold_drinking.csv', delimiter=\";\", skiprows=1)\n",
    "error_threshold_scratching = np.loadtxt('threshold_evaluation/error_threshold_scratching.csv', delimiter=\";\", skiprows=1)\n",
    "\n",
    "# Daten laden\n",
    "x = error_threshold_breathing[:, 0]\n",
    "error_gain_breathing = error_threshold_breathing[:, 2]\n",
    "error_cycles_breathing = error_threshold_breathing[:, 6]\n",
    "error_load_breathing = error_threshold_breathing[:, 7]\n",
    "error_gain_chewing = error_threshold_chewing[:, 2]\n",
    "error_cycles_chewing = error_threshold_chewing[:, 6]\n",
    "error_load_chewing = error_threshold_chewing[:, 7]\n",
    "error_gain_coughing = error_threshold_coughing[:, 2]\n",
    "error_cycles_coughing = error_threshold_coughing[:, 6]\n",
    "error_load_coughing = error_threshold_coughing[:, 7]\n",
    "error_gain_drinking = error_threshold_drinking[:, 2]\n",
    "error_cycles_drinking = error_threshold_drinking[:, 6]\n",
    "error_load_drinking = error_threshold_drinking[:, 7]\n",
    "error_gain_scratching = error_threshold_scratching[:, 2]\n",
    "error_cycles_scratching = error_threshold_scratching[:, 6]  \n",
    "error_load_scratching = error_threshold_scratching[:, 7] \n",
    "\n",
    "# Sortieren\n",
    "idx = np.argsort(x)\n",
    "x = x[idx]\n",
    "error_gain_breathing = error_gain_breathing[idx]\n",
    "error_cycles_breathing = error_cycles_breathing[idx]\n",
    "error_load_breathing = error_load_breathing[idx]\n",
    "error_gain_chewing = error_gain_chewing[idx]\n",
    "error_cycles_chewing = error_cycles_chewing[idx]\n",
    "error_load_chewing = error_load_chewing[idx]\n",
    "error_gain_coughing = error_gain_coughing[idx]\n",
    "error_cycles_coughing = error_cycles_coughing[idx]\n",
    "error_load_coughing = error_load_coughing[idx]\n",
    "error_gain_drinking = error_gain_drinking[idx]\n",
    "error_cycles_drinking = error_cycles_drinking[idx]\n",
    "error_load_drinking = error_load_drinking[idx]\n",
    "error_gain_scratching = error_gain_scratching[idx]\n",
    "error_cycles_scratching = error_cycles_scratching[idx]\n",
    "error_load_scratching = error_load_scratching[idx]\n",
    "\n",
    "# Smoothing\n",
    "x_smooth = np.linspace(x.min(), x.max(), 300)\n",
    "\n",
    "gain_smooth_breathing = make_interp_spline(x, error_gain_breathing)(x_smooth)\n",
    "cycles_smooth_breathing = make_interp_spline(x, error_cycles_breathing)(x_smooth)\n",
    "load_smooth_breathing = make_interp_spline(x, error_load_breathing)(x_smooth)\n",
    "gain_smooth_chewing = make_interp_spline(x, error_gain_chewing)(x_smooth)\n",
    "cycles_smooth_chewing = make_interp_spline(x, error_cycles_chewing)(x_smooth)\n",
    "load_smooth_chewing = make_interp_spline(x, error_load_chewing)(x_smooth)\n",
    "gain_smooth_coughing = make_interp_spline(x, error_gain_coughing)(x_smooth)\n",
    "cycles_smooth_coughing = make_interp_spline(x, error_cycles_coughing)(x_smooth)\n",
    "load_smooth_coughing = make_interp_spline(x, error_load_coughing)(x_smooth)\n",
    "gain_smooth_drinking = make_interp_spline(x, error_gain_drinking)(x_smooth)\n",
    "cycles_smooth_drinking = make_interp_spline(x, error_cycles_drinking)(x_smooth)\n",
    "load_smooth_drinking = make_interp_spline(x, error_load_drinking)(x_smooth)\n",
    "gain_smooth_scratching = make_interp_spline(x, error_gain_scratching)(x_smooth)\n",
    "cycles_smooth_scratching = make_interp_spline(x, error_cycles_scratching)(x_smooth)\n",
    "load_smooth_scratching = make_interp_spline(x, error_load_scratching)(x_smooth)\n",
    "\n",
    "diff_smooth_breathing = gain_smooth_breathing - cycles_smooth_breathing\n",
    "diff_smooth_chewing = gain_smooth_chewing - cycles_smooth_chewing\n",
    "diff_smooth_coughing = gain_smooth_coughing - cycles_smooth_coughing\n",
    "diff_smooth_drinking = gain_smooth_drinking - cycles_smooth_drinking\n",
    "diff_smooth_scratching = gain_smooth_scratching - cycles_smooth_scratching\n",
    "\n",
    "# Alle Kurven in ein Array stapeln\n",
    "stack_difference = np.vstack([\n",
    "    diff_smooth_breathing,\n",
    "    diff_smooth_chewing,\n",
    "    diff_smooth_coughing,\n",
    "    diff_smooth_drinking,\n",
    "    diff_smooth_scratching\n",
    "])\n",
    "\n",
    "# Alle Kurven in ein Array stapeln\n",
    "stack_load = np.vstack([\n",
    "    load_smooth_breathing,\n",
    "    load_smooth_chewing,\n",
    "    load_smooth_coughing,\n",
    "    load_smooth_drinking,\n",
    "    load_smooth_scratching\n",
    "])\n",
    "\n",
    "# Punktweiser Mittelwert\n",
    "mean_gain = np.mean(stack_difference, axis=0)\n",
    "mean_load = np.mean(stack_load, axis=0)   \n",
    "\n",
    "idx_max_gain = np.argmax(mean_gain)\n",
    "x_max_gain = x_smooth[idx_max_gain]\n",
    "y_max_gain = mean_gain[idx_max_gain]\n",
    "x_max_load = x_smooth[idx_max_gain]\n",
    "y_max_load = mean_load[idx_max_gain]\n",
    "\n",
    "\n",
    "# Plot\n",
    "figure1, ax1 = plt.subplots(figsize=(15, 7))\n",
    "ax1.plot(x_smooth, diff_smooth_breathing, linestyle='--', color='indianred', linewidth=1.5, alpha=0.7, label='Breathing Noise')\n",
    "ax1.plot(x_smooth, diff_smooth_chewing, linestyle='-.', color='skyblue', linewidth=1.5, alpha=0.7, label='Chewing Noise')\n",
    "ax1.plot(x_smooth, diff_smooth_coughing, linestyle=':', color='forestgreen', linewidth=1.5, alpha=0.7, label='Coughing Noise')\n",
    "ax1.plot(x_smooth, diff_smooth_drinking, linestyle='--', color='darkorange', linewidth=1.5, alpha=0.7, label='Drinking Noise')\n",
    "ax1.plot(x_smooth, diff_smooth_scratching, linestyle='-.', color='darkorchid', linewidth=1.5, alpha=0.7, label='Scratching Noise')\n",
    "ax1.plot(x_smooth, mean_gain, linestyle='--', color='red', linewidth=2.5, alpha=1, label='Mean Performance Gain')\n",
    "ax1.plot([x_max_gain, x_max_gain], [y_max_gain, 0], color='black', linestyle=':', linewidth=2)\n",
    "\n",
    "ax1.text(x_max_gain, y_max_gain+0.01,\n",
    "         f'{y_max_gain*100:.1f} \\% mean performance gain at error threshold {x_max_gain:.2f}',\n",
    "         fontsize=20,\n",
    "         ha='left')\n",
    "\n",
    "figure2, ax2 = plt.subplots(figsize=(15, 7))\n",
    "ax2.plot(x_smooth, load_smooth_breathing, linestyle='--', color='indianred', linewidth=1.5, alpha=0.7, label='Breathing Noise')\n",
    "ax2.plot(x_smooth, load_smooth_chewing, linestyle='-.', color='skyblue', linewidth=1.5, alpha=0.7, label='Chewing Noise')\n",
    "ax2.plot(x_smooth, load_smooth_coughing, linestyle=':', color='forestgreen', linewidth=1.5, alpha=0.7, label='Coughing Noise')\n",
    "ax2.plot(x_smooth, load_smooth_drinking, linestyle='--', color='darkorange', linewidth=1.5, alpha=0.7, label='Drinking Noise')\n",
    "ax2.plot(x_smooth, load_smooth_scratching, linestyle='-.', color='darkorchid', linewidth=1.5, alpha=0.7, label='Scratching Noise')\n",
    "ax2.plot(x_smooth, mean_load, linestyle='--', color='blue', linewidth=2.5, alpha=1, label='Mean DSP Load')\n",
    "ax2.plot([x_max_load, x_max_load], [y_max_load, 0], color='black', linestyle=':', linewidth=2)\n",
    "\n",
    "ax2.text(x_max_load, y_max_load+0.01,\n",
    "         f'{y_max_load*100:.1f} \\% mean DSP load at error threshold {x_max_load:.2f}',\n",
    "         fontsize=20,\n",
    "         ha='left')\n",
    "\n",
    "plt.rcParams.update({\n",
    "    \"text.usetex\": True,\n",
    "    \"font.family\": \"serif\",\n",
    "    'font.size': 16,          # Standardtext\n",
    "    'axes.labelsize': 30,     # Achsenbeschriftungen\n",
    "    'xtick.labelsize': 25,    # Tick-Beschriftungen\n",
    "    'ytick.labelsize': 25,\n",
    "    'legend.fontsize': 25     # Legende\n",
    "})\n",
    "\n",
    "ax1.set_xlabel(\"Error Threshold\")\n",
    "ax2.set_xlabel(\"Error Threshold\")\n",
    "ax1.set_ylabel(\"Performance Gain\")\n",
    "ax2.set_ylabel(\"DSP Load\")\n",
    "ax1.grid(True, linestyle='-.', alpha=0.4)\n",
    "ax2.grid(True, linestyle='-.', alpha=0.4)\n",
    "ax1.set_ylim(0, 1)\n",
    "ax2.set_ylim(0, 0.7)\n",
    "#Spines auf ganzen Plot anwenden\n",
    "ax1.yaxis.set_major_formatter(mtick.PercentFormatter(1.0))\n",
    "ax2.yaxis.set_major_formatter(mtick.PercentFormatter(1.0))\n",
    "ax1.spines['top'].set_visible(False)\n",
    "ax2.spines['top'].set_visible(False)\n",
    "ax1.spines['right'].set_visible(False)\n",
    "ax2.spines['right'].set_visible(False)\n",
    "ax1.legend(frameon=False, loc='upper right')\n",
    "ax2.legend(frameon=False, loc='upper right')\n",
    "figure1.tight_layout()\n",
    "figure2.tight_layout()\n",
    "if PLOT == True:\n",
    "    figure1.savefig(f'plots/fig_gain_error_threshold', dpi=600)\n",
    "    figure2.savefig(f'plots/fig_load_error_threshold', dpi=600)\n",
    "figure1.show()\n",
    "figure2.show()\n"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv (3.9.13)",
   "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
}
