Перейти к содержанию
    

Неправильное вычисление среднего значения.

Также можете поискать готовые модули в инете, например MavericDes00, Verilog,  и куча других похожих модулей по запросу "деление чисел плис site:electronix.ru"

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, MrGalaxy сказал:

Я с кодом до конца не разобрался, мозг закипел от бесконечных  STD_LOGIC_VECTOR, :wacko2: и ни одного комментария. :unknw:

Кто Вам запрещает? Если в итоге непременно нужен std_logic_vector, делаете арифметику в отдельном блоке и передаёте в другой блок. Шина одна и та же. Повысится наглядность кода, а это много стоит.

Деление на 2 синтезируется как сдвиг. То, что Вы явно в коде укажете сдвиг, ничего в плане быстродействия или экономии ресурсов не даст. (Про Xilinx не скажу, а Квартус синтезирует именно так).

 

Так и двигать не надо ничего. Просто отбрасывайте ненужные разряды и все. Эта операция не требует ресурсов FPGA.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 минут назад, Flip-fl0p сказал:

Так и двигать не надо ничего. Просто отбрасывайте ненужные разряды и все. Эта операция не требует ресурсов FPGA.

Можно и так, если устраивает погрешность в 1 мл. разряд. Если надо 1/2 мл.разряда, то такая халява не прокатит.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 минуты назад, MrGalaxy сказал:

Можно и так, если устраивает погрешность в 1 мл. разряд. Если надо 1/2 мл.разряда, то такая халява не прокатит.

Не понял Вас. 

Если мы работаем в fixed point то погрешность неизбежна.

Например найти Ср. арифм. 3 + 3 + 3 + 2. Ср. арифм. = 11/4=2,75.

При сдвиге мы отбросим 0,75.

Можно конечно анализировать дробную часть и если она меньше чем 0.5 то обрезать. Если больше чем 0,5 то к полученному результату добавлять 1, т.е нашу двойку округлять до 3. Но это имеет смысл только при очень низких значениях результата, когда порядки значений маленькие.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 минуту назад, Flip-fl0p сказал:

Можно конечно анализировать дробную часть и если она меньше чем 0.5 то обрезать. Если больше чем 0,5 то к полученному результату добавлять 1, т.е нашу двойку округлять до 3.

Да, я это и имел в виду.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

16 hours ago, MrGalaxy said:

Я с кодом до конца не разобрался, мозг закипел от бесконечных  STD_LOGIC_VECTOR, :wacko2: и ни одного комментария. :unknw:

да причем здесь код) ТС забыл что деление проверяется умножением). Берем картинку делимое 0x2820 (10272), частное 0х11EB (4587). 

ТС взял калькулятор виндовз, поставил режим работы "программист" ввел делимое и частное в хекс формате, получил 2 (что естественно, т.к. 10272/4587 = 2.23)  и считает что он делит на два. Тогда как в школе учат проверять совсем по другому (хотя закончил школу очень давно, может что изменилось).

Делаем проверку умножением частного на делитель получаем результат 0x23D6(9174). ТС ищет черную кошку в темной комнате, которой там нет.

А должно быть вот так 10272(0x2820)/3 =  3424(0xD60), более того, это деление целочисленное(остаток от деления равен нулю) и более того, это правильно считается в режиме "программист" калькулятора виндовз.

Резюмирую

On 3/30/2020 at 8:07 PM, des00 said:

ЗЗЫ. 99.9% ошибка со времянкой в делителе 32-х битных чисел 

классическая ошибка всех кто в плис недавно. Деление больших чисел, на настоящем делителе(который в столбик, пишется минут за 5-10), за 1 такт(вывод судя по коду). Самый простой вариант проверки (ну кроме загнать в функциональный симмулятор, но ТС любит сразу в железе, по хардкорному, с сигналтапом подмышкой), сделать так

On 3/30/2020 at 8:22 PM, des00 said:

 ЗЫ. Просидите в состоянии деления тактов 5-6,  должно помочь. На будущее, не используйте вот такую реализацию вычисления среднего. Это не МК

 

14 hours ago, Flip-fl0p said:

Можно конечно анализировать дробную часть и если она меньше чем 0.5 то обрезать. Если больше чем 0,5 то к полученному результату добавлять 1, т.е нашу двойку округлять до 3. Но это имеет смысл только при очень низких значениях результата, когда порядки значений маленькие.

