Hidden Links

Transcendental  Functions in Low Level C

 

To produce the sine function this system works by simplifying the sine wave using a Taylor Series approximation. 

 

 

With the first three terms it is possible to produce error rates below 0.23% at the fringes and up to 15 decimal places of precision at 0. However the function needs further approximation before it can be utilized on the Xilinx board. 

We will use the method of Finite Difference, sometimes called Newton’s method of divide difference. Apparently all polynomials can be simplified using the method of finite difference. We have to apply a Taylor Series approxamtion first beacuse the Finite Difference method will only work on polynomials.  The Taylor Series used here is a 5th degree polynomial, and this method will apply to it, even as it is scale (to between 0 and 4095), and shifted (to all values above 0V). 

The method of finite difference says that every polynomial can be simplified by taking the difference of two subsequent terms. 

Diff_1=f(x)-f(x-1)

Diff_2=Diff_1n – Diff_1n-1 

Diff_2 is a constant because f(x) in the example is a 2nd degree polynomial.

 

This system can be used in reverse to predict the next term in a series. The constant of this series (2), plus Diff_1 and the current f(x) produces the next value:

 2+7=9

16+9=25

Getting the initial seed values require calculation of the original function, but after that’s done (offline), the rest can be computed using only the addition operations. For a polynomial of degree 5, five seed values are required. 

The system must represent a maximum value of 4095 and a minimum of .00006(Diff_5 the smallest seed value rounded up).  Any numbers larger than this will overflow the 32 bit registers used by
MicroBlaze.

note: There are a few magic numbers in my solutions, because I've applied this mehtod to solve a very speicfic problem, perhaps later I'll produce a more general solution.  

 The Code(Aside from some html copy paste wonkyness ist's all here):

 

void Update_sin(){
     Set_Sin_wave(freq);
}
   
void Sin_val_set(int Sin_del_t,int ticks ){
    // int Sin_del_t=Sin_del_t_in;
     sin_ticks=ticks;
   
   //Calculating a variation of the Taylor Series expantion (5th order) using Newton's law of differences seed values       starting at for t=-PI/2
     int Sin_Diff_5 =       6;
     int Sin_Diff_4 =    -299;
     int Sin_Diff_3 =    1018;
     int Sin_Diff_2 =  187503;
     int Sin_Diff_1 =  221292;
     int Sin_out = 0;
   
   
   
   //incrementing the Taylor Series using Newton's law of implict diffrences places each element into an array
   for (i=0;i<100;i++){
//these values ar 100000 larger than normal
//generated for specific sine range not from -1 to 1, but for the input range used by our DAC
        Sin_Diff_4 += Sin_Diff_5;
         Sin_Diff_3 += Sin_Diff_4;
         Sin_Diff_2 += Sin_Diff_3;
         Sin_Diff_1 += Sin_Diff_2;
         Sin_out    += Sin_Diff_1;
    
        Sin_out_ad =Sin_out/100000;//integer divide to bring numbers back into range
        sin_A[i] = Sin_out_ad; 
   
        //stores the highest value produced by our function
        if ((Sin_out_ad)>Sin_high){ 
            Sin_high = (Sin_out_ad);
        }
   
   }
   for (i=100;i<200;i++){
         sin_A[i] = Sin_high - sin_A[i-100];
     }
   
   XIo_Out32(TIMER0_TLR0, Sin_del_t);
   XIo_Out32(TIMER0_TCSR0, 0x00000172);
   XIo_Out32(TIMER0_TCSR0, 0x000004D2);
   XIo_Out32(TIMER0_TCSR0, XIo_In32(TIMER0_TCSR0));
}
void Sin_waving(){
    static int j = 0;
  
  dac_send(sin_A[j]);
  
  if (j>=199) {
         rising = !rising;
         j=0;
    }else{
j        +=sin_ticks;
    }
   XIo_Out32(TIMER0_TCSR0, XIo_In32(TIMER0_TCSR0));
}


void Update_sin(){

  Set_Sin_wave(freq);

}