diff --git a/Makefile b/Makefile
index eea5e2513a58da05708cb1dd96667da16b2f6658..d73e3a4eeae6873a2632eb2e2af59fdfe57ae525 100644
--- a/Makefile
+++ b/Makefile
@@ -121,15 +121,16 @@ LDSCRIPT= $(STARTUPLD)/STM32F411xE.ld
 
 # C sources that can be compiled in ARM or THUMB mode depending on the global
 # setting.
-CSRC = $(ALLCSRC)                                  \
-         $(SRCDIR)/crc32.c                         \
-         $(SRCDIR)/benchmarks.c                    \
-         $(SRCDIR)/benchmarks/memory.c             \
-         $(SRCDIR)/benchmarks/blind_abstraction.c  \
-         $(SRCDIR)/main.c                          \
-	 $(SRCDIR)/random.c                        \
-	 $(SRCDIR)/serial.c                        \
-	 $(SRCDIR)/tests.c                         \
+CSRC = $(ALLCSRC)                                     \
+         $(SRCDIR)/crc32.c                            \
+         $(SRCDIR)/benchmarks.c                       \
+         $(SRCDIR)/benchmarks/memory.c                \
+         $(SRCDIR)/benchmarks/blind_abstraction.c     \
+         $(SRCDIR)/benchmarks/observer_abstraction.c  \
+         $(SRCDIR)/main.c                             \
+	 $(SRCDIR)/random.c                           \
+	 $(SRCDIR)/serial.c                           \
+	 $(SRCDIR)/tests.c                            \
 	 $(SRCDIR)/usb.c
 
 # C++ sources that can be compiled in ARM or THUMB mode depending on the global
diff --git a/scripts/benchmarks/observer_abstraction.py b/scripts/benchmarks/observer_abstraction.py
new file mode 100644
index 0000000000000000000000000000000000000000..e0780fbaaea88a5168bc61cf152d39ae9c4be397
--- /dev/null
+++ b/scripts/benchmarks/observer_abstraction.py
@@ -0,0 +1,82 @@
+## This file is part of the execution-time evaluation for the qronos observer abstractions.
+## Copyright (C) 2022-2023  Tim Rheinfels  <tim.rheinfels@fau.de>
+## See https://gitlab.cs.fau.de/qronos-state-abstractions/execution-time
+##
+## This program is free software: you can redistribute it and/or modify
+## it under the terms of the GNU General Public License as published by
+## the Free Software Foundation, either version 3 of the License, or
+## (at your option) any later version.
+##
+## This program is distributed in the hope that it will be useful,
+## but WITHOUT ANY WARRANTY; without even the implied warranty of
+## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+## GNU General Public License for more details.
+##
+## You should have received a copy of the GNU General Public License
+## along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+###
+###  @file  benchmarks/observer_abstraction.py
+###
+###  @brief  Provides @p observer_abstraction.ObserverAbstraction, the @p benchmark.Benchmark
+###          subclass for the observer abstraction benchmark
+###
+###  @author  Tim Rheinfels  <tim.rheinfels@fau.de>
+###
+
+import numpy as np
+import json
+
+from benchmark import Benchmark
+from data import decode
+
+###
+###  @brief  Encapsulates the observer abstraction execution time benchmark
+###
+class ObserverAbstraction(Benchmark):
+
+    ###
+    ###  @brief  Validates the computations performed on the STM32 by running them
+    ###          again in numpy and comparing the results.
+    ###
+    ###  @see  benchmark.Benchmark._validate for parameters
+    ###
+    def _validate(self, benchmark, key):
+        n_y = int(key)
+
+        for run in benchmark['tests']:
+            v = decode(run['setup']['v'])
+            rho = decode(run['setup']['rho'])
+            beta = decode(run['setup']['beta'])
+
+            assert(isinstance(v, float))
+            assert(isinstance(rho, float))
+            assert(isinstance(beta, float))
+
+            M_sqrt_T = decode(run['setup']['M_sqrt_T'])
+            y = decode(run['setup']['y'])
+
+            if n_y > 0:
+                assert(M_sqrt_T.shape == (n_y, n_y))
+                for i in range(n_y):
+                    for j in range(i):
+                        assert(np.isclose(M_sqrt_T[i, j], 0.0))
+                assert(np.all(np.linalg.eigvalsh(M_sqrt_T.T @ M_sqrt_T) > 0.0))
+            else:
+                assert(M_sqrt_T.size == 0)
+
+            assert(y.shape == (n_y,))
+
+            for i in range(benchmark['repetition_count']):
+                v = rho * v + beta + np.linalg.norm(M_sqrt_T @ y)
+
+            v_p = decode(run['teardown']['v_p'])
+            assert(np.isclose(v, v_p))
+
+    ###
+    ###  @brief  Constructor
+    ###
+    ###  @see  benchmark.Benchmark.__init__ for parameters
+    ###
+    def __init__(self, data):
+        Benchmark.__init__(self, data, 'Observer Abstraction', r'observer_abstraction_([0-9]+)', lambda m: m.group(1))
diff --git a/src/benchmarks.c b/src/benchmarks.c
index b9447988d7864c972dc411096edd2335a1632102..9fa7d76dfcbd616ac08964408977fac0b90181cc 100644
--- a/src/benchmarks.c
+++ b/src/benchmarks.c
@@ -28,6 +28,7 @@
 #include <benchmarks/campaign.h>
 
 #include <benchmarks/blind_abstraction.h>
