exponenta event banner

Расчет синуса с фиксированной точкой и косинуса

В этом примере показано, как использовать алгоритмы на основе CORDIC и таблицы поиска, предоставляемые Designer™ Fixed-Point, для аппроксимации синуса MATLAB ® (SIN) и косинус (COS) функции. Эффективные алгоритмы синусоиды и косинуса с фиксированной точкой имеют решающее значение для многих встроенных приложений, включая управление двигателями, навигацию, обработку сигналов и беспроводную связь.

Вычисление синуса и косинуса с помощью алгоритма CORDIC

Введение

cordiccexp, cordicsincos, cordicsin, и cordiccos функции аппроксимируют MATLAB sin и cos функции, использующие алгоритм на основе CORDIC. CORDIC - аббревиатура от COORDinate Rotation DIgital Computer. Алгоритм CORDIC на основе ротации Givens (см. [1,2]) является одним из наиболее аппаратных эффективных алгоритмов, поскольку требует только итеративных операций добавления сдвига. Алгоритм CORDIC исключает необходимость явных умножителей и подходит для вычисления множества функций, таких как синус, косинус, арксинус, арккосинус, арктангенс, векторная величина, деление, квадратный корень, гиперболические и логарифмические функции.

Для вычисления синуса и косинуса можно использовать режим вычисления вращения CORDIC, а также операции полярно-декартового преобразования. В этом режиме известны величина вектора и угол поворота, и компоненты координат (X-Y) вычисляются после поворота.

Режим вычисления вращения CORDIC

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

В режиме вращения уравнения CORDIC:

$$ z_{i+1} = z_{i} - d_{i}*atan(2^{-i}) $$

$$ x_{i+1} = x_{i} - y_{i}*d_{i}*2^{-i} $$

$$ y_{i+1} = y_{i} + x_{i}*d_{i}*2^{-i} $$

где если$$ d_{i} = -1 $$, и $$ z_{i} < 0 $$$$ +1 $$иначе;

$$ i = 0, 1, ..., N-1 $$и$$ N $$ является общим числом итераций.

Это дает следующий результат в качестве$$ N $$ подходов:$$ +\infty $$

$$ z_{N} = 0 $$

$$ x_{N} = A_{N}(x_{0}\cos{z_{0}} - y_{0}\sin{z_{0}}) $$

$$ y_{N} = A_{N}(y_{0}\cos{z_{0}} + x_{0}\sin{z_{0}}) $$

Где:

$$ A_{N} = \prod_{i=0}^{N-1}{\sqrt{1+2^{-2i}}} $$.

В режиме вращения алгоритм CORDIC ограничен углами поворота между$$ -\pi/2 $$ и. $$ \pi/2 $$Для поддержки углов за пределами этого диапазона, cordiccexp, cordicsincos, cordicsin, и cordiccos функции используют квадрантную коррекцию (включая возможное дополнительное отрицание) после завершения итераций CORDIC.

Понимание CORDICSINCOS Код синуса и косинуса

Введение

cordicsincos функция вычисляет синус и косинус входных углов в диапазоне [-2 * pi, 2 * pi) с помощью алгоритма CORDIC. Эта функция принимает$$ \theta $$ угол (радианы) и число итераций в качестве входных аргументов. Функция возвращает аппроксимации синуса и косинуса.

Выходные сигналы вычислений CORDIC масштабируются с помощью коэффициента усиления вращателя. Это усиление обусловлено предварительным масштабированием начального$$ 1 / A_{N} $$ значения константы.

Инициализация

cordicsincos выполняет следующие шаги инициализации:

  • Таблица поиска входного угла inpLUT имеет значение atan(2 .^ -(0:N-1)).

  • $$ z_{0} $$ имеет$$ \theta $$ значение входного аргумента.

  • $$ x_{0} $$ имеет значение.$$ 1 / A_{N} $$

  • $$ y_{0} $$ имеет нулевое значение.

Разумный выбор начальных значений позволяет алгоритму непосредственно вычислять одновременно как синус, так и косинус. После$$ N $$ итераций эти начальные значения приводят к следующим выводам в качестве$$ N $$ подходов:$$ +\infty $$

$$ x_{N} \approx cos(\theta) $$

$$ y_{N} \approx sin(\theta) $$

Общий код ядра CORDIC с фиксированной и плавающей точками

Код MATLAB для части ядра алгоритма CORDIC (режим ротации) выглядит следующим образом (для случая скаляра x, y, и z). Этот же код используется как для операций с фиксированной запятой, так и для операций с плавающей запятой:

