Интерполяция таблицы синусов

Я хочу собрать SDR-систему, которая сначала настраивает AM, позже FM и т.д. Система, которую я планирую использовать для этого, будет иметь таблицу синусоидального поиска для Direct Digital Synthesis (DDS). Для правильной настройки я ожидаю, что вам нужно будет точно контролировать частоту синусоидальной волны, подаваемой в микшер (в этом случае множитель). Я ожидаю, что линейная интерполяция будет близка, но думаю, что нелинейный метод обеспечит лучшие результаты.

Что такое хороший и быстрый метод интерполяции для использования в синусных таблицах. Умножение и добавление дешевы в целевой системе; разделение является дорогостоящим.

Изменить: Я планирую реализовать константы с функциями multiply/shift для нормализации констант до масштабированных целых чисел. Промежуточные значения будут использовать широкие добавления, а умножения будут использовать 18 или 17 бит. Можно использовать "предварительную вычисление" с плавающей запятой, но не на целевой платформе. Когда я говорю "разделение дорого", я имею в виду, что он должен реализовываться с использованием множителей и большого количества кода. Это немыслимо, но его следует избегать. Тем не менее, истинные методы IEEE с плавающей запятой потребуют значительного количества ресурсов на этой платформе, а также для пользовательской реализации.

Любой опыт SDR будет полезен.

Ответ 1

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

Формулы сумм и разностей

sin(A+B)=sinA*cosB + cosA*sinB
sin(A-B)=sinA*cosB - cosA*sinB
cos(A+B)=cosA*cosB - sinA*sinB
cos(A-B)=cosA*cosB + sinA*sinB

и вы можете предусмотреть значения sin и cos для диапазонов A, B, то есть

A range: 0, 10, 20, ... 90
B range: 0.01 ... 0.99

Ответ 2

табличная интерполяция для гладких функций = ick hurl bleah. IMHO Я бы использовал только интерполяцию таблицы на какой-то действительно странной функции или где вам абсолютно необходимо было избежать разрывов (обратите внимание, что производные для интерполированных таблиц являются прерывистыми, хотя). К тому времени, когда вы закончите поиск таблиц и требуемый код интерполяции, вы могли бы уже оценить полином или два, по крайней мере, если умножение не вызывает слишком много изжоги.

ИМХО, вам гораздо лучше использовать Чебышевское приближение для каждого сегмента (например, от -90 до +90 градусов или от -45 до + 45 градусов, а затем другие сегменты с одинаковой шириной) синусоидальной формы и выбор полинома минимальной степени, который уменьшает вашу ошибку до желаемого значения. Если сегмент достаточно мал, вы можете уйти с квадратичным или, возможно, даже линейным полиномом; существуют компромисс между точностью и количеством сегментов и степенью полинома.

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

(отредактируйте: в случае, если это было неясно, вы делаете чебышевское приближение во время разработки на своем любимом мощном ПК, так что во время работы вы можете использовать микроконтроллер с грязью или FPGA или что угодно с простым полином степени 1-4. Не переходите через степень 4, если вы не знаете, что делаете, 3 или ниже было бы лучше.)

Ответ 3

Почему таблица? Эта очень быстрая функция имеет наихудший пик шума при -90 дБ, когда сигнал находится на -20 дБ. Это безумно хорошо.

Для передискретизации звука я всегда использую один из интерполяторов из бумаги Elephant. Это обсуждалось в предыдущем SO-вопросе.

Если вы работаете с процессором, у которого нет fp, вы все равно можете делать все это, но они сложнее. Я был здесь. Я чувствую твою боль. Удачи! Раньше я делал преобразования для fp для целого числа для удовольствия, но теперь вам придется заплатить мне за это.: -)


Прохладные онлайн-ссылки, которые относятся к вашей проблеме:

http://www.audiomulch.com/~rossb/code/sinusoids/

http://www.dattalo.com/technical/theory/sinewave.html


Изменить: дополнительные мысли, основанные на ваших комментариях

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

Предположим, вы разбиваете квадрант на 90 частей (на самом деле вы, вероятно, используете 256 штук, но держите его 90 для знакомства и ясности). Кодируйте их как 16 бит. Это 180 байт таблицы.

