Выполните вычисления с фиксированной точкой

Этот пример показывает, как выполнить основные операции вычислений с фиксированной точкой.

Сохраните предупреждение состояний перед началом.

warnstate = warning;

Сложение и вычитание

Каждый раз, когда вы добавляете два числа фиксированной точки без знака, вам, возможно, понадобится бит переноса, чтобы правильно представлять результат. Поэтому при добавлении двух чисел B-бита (с тем же масштабированием), получившееся значение имеет дополнительный бит по сравнению с этими двумя используемыми операндами.

a = ufi(0.234375,4,6);
c = a + a
c = 

    0.4688

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Unsigned
            WordLength: 5
        FractionLength: 6
a.bin
ans =

    '1111'

c.bin
ans =

    '11110'

С two's-дополнительными числами со знаком подобный сценарий происходит из-за расширения знака, требуемого правильно представлять результат.

a = sfi(0.078125,4,6);
b = sfi(-0.125,4,6);
c = a + b
c = 

   -0.0469

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 5
        FractionLength: 6
a.bin
ans =

    '0101'

b.bin
ans =

    '1000'

c.bin
ans =

    '11101'

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

a = sfi(pi,16,13);
b = sfi(0.1,12,14);
c = a + b
c = 

    3.2416

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 18
        FractionLength: 14

Дальнейшие факторы для сложения и вычитания

Обратите внимание на то, что следующий шаблон не рекомендуется. Поскольку скалярные сложения выполняются в каждой итерации в цикле for, немного добавляется, чтобы работать временно во время каждой итерации. В результате вместо перекрытия (log2 (Nadds)) рост разрядности, рост разрядности равен Nadds.

s = rng; rng('default');
b = sfi(4*rand(16,1)-2,32,30);
rng(s); % restore RNG state
Nadds = length(b) - 1;
temp  = b(1);
for n = 1:Nadds
    temp = temp + b(n+1); % temp has 15 more bits than b
end

Если команда sum используется вместо этого, рост разрядности обуздан как ожидалось.

c = sum(b) % c has 4 more bits than b
c = 

    7.0059

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 36
        FractionLength: 30

Умножение

В целом продукт полной точности требует размера слова, равного сумме размеров слова операндов. В следующем примере обратите внимание, что размер слова продукта c равен размеру слова a плюс размер слова b. Дробная длина c также равна дробной длине a плюс дробная длина b.

a = sfi(pi,20);
b = sfi(exp(1),16);
c = a * b
c = 

    8.5397

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 36
        FractionLength: 30

“()” Присвоение

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

N = 10;
a = sfi(2*rand(N,1)-1,16,15);
b = sfi(2*rand(N,1)-1,16,15);
c = sfi(zeros(N,1),16,14);
for n = 1:N
    c(n) = a(n).*b(n);
end

Обратите внимание на то, что, когда продукт, a(n).*b(n) вычисляется с полной точностью, промежуточным результатом с wordlength 32 и дробной длиной 30, сгенерирован. Тот результат затем квантуется к wordlength 16 и дробной длине 14, как объяснено выше. Квантованное значение затем присвоено элементу c(n).

Квантование результатов явным образом

Часто, это не желательно к раунду к самому близкому или насыщать при квантовании результата из-за дополнительной требуемой логики/вычисления. Это также может быть нежелательный, чтобы должным быть присвоить значению левой стороны, чтобы выполнить квантование. Можно использовать QUANTIZE в таких целях. Общий падеж является обратной связью. Если никакое квантование не будет введено, неограниченный рост разрядности произойдет, когда больше входных данных обеспечивается.

a = sfi(0.1,16,18);
x = sfi(2*rand(128,1)-1,16,15);
y = sfi(zeros(size(x)),16,14);
for n = 1:length(x)
    z    = y(n);
    y(n) = x(n) - quantize(a.*z, true, 16, 14, 'Floor', 'Wrap');
end

В этом примере продукт a.*z вычисляется с полной точностью и впоследствии квантуется к wordlength 16 битов и дробной длине 14. Квантование сделано путем округления, чтобы поставить в тупик (усечение) и обеспечения переноса, если переполнение происходит. Квантование все еще происходит в присвоении, потому что выражение, x(n) - quantize(a.*z, ...) приводит к промежуточному результату 18 битов и y, задано, чтобы иметь 16 битов. Чтобы устранить квантование в присвоении, можно ввести дополнительное явное квантование как показано ниже. Преимущество выполнения этого состоит в том, что никакая round-to-nearest/saturation логика не используется. Результат левой стороны имеет тот же 16-битный wordlength и дробную длину 14 как y(n), таким образом, никакое квантование не необходимо.

a = sfi(0.1,16,18);
x = sfi(2*rand(128,1)-1,16,15);
y = sfi(zeros(size(x)),16,14);
T = numerictype(true, 16, 14);
for n = 1:length(x)
    z    = y(n);
    y(n) = quantize(x(n), T, 'Floor', 'Wrap') - ...
           quantize(a.*z, T, 'Floor', 'Wrap');
end

Суммы неполной точности

