aboutsummaryrefslogtreecommitdiff
path: root/FanController/fan_controller/median.c
diff options
context:
space:
mode:
Diffstat (limited to 'FanController/fan_controller/median.c')
-rw-r--r--FanController/fan_controller/median.c131
1 files changed, 131 insertions, 0 deletions
diff --git a/FanController/fan_controller/median.c b/FanController/fan_controller/median.c
new file mode 100644
index 0000000..03f16d4
--- /dev/null
+++ b/FanController/fan_controller/median.c
@@ -0,0 +1,131 @@
+/* Autor: Ján Sučan <jan@jansucan.sk>
+ *
+ * Zdrojove kody, ich casti a subory z nich vzniknute priamo alebo nepriamo
+ * (objektove subory, Intel Hex, ...) prosim nepouzivajte komercne, ani ako
+ * sucast komercnych diel. Vsetky ostatne pripady pouzitia su dovolene.
+ *
+ * Please don't use the source codes, their parts and files created from them
+ * directly or indirectly, (object files, Intel Hex files, ...) for commercial
+ * purposes, not even as a part of commercial products. All other use cases
+ * are allowed.
+ */
+
+#include <string.h>
+
+#include <fan_controller/median.h>
+#include <fan_controller/error.h>
+
+static void median_delete_oldest_sample(median_buffer_t * const buf);
+
+/**
+ * @brief Vymazanie najstarsej vzorky z bufferu medianu.
+ *
+ * @param buf Ukazovatel na buffer medianu.
+ */
+void
+median_delete_oldest_sample(median_buffer_t * const buf)
+{
+ // Ziskat index najstarsieho prvku v poli buf->samples
+ const uint8_t oldest_index = buf->age[0];
+
+ if (oldest_index >= buf->number_of_elements) {
+ error();
+ }
+ // Pocet prvkov, ktore sa budu presuvat na prazdne miesto po zmazanom prvku
+ const uint8_t samples_to_move = buf->number_of_elements - oldest_index - 1;
+ // Ak je co presuvat, presunie sa
+ if (samples_to_move > 0) {
+ memmove(buf->samples + oldest_index,
+ buf->samples + oldest_index + 1,
+ samples_to_move * sizeof(buf->samples[0]));
+ }
+
+ // Zmensi sa pocet ulozenych prvkov
+ --(buf->number_of_elements);
+
+ // Aktualizovat pozicie presunutych prvkov vo FIFO bufferi
+ for (uint8_t i = oldest_index; i < (oldest_index + samples_to_move); ++i) {
+ // Prvky sa posunuli k nizsim indexom
+ --(buf->age[(buf->samples[i]).age_index]);
+ }
+
+ // Treba aktualizovat FIFO indexov do buf->samples. Vyhodi sa najstarsi prvok
+ memmove(buf->age,
+ buf->age + 1,
+ buf->number_of_elements * sizeof(buf->samples[0]));
+
+ // Aktualizovat pozicie presunutych prvkov v bufferi vzoriek
+ for (uint8_t i = 0; i < buf->number_of_elements; ++i) {
+ // Prvky sa posunuli k nizsim indexom
+ --(buf->samples[buf->age[i]].age_index);
+ }
+}
+
+/**
+ * @brief Inicializacia bufferu medianu.
+ *
+ * Buffer medianu sa musi vzdy inicializovat pred prvym pouzitim.
+ *
+ * @param buf Ukazovatel na buffer medianu.
+ * @param capacity Kapacita bufferu, tj. max. pocet vzoriek z ktorych sa bude pocitat median.
+ */
+void
+median_init_buffer(median_buffer_t * const buf, uint8_t capacity)
+{
+ if ((capacity < MEDIAN_MIN_SAMPLES) ||(capacity > MEDIAN_MAX_SAMPLES)) {
+ error();
+ }
+ buf->number_of_elements = 0;
+ buf->capacity = capacity;
+}
+
+/**
+ * @brief Vlozenie prvku do bufferu pre median.
+ *
+ * @param buf Ukazovatel na buffer medianu.
+ * @param sample Hodnota pre ulozenie do bufferu medianu.
+ */
+void
+median_save_sample(median_buffer_t * const buf, uint16_t sample)
+{
+ if (buf->number_of_elements >= buf->capacity) {
+ // Buffer je plny, vymaze sa najtarsi prvok
+ median_delete_oldest_sample(buf);
+ }
+
+ // Buffer nie je plny, vzorka sa ulozi na koniec bufferu
+ buf->samples[buf->number_of_elements].value = sample;
+ buf->samples[buf->number_of_elements].age_index = buf->number_of_elements;
+ buf->age[buf->number_of_elements] = buf->number_of_elements;
+
+ // Vzorka sa zaradi na spravne miesto
+ for (uint8_t j = buf->number_of_elements, i = j - 1; j > 0; --i, --j) {
+ if (buf->samples[j].value < buf->samples[i].value) {
+ // Aktualizovat casove znacky
+ // Vzorka na pozicii i pojde na vyssi index
+ ++(buf->age[buf->samples[i].age_index]);
+ // Vzorka na pozicii j pojde na nizsi index
+ --(buf->age[buf->samples[j].age_index]);
+ // Vymenit vzorky
+ median_sample_t t;
+ t = buf->samples[j];
+ buf->samples[j] = buf->samples[i];
+ buf->samples[i] = t;
+ }
+ }
+
+ // Aktualizovat pocet ulozenych prvkov
+ ++(buf->number_of_elements);
+}
+
+/**
+ * @brief Ziskanie medianu z bufferu.
+ *
+ * @param buf Ukazovatel na buffer medianu.
+ * @return Median z doteraz ulozenych hodnot.
+ */
+uint16_t
+median_get(const median_buffer_t * const buf)
+{
+ return (buf->samples[buf->number_of_elements / 2]).value;
+} \ No newline at end of file