aboutsummaryrefslogtreecommitdiff
path: root/FanController/fan_controller/median.c
blob: 03f16d4810ffc33faae56d4543dbda1b64d85a05 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
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;
}