Этот пример показывает, как выполнить основные операции вычислений с фиксированной точкой.
Сохраните предупреждение состояний перед началом.
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
и 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
с тем же 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
Обратите внимание на то, что в C, результат операции между целочисленным типом данных и двойным типом данных продвигает двойное.
Однако в MATLAB, результатом операции между встроенным целочисленным типом данных и двойным типом данных является целое число. В этом отношении объект fi
ведет себя как встроенные целочисленные типы данных в MATLAB. Результатом операции между fi
и двойным является fi
.
При выполнении арифметики между 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>