математика — C ++ генерация математических функций

Работая над проектом, я столкнулся с необходимостью точно генерировать различные волны. Я думал, что простая синусоида будет проще всего начать, но, похоже, я ошибаюсь. Я сделал простую программу, которая генерирует vector сэмплов, а затем воспроизводит эти сэмплы, чтобы пользователь услышал волну в качестве теста. Вот соответствующий код:

vector<short> genSineWaveSample(int nsamples, float freq, float amp) {
vector<short> samples;
for(float i = 0; i <= nsamples; i++) {
samples.push_back(amp * sinx15(freq*i));
}
return samples;
}

Я не уверен, что проблема с этим. Я понимаю, что может быть некоторая проблема с вектором, сделанным из shorts, но это то, чего хочет моя звуковая инфраструктура, и я неопытен с такой библиотекой и поэтому не знаю, чего ожидать.

Симптомы следующие:

  • частота не верна
    • т.е.: заданная частота = 440, А4 не является проигрываемой нотой
  • странное искажение
    • Большинство частот не генерируют чистую волну. 220, 440, 880 все чистые, большинство других искажены
  • Большинство частот значительно смещены вверх

Кто-нибудь может дать совет, что я могу делать не так?

Вот что я пробовал до сих пор:

  • Создание моей собственной функции синуса, для большей точности.
    • Я использовал расширение Тейлора 15-й степени для греха (х)
  • Изменена частота дискретизации, от 256 до 44100, никаких изменений не слышно, учитывая вышеперечисленные ошибки, волны просто более искажены.

Спасибо. Если есть какая-либо информация, которая может вам помочь, я буду обязан предоставить ее.

0

Решение

Я подозреваю, что вы передаете неверные значения sin15x функция. Если вы знакомы с основами обработки сигналов, Частота Найквиста это минимальная частота, на которой вы можете точно восстановить (или в вашем случае построить) дискретизированный сигнал. Определяется как 2x самая высокая частотная составляющая, присутствующая в сигнале.

Для вашей программы это означает, что вам нужно по крайней мере 2 значения за цикл наивысшей частоты, которую вы хотите воспроизвести. При 20 кГц вам понадобится 40000 выборок в секунду. Похоже, что вы просто упаковываете вектор со значениями и позволяете программе воспроизведения выбирать время.

Мы будем считать, что вы используете частоту дискретизации при воспроизведении 44,1 кГц. Это означает, что фрагмент кода, генерирующий одну секунду волны 1 кГц, будет выглядеть

DataStructure wave = new DataStructure(44100) // creates some data structure of 44100 in length

for(int i = 0; i < 44100; i++)
{
wave[i] = sin(2*pi * i * (frequency / 44100) + pi / 2) // sin is in radians, frequency in Hz
}

Вам нужно делить на частоту, а не умножать. Чтобы увидеть это, рассмотрим случай передачи значения частоты 22 050 Гц. Для i = 0 вы получаете sin (0) = 1. Для i = 1, sin (3pi / 2) = -1 и так далее, и так далее. Это дает вам повторяющуюся последовательность 1, -1, 1, -1 …, которая является правильным представлением волны 22,050 Гц, сэмплированной с частотой 44,1 кГц. Это работает, когда вы понижаете частоту, но вы получаете все больше и больше семплов за цикл. Интересно, что это не имеет значения. Синусоидальная выборка с частотой 2 выборки за цикл воссоздается точно так же, как и выборка с 1000 выборок в секунду. Это не учитывает шум, но для большинства целей работает достаточно хорошо.

Я бы посоветовал изучить основы цифровой обработки сигналов, поскольку это очень интересная область и очень полезная для понимания.

Редактировать: Предполагается, что все эти параметры оцениваются как числа с плавающей запятой.

1

Другие решения

По сути, вы упускаете часть информации. Вы не указываете время, за которое вы хотите, чтобы ваши образцы были взяты. Это также можно рассматривать как скорость, с которой сэмплы будут воспроизводиться вашей системой. Что-то в этом направлении приблизит вас, но пока.

samples.push_back(amp * std::sin(M_PI / freq *i));
0

По вопросам рекламы [email protected]