function [x, y, z] = cordic_rotation_kernel(x, y, z, inpLUT, n)
% Perform CORDIC rotation kernel algorithm for N kernel iterations.
xtmp = x;
ytmp = y;
for idx = 1:n
    if z < 0
        z(:) = z + inpLUT(idx);
        x(:) = x + ytmp;
        y(:) = y - xtmp;
    else
        z(:) = z - inpLUT(idx);
        x(:) = x - ytmp;
        y(:) = y + xtmp;
    end
    xtmp = bitsra(x, idx); % bit-shift-right for multiply by 2^(-idx)
    ytmp = bitsra(y, idx); % bit-shift-right for multiply by 2^(-idx)
end

Визуализация КОРДИЧЕСКИХ итераций синусоидального-косинусного режима вращения

Алгоритм CORDIC обычно выполняется через заданное (постоянное) число итераций, так как завершение ранних итераций CORDIC нарушит конвейерный код, и усиление CORDIC$$ A_{n} $$ не будет постоянным, потому что$$ n $$ будет изменяться.

Для очень больших значений $$ n $$алгоритм CORDIC гарантированно сходится, но не всегда монотонно. Как будет показано в следующем примере, промежуточные итерации иногда дают более точные результаты, чем более поздние итерации. Обычно можно достичь большей точности, увеличив общее число итераций.

Пример

В следующем примере итерация 5 обеспечивает лучшую оценку результата, чем итерация 6, и алгоритм CORDIC сходится в более поздних итерациях.

theta   = pi/5; % input angle in radians
niters  = 10;   % number of iterations
sinTh   = sin(theta); % reference result
cosTh   = cos(theta); % reference result
y_sin   = zeros(niters, 1);
sin_err = zeros(niters, 1);
x_cos   = zeros(niters, 1);
cos_err = zeros(niters, 1);
fprintf('\n\nNITERS \tERROR\n');
fprintf('------\t----------\n');
for n = 1:niters
    [y_sin(n), x_cos(n)] = cordicsincos(theta, n);
    sin_err(n) = abs(y_sin(n) - sinTh);
    cos_err(n) = abs(x_cos(n) - cosTh);
    if n < 10
        fprintf('   %d \t %1.8f\n', n, cos_err(n));
    else
        fprintf('  %d \t %1.8f\n', n, cos_err(n));
    end
end
fprintf('\n');

NITERS 	ERROR
------	----------
   1 	 0.10191021
   2 	 0.13966630
   3 	 0.03464449
   4 	 0.03846157
   5 	 0.00020393
   6 	 0.01776952
   7 	 0.00888037
   8 	 0.00436052
   9 	 0.00208192
  10 	 0.00093798

Постройте график ошибки аппроксимации CORDIC на гистограмме

figure(1); clf;
bar(1:niters, cos_err(1:niters));
xlabel('Number of iterations','fontsize',12,'fontweight','b');
ylabel('Error','fontsize',12,'fontweight','b');
title('CORDIC approximation error for cos(pi/5) computation',...
    'fontsize',12,'fontweight','b');
axis([0 niters 0 0.14]);

Постройте график результатов X-Y для 5 итераций

Niter2Draw = 5;
figure(2), clf, hold on
plot(cos(0:0.1:pi/2), sin(0:0.1:pi/2), 'b--'); % semi-circle
for i=1:Niter2Draw
    plot([0 x_cos(i)],[0 y_sin(i)], 'LineWidth', 2); % CORDIC iteration result
    text(x_cos(i),y_sin(i),int2str(i),'fontsize',12,'fontweight','b');
end
plot(cos(theta), sin(theta), 'r*', 'MarkerSize', 20); % IDEAL result
xlabel('X (COS)','fontsize',12,'fontweight','b')
ylabel('Y (SIN)','fontsize',12,'fontweight','b')
title('CORDIC iterations for cos(pi/5) computation',...
    'fontsize',12,'fontweight','b')
axis equal;
axis square;

Вычисление синусоиды с фиксированной точкой с помощью cordicsin

Создание 1024 точек между [-2 * pi, 2 * pi)

stepSize = pi/256;
thRadDbl = (-2*pi):stepSize:(2*pi - stepSize);
thRadFxp = sfi(thRadDbl, 12);     % signed, 12-bit fixed-point values
sinThRef = sin(double(thRadFxp)); % reference results

Сравнение результатов КОРДИК с фиксированной точкой и результатов триговой функции с двойной точностью

