如何用 C 语言生成固定波形表?

发布于 2024-08-14 21:29:34 字数 57 浏览 3 评论 0原文

在 C 中生成包含正弦波幅度(从 1 到 -1 表示)的任意长度的有符号浮点数组的最有效方法是什么?

What is the most efficient way to generate a signed float array of arbitrary length containing the amplitude (represented from 1 to -1) of a sine wave in C?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

为你鎻心 2024-08-21 21:29:34

正如 Carl Smotricz 在他的答案中指出的那样,您可以轻松编写一个简单的C程序来为您构建一个硬编码数组。

下面的代码可以解决这个问题:

int main(int argc, char * argv[])
{
    const int tableSize = 10;
    const char * fileName = "sin_table.txt";

    int x;
    FILE * file;

    file = fopen(fileName, "w");
    if (file == NULL) { printf("unable to open file\n"); return -1; }

    fprintf(file, "float sin_table[%d] =\n{\n ", tableSize);
    for (x = 0; x < tableSize; x++)
    {
        fprintf(file, "\t%f,\n", sinf(x*2*pi/tableSize));
    }
    fprintf(file, "};\n");

    fclose(file);
    return 0;
}

输出如下所示:

float sin_table[10] =
{
    0.000000,
    0.587785,
    0.951057,
    0.951056,
    0.587785,
    -0.000000,
    -0.587785,
    -0.951057,
    -0.951056,
    -0.587785,
};

As Carl Smotricz pointed out in his answer, you can easily write a simple C program to build a hard-coded array for you.

The following code would do the trick:

int main(int argc, char * argv[])
{
    const int tableSize = 10;
    const char * fileName = "sin_table.txt";

    int x;
    FILE * file;

    file = fopen(fileName, "w");
    if (file == NULL) { printf("unable to open file\n"); return -1; }

    fprintf(file, "float sin_table[%d] =\n{\n ", tableSize);
    for (x = 0; x < tableSize; x++)
    {
        fprintf(file, "\t%f,\n", sinf(x*2*pi/tableSize));
    }
    fprintf(file, "};\n");

    fclose(file);
    return 0;
}

And the output would look like this:

float sin_table[10] =
{
    0.000000,
    0.587785,
    0.951057,
    0.951056,
    0.587785,
    -0.000000,
    -0.587785,
    -0.951057,
    -0.951056,
    -0.587785,
};
陌上青苔 2024-08-21 21:29:34

如果您想要非常快的东西,请使用表格(如已经建议的那样)。

另一种方法是模拟一个小的正弦振荡器并用它来生成数据数组。

下面是如何执行此操作的示例:

int main (int argc, char **args)
{
  int i;

  float data[1024];
  float angle = 2.0f * 3.14 / 1024;

  // start of the sine-wave:
  float sinval = 0;
  float cosval = 1;

  // rotation per iteration
  float delta_sin = sinf(angle);
  float delta_cos = cosf(angle);

  for (i=0; i<1024; i++)
  {
    // store current value:
    data[i] = sinval;

    // update the oscillator:
    float s = sinval * delta_cos - cosval * delta_sin;
    float c = sinval * delta_sin + cosval * delta_cos;
    sinval = s;
    cosval = c;
  }
}

这背后的技巧是,我们从 2D 空间中的固定点开始,存储在 9sinval、cosval 中。此外,我预先计算了 (delta_cos, delta_sin) 中单次旋转的参数。

我在循环中所做的就是使用固定旋转将点旋转 1024 次。这会在每次迭代中创建一个正弦/余弦对。 (注意:它与复数乘法相同)。

这种方法迟早会变得不稳定,并且不像在循环中调用 sin/cos 那样精确。

因此,用它创建巨大的表并不是一个好主意,但是如果您可以忍受轻微的错误并且可以创建最多一万个元素的小表,那么它是非常有用的。为了解决这个问题,您可以将类型更改为 double,进行适当的舍入或每 n 次迭代重新规范化结果。


编辑:刚刚用 double 和 1e9 迭代测试了代码。对我有用。我的相位有轻微的漂移,但结果仍然比使用单精度 sinf/cosf 更精确。

If you want something very fast use a table (as already suggested).

Another approach is to simulate a little sine-oscillator and use it to generate your data-array.

Here is an example how to do this:

int main (int argc, char **args)
{
  int i;

  float data[1024];
  float angle = 2.0f * 3.14 / 1024;

  // start of the sine-wave:
  float sinval = 0;
  float cosval = 1;

  // rotation per iteration
  float delta_sin = sinf(angle);
  float delta_cos = cosf(angle);

  for (i=0; i<1024; i++)
  {
    // store current value:
    data[i] = sinval;

    // update the oscillator:
    float s = sinval * delta_cos - cosval * delta_sin;
    float c = sinval * delta_sin + cosval * delta_cos;
    sinval = s;
    cosval = c;
  }
}

The trick behind this is, that we start with a fixed point in 2D-space, stored in 9sinval, cosval). Furthermore I precompute the parameters for a single rotation in (delta_cos, delta_sin).

All I do in the loop is to rotate the point 1024 times with the fixed rotation. This creates a sin/cos pair per iteration. (note: it's the same as a complex multiplication).

This method becomes unstable sooner or later and is not as exact as calling sin/cos in the loop.

So it's not a good idea to create huge tables with it, but if you can live with a slight error and smallish tables up to ten thousand elements it's quite usable. To get around that issue you could change the type to double, do proper rounding or re-normalize the result every n iterations.


Edit: Just tested the code with double and 1e9 iterations. Works for me. I have a slight drift in the phase, but the results are still more exact than using single precision sinf/cosf.

美人迟暮 2024-08-21 21:29:34

如果您不想运行时开销,请自己编写一个小程序,以 C 数组声明/初始化的形式打印出所有值,然后#include 该文件到您的程序中。

If you want no runtime overhead, write yourself a little program that prints out all your values as a C array declaration/initialization, and then #include that file into your program.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文