Generate sine signal in C without using the standard function

后端 未结 11 748
情歌与酒
情歌与酒 2021-02-02 09:41

I want to generate a sine signal in C without using the standard function sin() in order to trigger sine shaped changes in the brightness of a LED. My basic idea was to use a lo

11条回答
  •  小蘑菇
    小蘑菇 (楼主)
    2021-02-02 09:41

    OP's main problem is in generating the index for the table look-up.

    OP's code attempts to access outside array sine_table[40] leading to undefined behavior. Fix that at least.

    const int sine_table[40] = {0, 5125, 10125, ...
        ...
        x1 = (int) phase % 41;                     // -40 <= x1 <= 40
        x2 = x1 + 1;                               // -39 <= x2 <= 41  
        y = (sine_table[x2] - sine_table[x1])*...  // bad code, consider x1 = 40 or x2 = 40,41
    

    Suggested change

        x1 = (int) phase % 40;   // mod 40, not 41
        if (x1 < 0) x1 += 40;    // Handle negative values
        x2 = (x1 + 1) % 40;      // Handle wrap-around 
        y = (sine_table[x2] - sine_table[x1])*...  
    

    There exist much better approaches, yet to focus on OP's method see below.

    #include 
    #include 
    
    const int sine_table[40] = { 0, 5125, 10125, 14876, 19260, 23170, 26509, 29196,
    31163, 32364, 32767, 32364, 31163, 29196, 26509, 23170, 19260, 14876, 10125,
    5125, 0, -5126, -10126, -14877, -19261, -23171, -26510, -29197, -31164, -32365,
    -32768, -32365, -31164, -29197, -26510, -23171, -19261, -14877, -10126, -5126 };
    
    int i = 0;
    int x1 = 0;
    int x2 = 0;
    float y = 0;
    
    float sin1(float phase) {
      x1 = (int) phase % 40;
      if (x1 < 0) x1 += 40;
      x2 = (x1 + 1) % 40;
      y = (sine_table[x2] - sine_table[x1])
          * ((float) ((int) (40 * 0.001 * i * 100) % 4100) / 100 - x1)
          + sine_table[x1];
      return y;
    }
    
    int main(void) {
      double pi = 3.1415926535897932384626433832795;
      for (int j = 0; j < 1000; j++) {
        float x = 40 * 0.001 * i;
        float radians = x * 2 * pi / 40;
        printf("%f %f %f\n", x, sin1(x) / 32768, sin(radians));
        i = i + 1;
      }
    }
    

    Output

             OP's     Reference sin()
    0.000000 0.000000 0.000000
    0.040000 0.006256 0.006283
    0.080000 0.012512 0.012566
    ...
    1.960000 0.301361 0.303035
    2.000000 0.308990 0.309017
    2.040000 0.314790 0.314987
    ...
    39.880001 -0.020336 -0.018848
    39.919998 -0.014079 -0.012567
    39.959999 -0.006257 -0.006283
    

    Better code would not pass the values i, x1, x2, y as global variables, but as function parameters or function variables. Perhaps that is an artifact of OP's debugging.


    Does anybody have a better idea to implement a sine generator in C?

    This is quite broad. Better as in speed, precision, code space, portability, or maintainability? sine() functions are easy to make. High-quality ones take more effort.

    Although fuzzy, OP's use of a small look-up table is a good beginning - although I see it can be done without any floating point math. I recommend for OP to construct a tested and working solution and post it in Code Review for improvement ideas.

提交回复
热议问题