Используйте 12-разрядные квантованные входные данные и измените число итераций от 4 до 10.

for niters = 4:3:10
    cdcSinTh  = cordicsin(thRadFxp,  niters);
    errCdcRef = sinThRef - double(cdcSinTh);
    figure; hold on; axis([-2*pi 2*pi -1.25 1.25]);
    plot(thRadFxp, sinThRef,  'b');
    plot(thRadFxp, cdcSinTh,  'g');
    plot(thRadFxp, errCdcRef, 'r');
    ylabel('sin(\Theta)','fontsize',12,'fontweight','b');
    set(gca,'XTick',-2*pi:pi/2:2*pi);
    set(gca,'XTickLabel',...
        {'-2*pi', '-3*pi/2', '-pi', '-pi/2', ...
        '0', 'pi/2', 'pi', '3*pi/2','2*pi'});
    set(gca,'YTick',-1:0.5:1);
    set(gca,'YTickLabel',{'-1.0','-0.5','0','0.5','1.0'});
    ref_str = 'Reference: sin(double(\Theta))';
    cdc_str = sprintf('12-bit CORDICSIN; N = %d', niters);
    err_str = sprintf('Error (max = %f)', max(abs(errCdcRef)));
    legend(ref_str, cdc_str, err_str);
    title(cdc_str,'fontsize',12,'fontweight','b');
end

Вычислить ошибку LSB для N = 10

figure;
fracLen = cdcSinTh.FractionLength;
plot(thRadFxp, abs(errCdcRef) * pow2(fracLen));
set(gca,'XTick',-2*pi:pi/2:2*pi);
set(gca,'XTickLabel',...
    {'-2*pi', '-3*pi/2', '-pi', '-pi/2', ...
    '0', 'pi/2', 'pi', '3*pi/2','2*pi'});
ylabel(sprintf('LSB Error: 1 LSB = 2^{-%d}',fracLen),'fontsize',12,'fontweight','b');
title('LSB Error: 12-bit CORDICSIN; N=10','fontsize',12,'fontweight','b');
axis([-2*pi 2*pi 0 6]);

Вычислить уровень шума

fft_mag = abs(fft(double(cdcSinTh)));
max_mag = max(fft_mag);
mag_db  = 20*log10(fft_mag/max_mag);
figure;
hold on;
plot(0:1023, mag_db);
plot(0:1023, zeros(1,1024),'r--');     % Normalized peak (0 dB)
plot(0:1023, -62.*ones(1,1024),'r--'); % Noise floor level
ylabel('dB Magnitude','fontsize',12,'fontweight','b');
title('62 dB Noise Floor: 12-bit CORDICSIN; N=10',...
    'fontsize',12,'fontweight','b');
% axis([0 1023 -120 0]); full FFT
axis([0 round(1024*(pi/8)) -100 10]); % zoom in
set(gca,'XTick',[0 round(1024*pi/16) round(1024*pi/8)]);
set(gca,'XTickLabel',{'0','pi/16','pi/8'});

Ускорение работы с фиксированной точкой CORDICSINCOS Функция с FIACCEL

Функцию MEX можно создать из кода MATLAB с помощью функции fiaccel MATLAB ®. Как правило, выполнение сгенерированной функции MEX может улучшить скорость моделирования, хотя фактическое улучшение скорости зависит от используемой платформы моделирования. В следующем примере показано, как ускорить работу с фиксированной точкойcordicsincos функция с использованием fiaccel.

fiaccel функция компилирует код MATLAB в функцию MEX. Этот шаг требует создания временного каталога и разрешений на запись в этом каталоге.

tempdirObj = fidemo.fiTempdir('fi_sin_cos_demo');

При объявлении числа итераций константой (например, 10) с использованием coder.newtype('constant',10)скомпилированная таблица ракурса также будет постоянной и, таким образом, не будет вычисляться в каждой итерации. Кроме того, при звонке cordicsincos_mex, вам не нужно будет давать ему входной аргумент для числа итераций. При передаче числа итераций MEX-функция будет иметь ошибку.

Тип данных входных параметров определяет, cordicsincos выполняет вычисления с фиксированной или плавающей запятой. Когда MATLAB генерирует код для этого файла, код создается только для определенного типа данных. Например, если входной аргумент THETA является фиксированной точкой, то генерируется только код с фиксированной точкой.

inp = {thRadFxp, coder.newtype('constant',10)}; % example inputs for the function
fiaccel('cordicsincos', '-o', 'cordicsincos_mex',  '-args', inp)

