how to smooth arbitrary values without using an average

closed account (236Rko23)
hi there, i'm doing a fan controler for my pc, and i'm having some problems smoothing the fans' acceleration.

this is what i've so far, for the linear acceleration
"int16_t dc" is actualy a uint8_t but used int16_t there to save 1 byte.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void PWM_setdc_lineal(int16_t dc,  uint8_t ch_sel)
{
	PWM_dc_rotation(&dc, ch_sel); // rotates the rect's angle
	
	PMW_adc_adj(&dc, ch_sel); // stretchs to the min and max values, doesn't matter
	
	// proble here, i've tried lots of methods but this is the best so far.
	// calculate the diference between the current DC(OCR2) and value read 
	// from the ADC, filtered and adjusted previously, then divide them by 
	// the SMOOTH level and then subtract the value to the float version of
	// OCR2....then crop....then round() and set to the hardware register
	PWM_DCC[ch_sel] -= (float)(OCR2-dc)/(float)PWM_SMOOTH_LVL[ch_sel];
	
	PMW_dcc_adj(PWM_DCC, ch_sel); //crops the value to be between min and max
    
	PWM_set_dc(PWM_DCC, ch_sel); //set +duty cycle percentage
}


the problem is that it isn't that linear, and when the diference is small it starts to slow down, if i hadn't used round it would never reach to the value as that is the limit of the ecuation and since it rounds to the lower value by default it would always be 1 less.
it's exactly the same slope of the capasitors' charge time.

using an array to average isn't posible as it would use up to 255 bytes and till now i have only 446bytes of ram left, and i need two values to be controled and smoothed.

any suggestion?
thanks in advance, Laharl
Last edited on
I'm not entirely sure how your code is supposed to behave, but how about this?
Suppose you don't want the current (or whatever) to change faster than ±k units per unit of time. Then you can do
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
//0: not changing
//positive: rising
//negative: falling
int state=0;

const float k=/*...*/;
float new_speed,current_speed;

void set_speed(float new_speed){
    if (new_speed<current_speed)
        state=-1;
    else if (new_speed>current_speed)
        state=1;
    else
        state=0;
}

//this needs to be called in a loop:
void update_speed(){
    if (!state)
        return;
    float delta_time=time_since_last_call(),
        fractional_k=k/delta_time;
    if (state>0){
        if (current_speed+fractional_k>=new_speed){
            current_speed=new_speed;
            state=0;
        }else
            current_speed+=fractional_k;
    }else{
        if (current_speed-fractional_k<=new_speed){
            current_speed=new_speed;
            state=0;
        }else
            current_speed-=fractional_k;
    }
}
Last edited on
closed account (236Rko23)
i was experimenting with other methods too, but in the end, yours was the best. Thanks for the help.
i dont have a rtc in the chip but i do have a sample rate variable, so used that and the lvl one for dividing the time

thaks again for the help :P
Topic archived. No new replies allowed.