Теперь, для каждой из этих степеней, у нас будет 9 (на самом деле возможно 8 или 16) промежуточных точек.

В качестве примера возьмем диапазон от 3 до 4 градусов.

sin(3)=0.052335956 //this will be in your table as a 16-bit number
sin(4)=0.069756474 //this will be in your table as a 16-bit number

поэтому мы посмотрим на грех (3.1)

sin(3.1)=0.054978813 //we're going to be tricky and store the result
                     // in 8 bits as a percentage of the distance between
                     // sin(3) and sin(4)

То, что вы хотите сделать, - это выяснить, как грех (3.1) находится между грехом (3) и sin (4). Если это на полпути между, код, который как байт 128. Если это четверть пути между, код, который как 64.

Это дополнительные 90 байт, и вы закодировали до десятой степени в 16-разрядном res только в 180 + 90 * 9 байтах. Вы можете растягиваться по мере необходимости (возможно, до 32-битных углов и 16-битных углов поворота) и линейно интерполировать между ними очень быстро. Чтобы свести к минимуму пространство для хранения, вы используете тот факт, что последовательные значения близки друг к другу.


Изменить 2: лучший способ кодирования промежуточных углов в таблице

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

Я сначала вычислил максимальную ошибку в диапазоне, а затем основал шкалу на этом.

Работал отлично. Мне кажется, что я должен сделать код в блоге, чтобы проиллюстрировать.: -)

Ответ 4

Интерполяция в таблице синусов эффективно передискретизируется. Очевидно, что вы можете получить идеальные результаты одним вызовом sin, поэтому, независимо от вашего решения, это должно превзойти это. Для повторной выборки с фиксированным фильтром вы по-прежнему будете иметь только фиксированный набор доступных точек (3s: 1 upsampler означает, что у вас будет 2 новых точки между каждой точкой в ​​вашей таблице). Насколько дорогой является память в целевой системе? Моя основная рекомендация - просто улучшить разрешение таблицы и использовать линейную интерполяцию. Вы получите те же результаты, что и меньшая таблица, и простой пример, но с меньшими вычислительными издержками.

Ответ 5

Рассматривали ли вы использование серии Тейлора для функций-триггеров (найдено здесь)? Это включает в себя умножение и деление, но в зависимости от того, как представлены ваши числа, вы можете превратить деление в умножение (или бит сдвига, если вам очень повезло). Вы можете вычислить столько терминов серии, сколько вам нужно, и получить такую ​​точность.

В качестве альтернативы, если эта синусоидальная волна станет аналоговым сигналом в какой-то момент, вы можете просто использовать подход в таблице поиска и использовать аналоговый фильтр для удаления частоты выборки из результирующей формы сигнала. Если частота дискретизации в 100 раз больше частоты синуса, ее легко удалить. Для этого вам понадобится переменный фильтр. Я никогда не делал такого, но я знаю, что есть цифровые потенциометры, которые берут двоичное число и меняют свое сопротивление. Это может быть основой переменного RC-фильтра - возможно, с некоторыми op-усилителями для усиления и т.д.

Удачи!

Ответ 6

Люди написали удивительно умный код для быстрого вычисления sin() для систем с небольшим объемом памяти, которые даже не имеют инструкции по умножению аппаратных средств, а тем более инструкции разделения.

В порядке возрастания сложности:

  • Используйте прямоугольную волну. Многие радиостанции AM используют квадратные волны в своем кольцевом демодуляторе, и я не понимаю, почему ваш демодулятор AM требует чего-то более сложного.

  • Приблизительный sin() путем поиска "ближайшего значения" в исходной таблице из 256 значений за четверть цикла. Да, вы видите ужасные лестничные ступени, но (с немного аналоговой фильтрацией) это часто работает хорошо. (На самом деле это часто бывает излишним, а гораздо более короткая таблица является адекватной).

  • Приблизительный sin(), просматривая 2 ближайших значения в исходной таблице и линейно интерполируя между ними.

  • Приблизительный sin() с 16 короткими кубическими сплайнами с одинаковым интервалом в x для четвертого цикла "дает лучше, чем 16-битная точность" для sin (x).

Викиучебники: номера с фиксированной точкой ссылаются на некоторые умные реализации последних 3.