Сначала вычислите синус и косинус, вызвав cordicsincos.

tstart = tic;
cordicsincos(thRadFxp,10);
telapsed_Mcordicsincos = toc(tstart);

Затем вычислите синус и косинус, вызвав MEX-функцию cordicsincos_mex.

cordicsincos_mex(thRadFxp); % load the MEX file
tstart = tic;
cordicsincos_mex(thRadFxp);
telapsed_MEXcordicsincos = toc(tstart);

Теперь сравните скорость. Введите в командной строке MATLAB следующее, чтобы увидеть улучшение скорости на вашей платформе:

fiaccel_speedup = telapsed_Mcordicsincos/telapsed_MEXcordicsincos;

Для очистки временного каталога выполните следующие команды:

clear cordicsincos_mex;
status = tempdirObj.cleanUp;

Вычисление SIN и COS Использование таблиц подстановки

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

Подход на основе одной таблицы подстановки

sin и cos методы fi объект в конструкторе фиксированных точек аппроксимирует плавающую точку построения MATLAB ®sin и cos с использованием табличного подхода поиска с простой линейной интерполяцией ближайшего соседа между значениями. Этот подход позволяет создать небольшую таблицу поиска с действительным значением и использует простую арифметику.

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

Общие сведения о таблице подстановки SIN и COS Внедрение

Размер и точность таблицы подстановки

Двумя важными конструктивными соображениями таблицы подстановки являются ее размер и точность. Невозможно создать таблицу для каждого возможного входного значения. $$ u $$Также невозможно быть полностью точным из-за квантования$$ sin(u) $$ или $$ cos(u) $$поиска значений таблицы.

В качестве компромисса конструктор фиксированных точек SIN и COS методы FI использовать 8-битную таблицу поиска как часть их реализации. 8-битная таблица имеет длину всего 256 элементов, поэтому она мала и эффективна. Восемь битов также соответствует размеру байта или слова на многих платформах. Используемая в сочетании с линейной интерполяцией и 16-битовой точностью выходного сигнала (значение таблицы поиска), 8-битовая адресуемая таблица поиска обеспечивает как очень хорошую точность, так и производительность.

Инициализация константы SIN Значения таблицы подстановки

Для простоты реализации, однородности значений таблицы и скорости используется таблица с полным синевавом. Во-первых, четверть волны SIN функция дискретизируется через 64 однородных интервала в диапазоне [0, пи/2) радиан. Выбор подписанного 16-разрядного дробного типа данных с фиксированной точкой для значений таблицы, т.е. tblValsNT = numerictype(1,16,15), обеспечивает наилучшие результаты точности в SIN диапазон выходных данных [-1.0, 1.0). Значения предварительно квантуются до их установки, чтобы избежать предупреждений о переполнении.

tblValsNT = numerictype(1,16,15);
quarterSinDblFltPtVals  = (sin(2*pi*((0:63) ./ 256)))';
endpointQuantized_Plus1 = 1.0 - double(eps(fi(0,tblValsNT)));

halfSinWaveDblFltPtVals = ...
    [quarterSinDblFltPtVals; ...
    endpointQuantized_Plus1; ...
    flipud(quarterSinDblFltPtVals(2:end))];

fullSinWaveDblFltPtVals = ...
    [halfSinWaveDblFltPtVals; -halfSinWaveDblFltPtVals];

FI_SIN_LUT = fi(fullSinWaveDblFltPtVals, tblValsNT);

Обзор реализации алгоритма

Внедрение Fixed-Point Designer sin и cos методы fi объекты включают в себя сначала отбрасывание вводов углов с фиксированной точкой$$ u $$ (в радианах) на предварительно определенный тип данных в диапазоне [0, 2pi]. Для этого выполняют операцию по модулю 2pi для получения входного значения фиксированной точки inpValInRange в диапазоне [0, 2pi] и приведение к лучшей точности двоичной точки с масштабированием без знака 16-разрядного типа фиксированной точки numerictype(0,16,13):

% Best UNSIGNED type for real-world value range [0,  2*pi],
% which maps to fixed-point stored integer vals [0, 51472].
inpInRangeNT = numerictype(0,16,13);

Затем мы получаем 16-битное сохраненное беззнаковое целое значение из этого значения угла FI с фиксированной точкой в диапазоне:

idxUFIX16 = fi(storedInteger(inpValInRange), numerictype(0,16,0));