+#include <benchmarks/observer_abstraction.h>
 
 void benchmarks_run(void)
 {
@@ -41,5 +42,6 @@ void benchmarks_run(void)
 
     // Comparative execution time benchmarks
     benchmarks_run_blind_abstraction();
+    benchmarks_run_observer_abstraction();
 
 }
diff --git a/src/benchmarks/memory.c b/src/benchmarks/memory.c
index c8d2ef42a601d77de858e1cd74b2ee2fae60813f..84a95f59df5d4f06436cb1fb0df4acbed88c702b 100644
--- a/src/benchmarks/memory.c
+++ b/src/benchmarks/memory.c
@@ -29,6 +29,7 @@
 #include <string.h>
 
 #include <benchmarks/blind_abstraction.h>
+#include <benchmarks/observer_abstraction.h>
 
 ///
 ///  @brief  Size of the padding in bytes used for checking memory violations
@@ -49,7 +50,8 @@
 ///  @brief  Actual benchmark memory
 ///
 static float work[2u * PADDING
-    + BENCHMARKS_BLIND_ABSTRACTION_WORK_SIZE
+    + MAX(BENCHMARKS_BLIND_ABSTRACTION_WORK_SIZE,
+          BENCHMARKS_OBSERVER_ABSTRACTION_WORK_SIZE)
 ];
 
 float * const benchmarks_memory = work + PADDING;
