diff --git a/Task-8/CircBuffer.h b/Task-8/CircBuffer.h index a7d330d..1b8eb2e 100644 --- a/Task-8/CircBuffer.h +++ b/Task-8/CircBuffer.h @@ -6,5 +6,5 @@ struct CircBuffer { } info; char padding[1024]; }; - double data[200]; + double data[8192]; }; \ No newline at end of file diff --git a/Task-8/funs.h b/Task-8/funs.h new file mode 100644 index 0000000..3fc4c68 --- /dev/null +++ b/Task-8/funs.h @@ -0,0 +1,28 @@ +// From https://github.com/veltzer/demos-linux +const long long NSEC_PER_SEC=1000000000; + +static inline unsigned long long timespec_diff_nano(struct timespec* x, struct timespec* y) { + return (x->tv_sec-y->tv_sec)*NSEC_PER_SEC+(x->tv_nsec-y->tv_nsec); +} + +static inline void timespec_sub(struct timespec* result, struct timespec* x, struct timespec* y) { + /* Perform the carry for the later subtraction by updating Y. */ + if (x->tv_nsec < y->tv_nsec) { + int nsec = (y->tv_nsec - x->tv_nsec) / NSEC_PER_SEC + 1; + y->tv_nsec -= NSEC_PER_SEC * nsec; + y->tv_sec += nsec; + } + if (x->tv_nsec - y->tv_nsec > NSEC_PER_SEC) { + int nsec = (x->tv_nsec - y->tv_nsec) / NSEC_PER_SEC; + y->tv_nsec += NSEC_PER_SEC * nsec; + y->tv_sec -= nsec; + } + /* Compute the time remaining to wait. `tv_nsec' is certainly positive. */ + result->tv_sec = x->tv_sec - y->tv_sec; + result->tv_nsec = x->tv_nsec - y->tv_nsec; + + /* Check that result is not negative */ + // CHECK_ASSERT(x->tv_sec >= y->tv_sec); +} + +// END From https://github.com/veltzer/demos-linux diff --git a/Task-8/k_avg.c b/Task-8/k_avg.c index ba527a7..ba88a49 100644 --- a/Task-8/k_avg.c +++ b/Task-8/k_avg.c @@ -12,59 +12,65 @@ #include #include "CircBuffer.h" +#include "funs.h" -#define PI 3.14 -#define SIG_FREQ 100 -#define SAM_FREQ 2000 +void handle_arguments(int argc, char *argv[]) { + if (argc != 3) { + fprintf(stderr, "Usage: %s REFRESHING_FREQUENCY ALPHA\n", argv[0]); + exit(EXIT_FAILURE); + } -_Noreturn void k_avg(int fd) { - // Exponential Moving Average should be updated with f = 10Hz (i.e. every 200 samples). - int samples = 200; + if (strtol(argv[1], NULL, 10) < 2) { + fprintf(stderr, "Refreshing frequency should be at least 2Hz!\n"); + exit(EXIT_FAILURE); + } + + if (strtod(argv[2], NULL) > 1 || strtod(argv[2], NULL) < 0) { + fprintf(stderr, "Alpha coefficient should be in range [0, 1]!\n"); + exit(EXIT_FAILURE); + } +} + +_Noreturn void k_avg(int fd, int refreshing_frequency, double alpha) { + // Exponential Moving Average printf("A k_avg has been called\n"); + //----- Initialize the buffer ----- struct CircBuffer *buffer; - buffer = mmap(NULL, sizeof(struct CircBuffer*), PROT_READ, MAP_SHARED, fd, 0); + buffer = mmap(NULL, sizeof(struct CircBuffer), PROT_READ, MAP_SHARED, fd, 0); if (buffer == MAP_FAILED) { fprintf(stderr, "mmap: "); exit(EXIT_FAILURE); } - struct timespec delay; + struct timespec delay, tic, toc; delay.tv_sec = 0; - delay.tv_nsec = 100000000ULL*1; // 100ms == 100 000 000ns -> 10Hz + delay.tv_nsec = (1./refreshing_frequency * NSEC_PER_SEC); // 1/f in nanoseconds + clock_gettime(CLOCK_REALTIME, &tic); - - double alpha = 0.1; double ema; - int start_idx = 0; - + int read_idx; + + read_idx = buffer->info.free_idx - 1; + ema = buffer->data[read_idx]; + printf("Refreshing period = %ldms\n", delay.tv_nsec/1000000); while (1) { - start_idx = buffer->info.free_idx; - ema = buffer->data[start_idx]; - printf("start_idx = %d\n", start_idx); - printf("EMA = %lf\n", ema); - nanosleep(&delay, NULL); + clock_gettime(CLOCK_REALTIME, &toc); + if (timespec_diff_nano(&toc, &tic) > delay.tv_nsec) { + printf("EMA = %f\n", ema); + clock_gettime(CLOCK_REALTIME, &tic); + } + while (read_idx == ((buffer->info.free_idx - 1) % buffer->info.size)) {}; + read_idx = ++read_idx % buffer->info.size; + ema = alpha * buffer->data[read_idx] + (1 - alpha) * ema; } - - - - // while (1) { - // start_idx = (buffer->info.free_idx - samples) % buffer->info.size; - // printf("start_idx = %d\n", start_idx); - // ema = buffer->data[start_idx]; - // for (int read_idx = start_idx + 1; read_idx < samples; read_idx = ++read_idx % buffer->info.size) { - // ema = alpha*buffer->data[read_idx] + (1 - alpha) * ema; - // printf("EMA[%d] = %lf\n", read_idx, ema); - // } - // printf("EMA = %lf\n", ema); - // nanosleep(&delay, NULL); - // } - } int main(int argc, char *argv[]) { + handle_arguments(argc, argv); + //----- Open a shared memory ----- const char *memory_name = "/dsp"; int fd = shm_open(memory_name, O_RDONLY, 0777); @@ -74,7 +80,7 @@ int main(int argc, char *argv[]) { } printf("Shared memory file descriptor: %d\n", fd); - k_avg(fd); + k_avg(fd, strtol(argv[1], NULL, 10), strtod(argv[2], NULL)); return 0; } \ No newline at end of file diff --git a/Task-8/k_f0.c b/Task-8/k_f0.c new file mode 100644 index 0000000..b469ce3 --- /dev/null +++ b/Task-8/k_f0.c @@ -0,0 +1,83 @@ +// +// Written for Computer Networks and Systems lab classes +// AUTHOR : Sergiusz Warga + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "CircBuffer.h" +#include "funs.h" + +int crosses_zero(double prev, double curr) { + // let's just ignore 0 for now + return (prev > 0 && curr < 0) || (prev < 0 && curr > 0); +} + +_Noreturn void k_f0(int fd, int sampling_frequency, int refreshing_frequency) { + printf("A k_f0 has been called\n"); + + //----- Initialize the buffer ----- + struct CircBuffer *buffer; + buffer = mmap(NULL, sizeof(struct CircBuffer), PROT_READ, MAP_SHARED, fd, 0); + if (buffer == MAP_FAILED) { + fprintf(stderr, "mmap: "); + exit(EXIT_FAILURE); + } + + struct timespec tic, toc; + // delay.tv_sec = 0; + // delay.tv_nsec = (1./refreshing_frequency * 1000000000L); // 1/f in nanoseconds + unsigned long long delay = NSEC_PER_SEC*1./refreshing_frequency; + clock_gettime(CLOCK_REALTIME, &tic); + + int transitions = 0; + int samples = 0; + int read_idx; + + read_idx = buffer->info.free_idx - 1; + + while (1) { + clock_gettime(CLOCK_REALTIME, &toc); + if (timespec_diff_nano(&toc, &tic) > delay) { + double t_samp = 1./sampling_frequency; + // printf("t_samp = %fs\n", t_samp); + // printf("n_samp = %d\n", samples); + double t_anal = t_samp*samples; + // printf("t_anal = %fs\n", t_anal); + // printf("n_tran = %d\n", transitions); + printf("f = %fHz\n", transitions/(2*t_anal)); + transitions = 0; + samples = 0; + clock_gettime(CLOCK_REALTIME, &tic); + } + + if (crosses_zero(buffer->data[read_idx-1], buffer->data[read_idx])) { + ++transitions; + } + while (read_idx == ((buffer->info.free_idx - 1) % buffer->info.size)) {}; + read_idx = ++read_idx % buffer->info.size; + ++samples; + } +} + +int main(int argc, char *argv[]) { + + //----- Open a shared memory ----- + const char *memory_name = "/dsp"; + int fd = shm_open(memory_name, O_RDONLY, 0777); + if (fd < 0) { + fprintf(stderr, "shm_open: "); + exit(EXIT_FAILURE); + } + printf("Shared memory file descriptor: %d\n", fd); + + k_f0(fd, 2000, 1); + + return 0; +} \ No newline at end of file diff --git a/Task-8/producer.c b/Task-8/producer.c index 471e8ff..76f5bfe 100644 --- a/Task-8/producer.c +++ b/Task-8/producer.c @@ -7,53 +7,74 @@ #include #include #include -#include +// #include #include #include #include "CircBuffer.h" +#include "funs.h" #define PI 3.14 #define SIG_FREQ 100 -#define SAM_FREQ 2000 -double get_sample(int signal_frequeuncy, int sampling_frequency, int sample_no) { +void handle_arguments(int argc, char *argv[]) { + if (argc != 2) { + fprintf(stderr, "Usage: %s SAMPLING_FREQUENCY\n", argv[0]); + exit(EXIT_FAILURE); + } + + if (strtol(argv[1], NULL, 10) < 400) { + fprintf(stderr, "Sampling frequency should be at least 400Hz!\n"); + exit(EXIT_FAILURE); + } +} + +double get_sample(int signal_frequeuncy, int sampling_frequency, unsigned int sample_no) { // TODO: Just a sketch, gotta rewrite - double step = 2.*PI/200; + double step = 2.*PI/((double)sampling_frequency/signal_frequeuncy); // Step in radians return sin(sample_no*step); } -_Noreturn void producer(int fd) { // That's something new I've learned and I think that - // function specifiers are cute. +_Noreturn void producer(int fd, int sampling_frequency) { // That's something new I've learned and I think that + // function specifiers are cute. printf("The producer has been called\n"); + //----- Initialize the buffer ----- struct CircBuffer *buffer; buffer = mmap(NULL, sizeof(struct CircBuffer), PROT_WRITE, MAP_SHARED, fd, 0); if (buffer == MAP_FAILED) { fprintf(stderr, "mmap: "); exit(EXIT_FAILURE); - } - - int i = 0; - int free_idx = 0; - - struct timespec delay; + unsigned int i = 0; + int free_idx; + struct timespec delay, tic, toc; delay.tv_sec = 0; - delay.tv_nsec = 500000ULL*1; // 0.5ms == 500 000ns -> 2kHz + delay.tv_nsec = (int) (1./sampling_frequency * NSEC_PER_SEC); // 1/f in nanoseconds + clock_gettime(CLOCK_REALTIME, &tic); + clock_gettime(CLOCK_REALTIME, &toc); + printf("Starting to sampling the signal at %dHz with t_s = %ldns\n", sampling_frequency, delay.tv_nsec); + //----- Fill the buffer ----- while (1) { - free_idx = buffer->info.free_idx; // For more readable code - buffer->data[free_idx] = get_sample(SIG_FREQ, SAM_FREQ, i+1); // Put a sample into the buffer - buffer->info.free_idx = (free_idx + 1 ) % buffer->info.size; // Increase the free-cell index - printf("CircBuffer[%d] = \t %lf\n", free_idx, buffer->data[free_idx]); - i = ++i % 200; - nanosleep(&delay, NULL); - } - + clock_gettime(CLOCK_REALTIME, &toc); + free_idx = buffer->info.free_idx; + buffer->data[free_idx] = get_sample(SIG_FREQ, sampling_frequency, i); + // printf("CircBuffer[%d] = \t %lf\n", free_idx, buffer->data[free_idx]); + buffer->info.free_idx = (free_idx + 1 ) % buffer->info.size; + ++i; + while (timespec_diff_nano(&toc, &tic) < delay.tv_nsec) { + // printf("%lld\n", timespec_diff_nano(&toc, &tic)); + clock_gettime(CLOCK_REALTIME, &toc); + } + clock_gettime(CLOCK_REALTIME, &tic); + } } int main(int argc, char *argv[]) { + //----- Arguments handling ----- + handle_arguments(argc, argv); + int sampling_frequency = strtol(argv[1], NULL, 10) ; //----- Create a shared memory ----- const char *memory_name = "/dsp"; @@ -62,10 +83,9 @@ int main(int argc, char *argv[]) { fprintf(stderr, "shm_open: "); exit(EXIT_FAILURE); } - printf("Shared memory file descriptor: %d\n", fd); + // printf("Shared memory file descriptor: %d\n", fd); //----- Truncate memory to the buffer's size - if (ftruncate(fd, sizeof(struct CircBuffer)) < 0) { fprintf(stderr, "ftruncate: \n"); exit(EXIT_FAILURE); @@ -81,7 +101,8 @@ int main(int argc, char *argv[]) { buffer->info.size = sizeof(buffer->data)/sizeof(double); buffer->info.free_idx = 0; - producer(fd); + //----- Sample the producer ----- + producer(fd, sampling_frequency); return 0; } \ No newline at end of file