Last active
August 11, 2023 18:47
-
-
Save lbfalvy/64f635db3194432630d219d92e2e4e45 to your computer and use it in GitHub Desktop.
Solution for the coursework in COM3023 "Internet of Things" at the University of Surrey. I have no idea if the transfer function is correct
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "contiki.h" | |
#include "dev/light-sensor.h" | |
#include <stdio.h> | |
// buffer size | |
// this has to be comptime constant | |
#define BUFSIZE 12 | |
// threshold for aggregating the whole buffer into one value | |
static double FULL_AGG_THRESH = 100.0; | |
// threshold for aggregating every 4 samples | |
static double AGG_4_THRESH = 600.0; | |
// The meaning of the above values was not specified in the coursework brief | |
// with respect to the variable buffer size, so I guessed. I had to guess | |
// a lot actually during these 3 years because no coursework brief in the | |
// entire course demonstrated the meaning of any task with more than one | |
// value of the other variable config options mandated by the same brief. | |
// Shallow imitation of the cross-language ubiquitous hard-crashing assert | |
void assert(int b, char* message) { | |
if (!b) { | |
printf("Assertion failed: %s\n", message); | |
exit(-1); | |
} | |
} | |
/* ================ Helpers ================ */ | |
// these are in math.h but I couldn't find how to edit CFLAGS | |
double fmin(double a, double b) { if(a < b){ return a; }else{ return b; }}; | |
double fmax(double a, double b) { if(a < b){ return b; }else{ return a; }}; | |
double sqrt(double x) { | |
if (x == 1) return 1; | |
if (x < 0) x = -x; | |
double lb = fmin(1.0, x); | |
double ub = fmax(1.0, x); | |
double eps = 0.001; | |
double guess, error; | |
do { | |
guess = (lb + ub) / 2; | |
double guess2 = guess * guess; | |
if (guess2 < x) { | |
lb = guess; | |
error = x / guess2; | |
} else { // x <= guess2 | |
ub = guess; | |
error = guess2 / x; | |
} | |
} while (eps < error - 1); | |
return guess; | |
} | |
// Find the number of decimal digits in a nonnegative integer | |
int oom(int x) { | |
assert(0 <= x, "oom only supports natural numbers"); | |
if (x == 0) return 1; | |
int ret = 0; | |
while (0 < x) { | |
x = x / 10; | |
ret++; | |
} | |
return ret; | |
} | |
// Find the n-th digit of a double. | |
// 0 is the 1s digit, positive indices move left of the decimal point | |
char nth_digit(double f, int digit) { | |
while (digit != 0) { // could also use pow | |
if (digit < 0) { f *= 10; digit++; } | |
else { f /= 10; digit--; } | |
} | |
assert(0 <= f, "nth_digit only supports positive numbers"); | |
return '0' + ((long)f % 10l); | |
} | |
// convert a floating point number to string. | |
// Return the leftover buffer | |
char* f2str(char* buffer, char* end, double f, int decimals) { | |
char* cur = buffer; | |
if (f == 0) { | |
*(cur++) = '0'; | |
if (cur < end) *cur = 0; | |
return cur; | |
} | |
if (f < 0) { | |
*(cur++) = '-'; | |
f = -f; | |
} | |
int i = oom(f) - 1; | |
while (0 <= i && cur < end) *(cur++) = nth_digit(f, i--); | |
assert(i == -1, "Overflowed buffer while writing double to string"); | |
if (decimals == 0 || ((double)(int)f == f)) { | |
*cur = 0; | |
return cur; | |
} | |
if (cur < end && 0 < decimals) *(cur++) = '.'; | |
while (-i < decimals && cur < end) *(cur++) = nth_digit(f, i--); | |
if (cur < end) *cur = 0; // cut buffer short if needed | |
while (*--cur == '0') *cur = 0; // erase trailing zeros | |
if (*--cur == '.') *cur = 0; // erase the dot if all decimals were zeros | |
return cur+1; // return cursor immediately after last failed test above | |
} | |
// Obtain light sensor data in lumen | |
double light_lx(void) { | |
double val2voltage = 1.5 / 4096.0; // mote characteristics | |
double voltage2current = 1.0/100000.0; // resistance | |
double current2lx = 0.625*1e6*1000.0; // see the datasheet | |
double transfer = val2voltage * voltage2current * current2lx; | |
double sensor_value = light_sensor.value(LIGHT_SENSOR_PHOTOSYNTHETIC); | |
return sensor_value * transfer; | |
} | |
// Algebraic mean | |
double fmean(int c, double* v) { | |
double sum = 0; int i = 0; | |
while (i < c) sum += v[i++]; | |
return sum / (double)c; | |
} | |
// Standard deviation | |
double fstddev(int c, double* v) { | |
double mean = fmean(c, v); | |
double sqsum = 0; int i = 0; | |
while (i < c) sqsum += pow(v[i++] - mean, 2); | |
return sqrt(sqsum / (double)c); | |
} | |
static char fstrbuf[32]; | |
// Deal with a full buffer | |
void process_data(double buffer[]) { | |
int i, agg = 1; | |
double dev = fstddev(BUFSIZE, buffer); | |
if (dev < FULL_AGG_THRESH) agg = BUFSIZE; | |
else if (dev < AGG_4_THRESH) agg = 4; | |
int reportc = BUFSIZE/agg; | |
double reportv[reportc]; | |
for (i = 0; i < reportc; i++) reportv[i] = fmean(agg, buffer+(i*agg)); | |
printf("B = ["); | |
for (i = 0; i < BUFSIZE - 1; i++) printf("%d, ", (int)buffer[i]); | |
printf("%d]\n", (int)buffer[BUFSIZE - 1]); | |
f2str(fstrbuf, fstrbuf+31, dev, 2); | |
printf("StdDev = %s\n", fstrbuf); | |
printf("Aggregation = %d-into-1\n", agg); | |
printf("X = ["); | |
for (i = 0; i < reportc; i++) { | |
f2str(fstrbuf, fstrbuf+31, reportv[i], 2); | |
printf("%s", fstrbuf); | |
if (i + 1 < reportc) printf(","); | |
} | |
printf("]\n"); | |
} | |
int i = 0; | |
double buffer[BUFSIZE]; | |
/*---------------------------------------------------------------------------*/ | |
PROCESS(hello_world_process, "Hello world process"); | |
AUTOSTART_PROCESSES(&hello_world_process); | |
/*---------------------------------------------------------------------------*/ | |
PROCESS_THREAD(hello_world_process, ev, data) | |
{ | |
static struct etimer timer; | |
PROCESS_BEGIN(); | |
etimer_set(&timer, CLOCK_CONF_SECOND/2); | |
SENSORS_ACTIVATE(light_sensor); | |
while(1) { | |
// this apparently declares a jump target, | |
// otherwise the buffer could be local state | |
PROCESS_WAIT_EVENT_UNTIL(ev=PROCESS_EVENT_TIMER); | |
buffer[i++] = light_lx(); | |
if (BUFSIZE <= i) { | |
i = 0; | |
process_data(buffer); | |
} | |
etimer_reset(&timer); | |
} | |
PROCESS_END(); | |
} | |
/*---------------------------------------------------------------------------*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment