/*
	(c) by polprog 2018
	released on 3-clause BSD license
		
	version 1.0

	Minimal FIR implementation, based on a structure
	
	buffer holds the values of sample delay blocks,
	weights hold the weighted average weights,
	[void (*tick)(...) currently unused]
	
	Demo program in main() shows an impulse response of a filter that
	has the weights set by 1/x function.
	
	For microcontroller implementation its possible and advisable to do the maths
	with [u]ints not floats.
*/
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <math.h>

typedef struct filter {
	int filtersize;
	float* buffer;
	float* weights;
	float output;
	void (*tick)(struct filter, float); //tick is a ptr to a function(filter) returning void
	
		
} filter_t;

filter_t filter_init(int size){
	printf("Initializing filter of size %d...\n", size);
	filter_t filter;
	filter.filtersize = size;
	filter.buffer = malloc(sizeof(float) * size);
	assert(filter.buffer != NULL);
	filter.weights = malloc(sizeof(float) * size);
	assert(filter.weights != NULL);
	filter.output = 0;
	
	for(int i = 0; i < filter.filtersize; i++){
		filter.buffer[i] = 0;
	}
	
	return filter;
}

void print_filter_state(filter_t* filter){
	printf("Filter state:\nsize=%d\n", 8);
	printf("buffer=\n[ ");
	for(int i = 0; i < filter->filtersize; i++){
		printf("%f ", filter->buffer[i]);
	}
	printf("]\nweights=\n[ ");
	for(int i = 0; i < filter->filtersize; i++){
		printf("%f ", filter->weights[i]);
	}
	printf("]\n\n\t\toutput=%f\n\n", filter->output);
}

void filter_init_weights_hyperbolic(filter_t* filter){
	printf("initializing weights hyperbolically...\n");
	for(int i = 0; i < filter->filtersize; i++){
		filter->weights[i] = (1/ ((float) i+1));
	}
}

void filter_tick(filter_t* filter, float input){
	//shift buffer one place right, advancing time
	for(int i = filter->filtersize-1; i > 0; i--){
		filter->buffer[i] = filter->buffer[i-1];
	}
	//insert input to zeroth field
	filter->buffer[0] = input;
	//do the maths (weighted average)
	float output;
	for(int i = 0; i < filter->filtersize; i++){
		output += filter->buffer[i] * filter->weights[i];
	}
	output /= filter->filtersize;
	filter->output = output;
}

int main(){
	filter_t filter;
	filter = filter_init(8); //create a filter of length = 8;
	print_filter_state(&filter);
	
	//set up weights - weight(x) = 1/x
	filter_init_weights_hyperbolic(&filter);
	print_filter_state(&filter);
	
	

	printf("\n------\n");
	print_filter_state(&filter);
	
	//send an impulse (dirac's delta)
	printf("\n\n\t---Impulse!---\n\n");
	filter_tick(&filter, 1);
	
	//let the time go on for a while
	for(int i = 0; i <10; i++){
		print_filter_state(&filter);
		filter_tick(&filter, 0);
	}
}