офтопик конечно, но, как показала моя практика, если округления вида floor(num/div) + sign(num) недостаточно, то на плисах лучше все же делать floor((num+0.5*div)/div). Варианты сложного постанализа по ресурсу занимают больше)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, des00 сказал:

на плисах лучше все же делать floor((num+0.5*div)/div)

Арифметика, вроде, целочисленная обсуждается. Или Вы про саму идею?

Я делаю так:

result <= num/div + (((num*2)/div) rem 2);

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Just now, MrGalaxy said:

Арифметика, вроде, целочисленная обсуждается. Или Вы про саму идею?

Я делаю так:

result <= num/div + (((num*2)/div) rem 2);

это офтопик в область идей округления, упомянули же. В вашей формуле не хватает floor ов) да и еще важный момент при округлении, необходимость блока ограничения при работе с числами с максимальным, для данной разрядности, значением. там требуется увеличить разрядность на 1 бит, потом ограничить и усечь разрядность. В общем нормальный round "дорогое" удовольствие на ПЛИС.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 минут назад, des00 сказал:

это офтопик

Предлагаю вынести в отдельную ветку.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

4 часа назад, des00 сказал:

10272/4587 = 2.23)  и считает что он делит на два.

Я не обратил на это внимания. Получается, что тупо не хватает быстродействия и действительно надо подождать лишние 2-3 такта?

4 часа назад, des00 сказал:

На будущее, не используйте вот такую реализацию вычисления среднего. Это не МК

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, MrGalaxy said:

Предлагаю вынести в отдельную ветку.

да где-то есть на форуме) лет 10 назад обсуждали активно)

40 minutes ago, MrGalaxy said:

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

возможно это поможет

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity moving_average is
generic (
  G_NBIT                     : integer := 8;
  G_AVG_LEN_LOG              : integer := 2 );
port (
  i_clk                      : in  std_logic;
  i_rstb                     : in  std_logic;
  i_sync_reset               : in  std_logic;
  -- input
  i_data_ena                 : in  std_logic;
  i_data                     : in  std_logic_vector(G_NBIT-1 downto 0);
  -- output
  o_data_valid               : out std_logic;
  o_data                     : out std_logic_vector(G_NBIT-1 downto 0));
end moving_average;

architecture rtl of moving_average is

type t_moving_average is array (0 to 2**G_AVG_LEN_LOG-1) of signed(G_NBIT-1 downto 0);

signal p_moving_average                 : t_moving_average;
signal r_acc                            : signed(G_NBIT+G_AVG_LEN_LOG-1 downto 0);  -- average accumulator
signal r_data_valid                     : std_logic;

begin

p_average : process(i_clk,i_rstb)
begin
  if(i_rstb='0') then
    r_acc              <= (others=>'0');
  p_moving_average   <= (others=>(others=>'0'));
  r_data_valid       <= '0';
  o_data_valid       <= '0';
  o_data             <= (others=>'0');
  elsif(rising_edge(i_clk)) then
  r_data_valid       <= i_data_ena;
  o_data_valid       <= r_data_valid;
  if(i_sync_reset='1') then
    r_acc              <= (others=>'0');
    p_moving_average   <= (others=>(others=>'0'));
  elsif(i_data_ena='1') then
    p_moving_average   <= signed(i_data)&p_moving_average(0 to p_moving_average'length-2);
    r_acc              <= r_acc + signed(i_data)-p_moving_average(p_moving_average'length-1);
  end if;
  o_data             <= std_logic_vector(r_acc(G_NBIT+G_AVG_LEN_LOG-1 downto G_AVG_LEN_LOG));  -- divide by 2^G_AVG_LEN_LOG
  
  end if;
end process p_average;

end rtl;

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, Maverick_ said:

возможно это поможет (если числа знаковые надо тип signed применять)

 

спасибо. а если у меня массив 18-битных значений - G_NBIT : integer := 18; ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 minute ago, jenya7 said:

спасибо. а если у меня массив 18-битных значений - G_NBIT : integer := 18; ?

да

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, Maverick_ said:

да

еще такой вопрос G_AVG_LEN_LOG : integer := 2 это на сколько значений будет вычисленно среднее значение?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...