Суммы полной точности не всегда желательны. Например, 18-битное соответствие wordlength промежуточному результату, x(n) - quantize(...) выше может привести к сложному и неэффективному коду, если код С сгенерирован. Вместо этого может быть желательно сохранить все результаты сложения/вычитания к 16 битам. Можно использовать accumpos и функции accumneg с этой целью.

a = sfi(0.1,16,18);
x = sfi(2*rand(128,1)-1,16,15);
y = sfi(zeros(size(x)),16,14);
T = numerictype(true, 16, 14);
for n = 1:length(x)
    z    = y(n);
    y(n) = quantize(x(n), T);                 % defaults: 'Floor','Wrap'
    y(n) = accumneg(y(n), quantize(a.*z, T)); % defaults: 'Floor','Wrap'
end

Моделирование аккумуляторов

accumpos и accumneg являются подходящими к образцовым аккумуляторам. Поведение соответствует + = и - = операторы в C. Типичный пример является КИХ, просачиваются, который коэффициенты и входные данные представлены с 16 битами. Умножение выполняется в полной точности, приводя к 32 битам, и аккумуляторе с 8 "сторожевыми" разрядами, т.е. общее количество на 40 битов используется, чтобы включить до 256 накоплений без возможности переполнения.

b = sfi(1/256*[1:128,128:-1:1],16); % Filter coefficients
x = sfi(2*rand(300,1)-1,16,15);     % Input data
z = sfi(zeros(256,1),16,15);        % Used to store the states
y = sfi(zeros(size(x)),40,31);      % Initialize Output data
for n = 1:length(x)
    acc = sfi(0,40,31); % Reset accumulator
    z(1) = x(n);        % Load input sample
    for k = 1:length(b)
        acc = accumpos(acc,b(k).*z(k)); % Multiply and accumulate
    end
    z(2:end) = z(1:end-1); % Update states
    y(n) = acc;            % Assign output
end

Матричная арифметика

Чтобы упростить синтаксис и сократить время симуляции, можно использовать матричную арифметику. Поскольку КИХ фильтрует пример, можно заменить внутренний цикл на скалярное произведение.

z = sfi(zeros(256,1),16,15); % Used to store the states
y = sfi(zeros(size(x)),40,31);
for n = 1:length(x)
    z(1) = x(n);
    y(n) = b*z;
    z(2:end) = z(1:end-1);
end

Скалярное произведение b*z выполняется с полной точностью. Поскольку это - операция над матрицей, рост разрядности происходит и из-за включенного умножения и из-за сложения получившихся продуктов. Поэтому рост разрядности зависит от длины операндов. Поскольку b и z имеют длину 256, который составляет 8-битный рост из-за сложений. Поэтому скалярное произведение приводит к 32 + 8 = 40 битов (с дробной длиной 31). Поскольку это - формат, к которому инициализируется y, никакое квантование не происходит в присвоении y(n) = b*z.

Если бы необходимо было выполнить скалярное произведение больше чем для 256 коэффициентов, рост разрядности составил бы больше чем 8 битов вне этих 32, необходимых для продукта. Если бы у вас только был 40-битный аккумулятор, вы могли бы смоделировать поведение или представлением квантизатора, как в y(n) = quantize(Q,b*z), или вы могли использовать функцию accumpos, как был показан.

Моделирование счетчика

accumpos может использоваться, чтобы смоделировать простой счетчик, который естественно переносится после достижения его максимального значения. Например, можно смоделировать 3-битный счетчик можно следующим образом.

c = ufi(0,3,0);
Ncounts = 20; % Number of times to count
for n = 1:Ncounts
    c = accumpos(c,1);
end

Поскольку 3-битный счетчик естественно переносится назад к 0 после достижения 7, окончательное значение счетчика ультрасовременно (20,8) = 4.

Математика с другими встроенными типами данных

FI * ДВАЖДЫ

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

a = fi(pi);
b = 0.5 * a
b = 

    1.5708

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 32
        FractionLength: 28

FI + DOUBLE или FI - DOUBLE

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

Это поведение fi + double, измененный в R2012b. Можно выключить предупреждение несовместимости путем ввода следующей команды предупреждения.

warning off fixed:incompatibility:fi:behaviorChangeHeterogeneousMathOperationRules
a = fi(pi);
b = a + 1
b = 

    4.1416

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 17
        FractionLength: 13

Некоторые различия между MATLAB® и C

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

Однако в MATLAB, результатом операции между встроенным целочисленным типом данных и двойным типом данных является целое число. В этом отношении объект fi ведет себя как встроенные целочисленные типы данных в MATLAB. Результатом операции между fi и двойным является fi.

FI * INT8

При выполнении арифметики между fi и одним из встроенных целочисленных типов данных [u] int [8,16,32], сохраняется размер слова и со знаком из целого числа. Результатом операции является fi.

a = fi(pi);
b = int8(2) * a
b = 

    6.2832

          DataTypeMode: Fixed-point: binary point scaling
            Signedness: Signed
            WordLength: 24
        FractionLength: 13

Восстановите предупреждение состояний.

warning(warnstate);
%#ok<*NASGU,*NOPTS>