Мы умножаем сохраненное целое значение на константу нормализации, 65536/51472. Результирующее целое значение будет находиться в полноразмерном диапазоне индексов uint16:

normConst_NT = numerictype(0,32,31);
normConstant = fi(65536/51472, normConst_NT);
fullScaleIdx = normConstant * idxUFIX16;
idxUFIX16(:) = fullScaleIdx;

8 старших битов (MSB) этого полноразмерного 16-битного индекса без знака idxUFIX16 используются для прямого индексирования в 8-битную таблицу поиска синусов. Выполняется два поиска в таблице, один в вычисленном местоположении индекса таблицы. lutValBelow, и один в следующей позиции индекса lutValAbove:

idxUint8MSBs = storedInteger(bitsliceget(idxUFIX16, 16, 9));
zeroBasedIdx = int16(idxUint8MSBs);
lutValBelow  = FI_SIN_LUT(zeroBasedIdx + 1);
lutValAbove  = FI_SIN_LUT(zeroBasedIdx + 2);

Остальные 8 младших битов (LSB) idxUFIX16 используются для интерполяции между этими двумя табличными значениями. Значения LSB рассматриваются как нормированный масштабный коэффициент с 8-битовым дробным типом данных rFracNT:

rFracNT      = numerictype(0,8,8); % fractional remainder data type
idxFrac8LSBs = reinterpretcast(bitsliceget(idxUFIX16,8,1), rFracNT);
rFraction    = idxFrac8LSBs;

Действительное умножение используется для определения взвешенной разницы между двумя точками. Это приводит к простому вычислению (эквивалентному одному произведению и двум суммам) для получения интерполированного результата синуса с фиксированной точкой:

temp = rFraction * (lutValAbove - lutValBelow);
rslt = lutValBelow + temp;

Пример

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

% Use an arbitrary input value (e.g., 0.425 radians)
inpInRangeNT  = numerictype(0,16,13);    % best precision, [0, 2*pi] radians
inpValInRange = fi(0.425, inpInRangeNT); % arbitrary fixed-point input angle

% Normalize its stored integer to get full-scale unsigned 16-bit integer index
idxUFIX16     = fi(storedInteger(inpValInRange), numerictype(0,16,0));
normConst_NT  = numerictype(0,32,31);
normConstant  = fi(65536/51472, normConst_NT);
fullScaleIdx  = normConstant * idxUFIX16;
idxUFIX16(:)  = fullScaleIdx;

% Do two table lookups using unsigned 8-bit integer index (i.e., 8 MSBs)
idxUint8MSBs  = storedInteger(bitsliceget(idxUFIX16, 16, 9));
zeroBasedIdx  = int16(idxUint8MSBs);          % zero-based table index value
lutValBelow   = FI_SIN_LUT(zeroBasedIdx + 1); % 1st table lookup value
lutValAbove   = FI_SIN_LUT(zeroBasedIdx + 2); % 2nd table lookup value

% Do nearest-neighbor interpolation using 8 LSBs (treat as fractional remainder)
rFracNT       = numerictype(0,8,8); % fractional remainder data type
idxFrac8LSBs  = reinterpretcast(bitsliceget(idxUFIX16,8,1), rFracNT);
rFraction     = idxFrac8LSBs; % fractional value for linear interpolation
temp          = rFraction * (lutValAbove - lutValBelow);
rslt          = lutValBelow + temp;

Вот график результатов алгоритма:

x_vals = 0:(pi/128):(pi/4);
xIdxLo = zeroBasedIdx - 1;
xIdxHi = zeroBasedIdx + 4;
figure; hold on; axis([x_vals(xIdxLo) x_vals(xIdxHi) 0.25 0.65]);
plot(x_vals(xIdxLo:xIdxHi), double(FI_SIN_LUT(xIdxLo:xIdxHi)), 'b^--');
plot([x_vals(zeroBasedIdx+1) x_vals(zeroBasedIdx+2)], ...
    [lutValBelow lutValAbove], 'k.'); % Closest values
plot(0.425, double(rslt), 'r*'); % Interpolated fixed-point result
plot(0.425, sin(0.425),   'gs'); % Double precision reference result
xlabel('X'); ylabel('SIN(X)');
lut_val_str = 'Fixed-point lookup table values';
near_str    = 'Two closest fixed-point LUT values';
interp_str  = 'Interpolated fixed-point result';
ref_str     = 'Double precision reference value';
legend(lut_val_str, near_str, interp_str, ref_str);
title('Fixed-Point Designer Lookup Table Based SIN with Linear Interpolation', ...
    'fontsize',12,'fontweight','b');

