2010-10-11 4 views
5

Я работаю над проектом DDS с микроконтроллером в C, и у меня есть некоторые проблемы с вычислением того, как вычислить линейную интерполяцию, чтобы сгладить выходные значения. Программа в ее нынешнем виде
использует верхние 8 бит 24-разрядного аккумулятора в качестве индекса для массива из 8-разрядных выходных значений. Мне нужно придумать функцию, которая будет принимать средний и нижний байт аккумулятора и создать значение между «предыдущим» и «следующим» значением в массиве. Это было бы достаточно просто на быстром оборудовании, но поскольку я использую микроконтроллер, мне действительно нужно избегать операций с плавающей запятой или подразделений!Линейная интерполяция в прямом цифровом синтезе

С этими ограничениями я не уверен в возможности получить 8-битное интерполированное значение из двух моих 8-разрядных номеров ввода и нижних 2 байтов аккумулятора, что представляет собой «расстояние» между двумя входные значения. Заранее благодарю за любой совет!

РАЗЪЯСНЕНИЕ

DDS = прямой цифровой синтез

в DDS форма сигнал генерируется из справочной таблицы с использованием фазы аккумулятора. Аккумулятор фазы обычно содержит целочисленный компонент и дробную составляющую. Целочисленный компонент используется как индекс в таблице поиска. В простых реализациях DDS дробная часть игнорируется, но для получения более высокого качества дробная составляющая используется для интерполяции (обычно только линейной интерполяции) между соседними значениями таблицы поиска. По вышеуказанному вопросу мы рассмотрим, как эффективно выполнить эту линейную интерполяцию между двумя значениями таблицы поиска для данной фракции f, где 0 <= f < 1.

+0

Что такое _DDS_? –

+0

DDS = Direct Digital Synthesis - используется для генерации сигналов в аудио/радио/коммуникациях/etc –

ответ

7

Если у вас есть таблица значений волновых форм (либо один квадрант или четыре квадранта, это не имеет значения), то один из возможных оптимизации для хранения значения дельта между последовательными значениями таблицы. То есть если у вас есть, например, N = 256 и таблице осциллограмм LUT[N], тогда у вас также есть таблица значений дельта, LUT_delta[N]. Связь между двумя предварительно вычисленными таблицами равна LUT_delta[i] = LUT[i+1] - LUT[i]. Поэтому вместо поиска двух последовательных табличных значений, LUT[i] и LUT[i+1], вычитая их для получения дельта, затем выполнив интерполяцию, вы просто посмотрите первое значение таблицы LUT[i] и дельта LUT_delta[i], а затем вычислите интерполированное значение. Для этого требуется одинаковое количество поиска таблиц, но меньше математических операций. Вы должны иметь возможность выполнить интерполяцию с помощью одной команды умножения накоплений, если вы используете DSP, иначе это умножьте + масштабирование + добавьте на CPU общего назначения.Также, если вы чередуете значения LUT и LUT_delta, вы можете найти LUT[i] и LUT_delta[i] с одним чтением, а затем распаковать два значения.

Псевдо-код:

extract integer LUT index, i, from accumulator // just need a shift for this 
extract fractional part of accumulator, f // mask or subtract to get f 
get p = LUT[i] // lookup waveform value 
get delta = LUT_delta[i] // lookup delta 
calculate p_interp = p + p_delta * f // single multiply-accumulate instruction on most DSPs - need scaling on general purpose CPUs 
+0

Я, вероятно, не понимаю вас правильно - но с 24-битным аккумулятором это не значит, что мне нужно будет хранить значение дельта для всех приращений 2^16 между каждой точкой моей таблицы? Если бы у меня было такое пространство, я бы просто сохранил таблицу при более высоком разрешении и не беспокоился об интерполяции! :) – Bitrex

+0

@Bitrex - нет, если у вас есть таблица точек N (например, N = 256), вам просто нужна вторая таблица точек N для дельт, где 'LUT_delta [i] = LUT [i + 1] - LUT [i ] '. –

+0

А, я вижу. Кажется, у меня достаточно места для стола такого размера! – Bitrex

-1

линейная интерполяция между двумя значениями, и б является (а + б)/2.

Это прост в простом оборудовании и не требует разделения или с плавающей запятой.

Разделить на 2 == сдвиг вправо один бит.

+0

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

+0

"Произвольные"? Средняя точка кажется такой же произвольной, как и любая другая точка. –

+1

@ S.Lott: если вы читаете вопрос о том, что он делает DDS с фазовым аккумулятором, дробная часть фазового аккумулятора определяет точку между двумя значениями, в которых вам нужно интерполировать. Что касается «произвольный», мой словарь говорит: * 2. Математика (постоянной или другой величины) неопределенного значения. * –

0

Если вам действительно нужна скорость, зарегистрируйтесь AVR assembler.

1

Если вам нужна более высокая точность, я бы предложил сначала проверить нижние разряды аккумулятора. Например, если мы хотим, 4 выходных значений вместо 1:

Acc += 0x2000; 
uint lower_bits = Acc & 0xffff; 
int rl = LUT[ Acc >> 16]; 
int rh = LUT[(Acc >> 16) + 1]; 
if (lower_bits < 0x4000) 
    return rl; 
if (lower_bits < 0x8000) 
    return (rl * 3 + rh) >> 2; 
if (lower_bits < 0xC000) 
    return (rl + rh) >> 1; 
return (rl + rh * 3) >> 2; 
4

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

значения (х) = предыдущего,
значения (x + 1) = next значение (x + dx) = предыдущее + (следующее - предыдущее) * dx

Ваш вопрос: как вычислить dx? Хитрость заключается в том, чтобы иметь свой индекс интерполяции (16 младший бит вашего аккумулятора), вычисленный таким образом, что максимальное значение (ах = 1) является степенью двойки:

value(x + dx) = previous + ((next - previous) * index)/1024 

Здесь вы вычислили ваш шаг значение, так что максимальный шаг равен 1024 и соответствует dx = 1. Индекс = 512 для dx = 0,5 и т. Д.

+0

Я вижу, поэтому в моем случае с 24-битным аккумулятором, использующим верхние 8 бит в качестве индекса (значение 2^16 шагов), деление должно быть на 2^16 или на 16 бит вправо. – Bitrex

+0

Да, проблема в том, что вы должны иметь возможность хранить (следующий - предыдущий) * 2^16 в своем вычислении. – shodanex

Смежные вопросы