diff --git a/src/benchmarks/observer_abstraction.c b/src/benchmarks/observer_abstraction.c
new file mode 100644
index 0000000000000000000000000000000000000000..c04ecc0b5e982ce036699a9c2ce9979aa468006c
--- /dev/null
+++ b/src/benchmarks/observer_abstraction.c
@@ -0,0 +1,153 @@
+// This file is part of the execution-time evaluation for the qronos observer abstractions.
+// Copyright (C) 2022-2023  Tim Rheinfels  <tim.rheinfels@fau.de>
+// See https://gitlab.cs.fau.de/qronos-state-abstractions/execution-time
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+///
+///  @file  benchmarks/observer_abstraction.c
+///
+///  @brief  Provides the implementation of the observer abstraction execution time benchmark
+///
+///  @author  Tim Rheinfels  <tim.rheinfels@fau.de>
+///
+
+#include "observer_abstraction.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <linalg.h>
+#include <random.h>
+#include <serial.h>
+#include <benchmarks/campaign.h>
+
+static float *M_sqrt_T = NULL;  ///<  Triangular matrix chol(LtPL) for the measurement vector's norm
+static float *y = NULL;         ///<  Measurement vector
+
+///
+///  @brief  Configures the memory layout and randomly initializes the data
+///
+static void setup_matrices(size_t n_y)
+{
+    M_sqrt_T = benchmarks_memory;
+    y = M_sqrt_T + n_y*n_y;
+
+    random_matrix_cholesky(M_sqrt_T, n_y);
+    random_matrix(y, n_y, 1u);
+
+    serial_print_matrix("M_sqrt_T", M_sqrt_T, n_y, n_y);
+    serial_print_vector("y", y, n_y);
+}
+
+void benchmarks_run_observer_abstraction(void)
+{
+    volatile float v;
+    float rho;
+    float beta;
+
+    #define SETUP(N_Y) {                                                                                                          \
+            v = random_float();                                                                                                   \
+            rho = random_float();                                                                                                 \
+            beta = random_float();                                                                                                \
+            serial_printf("\"v\": %u, \"rho\": %u, \"beta\": %u,\n", serial_encode(v), serial_encode(rho), serial_encode(beta));  \
+            setup_matrices(N_Y);                                                                                                  \
+    }
+
+    #define TEARDOWN {                                   \
+            serial_printf("\"v_p\": %u,\n", serial_encode(v));  \
+    }
+
+    #define CAMPAIGN(N_Y) {                                                              \
+            BENCHMARKS_CAMPAIGN("observer_abstraction_" #N_Y,                            \
+                                    {                                                    \
+                                        float accu = 0.0f;                               \
+                                        for(size_t i = 0u; i < N_Y; ++i) {               \
+                                            float accu_row = 0.0f;                       \
+                                            for(size_t j = i; j < N_Y; ++j) {            \
+                                                accu_row += M_sqrt_T[(i*N_Y)+j] * y[j];  \
+                                            }                                            \
+                                            accu += accu_row * accu_row;                 \
+                                        }                                                \
+                                        v = rho*v + beta + sqrtf(accu);                  \
+                                    },                                                   \
+                                    SETUP(N_Y),                                          \
+                                    TEARDOWN,                                            \
+                                    10u,                                                 \
+                                    10u                                                  \
+                                )                                                        \
+        }
+
+    CAMPAIGN(1);
+    CAMPAIGN(2);
+    CAMPAIGN(3);
+    CAMPAIGN(4);
+    CAMPAIGN(5);
+    CAMPAIGN(6);
+    CAMPAIGN(7);
+    CAMPAIGN(8);
+    CAMPAIGN(9);
+    CAMPAIGN(10);
+    CAMPAIGN(11);
+    CAMPAIGN(12);
+    CAMPAIGN(13);
+    CAMPAIGN(14);
+    CAMPAIGN(15);
+    CAMPAIGN(16);
+    CAMPAIGN(17);
+    CAMPAIGN(18);
+    CAMPAIGN(19);
+    CAMPAIGN(20);
+    CAMPAIGN(21);
+    CAMPAIGN(22);
+    CAMPAIGN(23);
+    CAMPAIGN(24);
+    CAMPAIGN(25);
+    CAMPAIGN(26);
+    CAMPAIGN(27);
+    CAMPAIGN(28);
+    CAMPAIGN(29);
+    CAMPAIGN(30);
+    CAMPAIGN(31);
+    CAMPAIGN(32);
+    CAMPAIGN(33);
+    CAMPAIGN(34);
+    CAMPAIGN(35);
+    CAMPAIGN(36);
+    CAMPAIGN(37);
+    CAMPAIGN(38);
+    CAMPAIGN(39);
+    CAMPAIGN(40);
+    CAMPAIGN(41);
+    CAMPAIGN(42);
+    CAMPAIGN(43);
+    CAMPAIGN(44);
+    CAMPAIGN(45);
+    CAMPAIGN(46);
+    CAMPAIGN(47);
+    CAMPAIGN(48);
+    CAMPAIGN(49);
+    CAMPAIGN(50);
+    CAMPAIGN(51);
+    CAMPAIGN(52);
+    CAMPAIGN(53);
+    CAMPAIGN(54);
+    CAMPAIGN(55);
+    CAMPAIGN(56);
+    CAMPAIGN(57);
+    CAMPAIGN(58);
+    CAMPAIGN(59);
+    CAMPAIGN(60);
+
+}
diff --git a/src/benchmarks/observer_abstraction.h b/src/benchmarks/observer_abstraction.h
new file mode 100644
index 0000000000000000000000000000000000000000..1a38d7687459f03b21af0b2b2c375d67b6f887c7
--- /dev/null
+++ b/src/benchmarks/observer_abstraction.h
@@ -0,0 +1,44 @@
+// This file is part of the execution-time evaluation for the qronos observer abstractions.
+// Copyright (C) 2022-2023  Tim Rheinfels  <tim.rheinfels@fau.de>
+// See https://gitlab.cs.fau.de/qronos-state-abstractions/execution-time
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+///
+///  @file  benchmarks/observer_abstraction.h
+///
+///  @brief  Provides the interface for the observer abstraction execution time benchmark
+///
+///  @author  Tim Rheinfels  <tim.rheinfels@fau.de>
+///
+
+#ifndef BENCHMARKS_OBSERVERABSTRACTION_H
+#define BENCHMARKS_OBSERVERABSTRACTION_H
+
+#include <benchmarks/memory.h>
+
+///
+///  @brief  Memory required for running the observer abstraction execution time benchmark
+///
+#define BENCHMARKS_OBSERVER_ABSTRACTION_WORK_SIZE (N_Y_MAX * N_Y_MAX + N_Y_MAX)
+
+///
+///  @brief  Runs the observer abstraction execution time benchmark
+///
+///  This function measures the execution time needed in order to update the
+///  blind abstraction proposed in @cite ECRTS23-Rheinfels by equation (8a).
+///
+void benchmarks_run_observer_abstraction(void);
+
+#endif // BENCHMARKS_OBSERVERABSTRACTION_H