Как мне сгенерировать таблицу с фиксированным сигналом в C? - PullRequest
2 голосов
/ 19 декабря 2009

Каков наиболее эффективный способ генерации массива с плавающей запятой произвольной длины, содержащего амплитуду (представленную от 1 до -1) синусоидальной волны в C?

Ответы [ 3 ]

3 голосов
/ 19 декабря 2009

Как отметил Карл Смотриц в своем ответе , вы можете легко написать простую программу на 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,
};
3 голосов
/ 19 декабря 2009

Если вы хотите что-то очень быстрое, используйте таблицу (как уже было предложено).

Другой подход состоит в том, чтобы смоделировать небольшой синусоидальный генератор и использовать его для генерации массива данных.

Вот пример, как это сделать:

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 для каждой итерации.(примечание: это то же самое, что и сложное умножение).

Этот метод рано или поздно становится нестабильным и не так точен, как вызов sin / cos в цикле.

Так что создавать с ним огромные таблицы не очень хорошая идея, но если вы можете жить с небольшой ошибкой и с небольшими таблицами до десяти тысяч элементов, это вполне пригодно для использования.Чтобы обойти эту проблему, вы можете изменить тип на удвоение, сделать правильное округление или повторно нормализовать результат каждые n итераций.


Редактировать: просто протестировать код с двойной и 1e9 итерациями.Работает для меня.У меня небольшой сдвиг в фазе, но результаты все же более точные, чем при использовании одинарной точности sinf / cosf.

2 голосов
/ 19 декабря 2009

Если вы не хотите никаких накладных расходов во время выполнения, напишите себе небольшую программу, которая распечатывает все ваши значения в виде объявления / инициализации массива C, а затем #include этот файл в вашу программу.

...