Вычисление синусоиды с фиксированной точкой с помощью SIN

Создание 1024 точек между [-2 * pi, 2 * pi)

stepSize = pi/256;
thRadDbl = (-2*pi):stepSize:(2*pi - stepSize); % double precision floating-point
thRadFxp = sfi(thRadDbl, 12); % signed, 12-bit fixed-point inputs

Сравнение результатов SIN с фиксированной точкой и результатов SIN с двойной точностью

fxpSinTh  = sin(thRadFxp); % fixed-point results
sinThRef  = sin(double(thRadFxp)); % reference results
errSinRef = sinThRef - double(fxpSinTh);
figure; hold on; axis([-2*pi 2*pi -1.25 1.25]);
plot(thRadFxp, sinThRef,  'b');
plot(thRadFxp, fxpSinTh,  'g');
plot(thRadFxp, errSinRef, 'r');
ylabel('sin(\Theta)','fontsize',12,'fontweight','b');
set(gca,'XTick',-2*pi:pi/2:2*pi);
set(gca,'XTickLabel',...
    {'-2*pi', '-3*pi/2', '-pi', '-pi/2', ...
    '0', 'pi/2', 'pi', '3*pi/2','2*pi'});
set(gca,'YTick',-1:0.5:1);
set(gca,'YTickLabel',{'-1.0','-0.5','0','0.5','1.0'});
ref_str = 'Reference: sin(double(\Theta))';
fxp_str = sprintf('16-bit Fixed-Point SIN with 12-bit Inputs');
err_str = sprintf('Error (max = %f)', max(abs(errSinRef)));
legend(ref_str, fxp_str, err_str);
title(fxp_str,'fontsize',12,'fontweight','b');

Вычислить ошибку LSB

figure;
fracLen = fxpSinTh.FractionLength;
plot(thRadFxp, abs(errSinRef) * pow2(fracLen));
set(gca,'XTick',-2*pi:pi/2:2*pi);
set(gca,'XTickLabel',...
    {'-2*pi', '-3*pi/2', '-pi', '-pi/2', ...
    '0', 'pi/2', 'pi', '3*pi/2','2*pi'});
ylabel(sprintf('LSB Error: 1 LSB = 2^{-%d}',fracLen),'fontsize',12,'fontweight','b');
title('LSB Error: 16-bit Fixed-Point SIN with 12-bit Inputs','fontsize',12,'fontweight','b');
axis([-2*pi 2*pi 0 8]);

Вычислить уровень шума

fft_mag = abs(fft(double(fxpSinTh)));
max_mag = max(fft_mag);
mag_db  = 20*log10(fft_mag/max_mag);
figure;
hold on;
plot(0:1023, mag_db);
plot(0:1023, zeros(1,1024),'r--');     % Normalized peak (0 dB)
plot(0:1023, -64.*ones(1,1024),'r--'); % Noise floor level (dB)
ylabel('dB Magnitude','fontsize',12,'fontweight','b');
title('64 dB Noise Floor: 16-bit Fixed-Point SIN with 12-bit Inputs',...
    'fontsize',12,'fontweight','b');
% axis([0 1023 -120 0]); full FFT
axis([0 round(1024*(pi/8)) -100 10]); % zoom in
set(gca,'XTick',[0 round(1024*pi/16) round(1024*pi/8)]);
set(gca,'XTickLabel',{'0','pi/16','pi/8'});

Сравнение затрат на алгоритмы аппроксимации с фиксированной точкой

Алгоритм CORDIC с фиксированной точкой требует выполнения следующих операций:

  • 1 поиск в таблице за одну итерацию

  • 2 сдвига на итерацию

  • 3 добавления на одну итерацию

Упрощенный алгоритм одиночной таблицы подстановки с линейной интерполяцией ближайшего соседа требует выполнения следующих операций:

  • 2 поиска в таблице

  • 1 умножение

  • 2 дополнения

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

close all; % close all figure windows

Ссылки

  1. Jack E. Volder, The CORDIC Trigonometric Computing Technique, IRE Transactions on Electronic Computers, том EC-8, сентябрь 1959, pp330-334.

  2. Рэй Андрака, обзор алгоритма CORDIC для компьютеров на основе FPGA, Труды ACM/SIGDA 1998 года шестой международный симпозиум по полевым программируемым матрицам затворов, 22-24 февраля 1998 года, pp191-200