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

Поиск часто встречающихся элементов в массиве VHDL

Вот моя наброска самой простой реализации (не проверял, но логически вроде верно) - на вход поставить паралельно-последовательный конвертор, чтобы на вход моего модуля данные (Ваши 25 чисел) приходили последовательно)

 

library ieee;
use ieee.std_logic_1164.all;
library work;    

package Const_type is

type my_array is array (0 to 255) of std_logic_vector (7 downto 0);

end package;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
USE ieee.numeric_std.ALL;
use work.Const_type.all;

entity hist is

Port ( 
CLK : in std_logic;
rst : in std_logic;
indata : in  std_logic_vector (7 downto 0);

ready : out std_logic;
outdata : out std_logic_vector (7 downto 0);

 );
end hist;

architecture behavioral of hist is

signal table_index  :  my_array;
signal reg_data : std_logic_vector (7 downto 0);
signal reg_index : std_logic_vector (7 downto 0);
signal reg_state : std_logic_vector (1 downto 0);;

begin

process (all)
begin
if (rst = '1') then
	reg_index <= (OTHERS => (OTHERS => '0'));
	reg_state <=  (others => '0');
	reg_ready <= '0';
	reg_index <= (others => '0');
	reg_data <= (others => '0');
elsif (CLK'event and CLK ='1') then 
	if reg_state = "00" then -- read  data from table
		reg_data <= indata;
		reg_index <= table_index(to_integer(unsigned(indata)));
		reg_state <= std_logic_vector( unsigned(reg_state) + 1);
		reg_ready <= '0';
	
	elsif reg_state = "01" then -- calculation index
		reg_state <= std_logic_vector( unsigned(reg_state) + 1); 
		reg_index <= std_logic_vector( unsigned(reg_index) + 1);
	
	elsif reg_state = "10" then -- write new date to table 
		reg_state <= (OTHERS => '0'); 
		table_index (to_integer(unsigned(reg_data))) <= reg_index; 
		reg_ready <= '1';
	end if;
end if;	
end process;

outdata <= table_index (to_integer(unsigned(reg_data)));
ready <= reg_ready;

end behavioral;

Реализация простая есть так сказать 3 состояния/такта (reg_state). На каждом состоянии/такте происходит соотвующая операция:

1. чтение данных из таблицы;

2 инкремент индекса

3 запись нового значения индекса в таблицу

Далее все начинается сначала...

PS  Далее делаем второй модуль который сделать по сигналу ready сравнивает значение индексов (выход outdata) с предыдущим значение. Внутренний регистр в котором будет храниться максимальное число инициализируете максимальным числом (как то так reg_max <= (others => '1');)

 

не проверял - наброски...

library ieee;
use ieee.std_logic_1164.all;
library work;    

package Const_type is

type my_array is array (0 to 24) of std_logic_vector (7 downto 0);

end package;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
USE ieee.numeric_std.ALL;
use work.Const_type.all;

entity parallel2serial is
generic(
  num               : integer:= 25 );
port (
  i_clk                          : in  std_logic;
  i_rstb                         : in  std_logic;
  i_data_ena                     : in  std_logic;
  i_data                         : in  my_array;
  o_data_valid                   : out std_logic;
  o_data                         : out std_logic_vector (7 downto 0));
end parallel2serial;
architecture rtl of parallel2serial is
signal r_data                         : my_array;
signal r_count     : integer range 0 to (num-1);
begin

p_paralle2serial : process(all)
begin
  if(i_rstb='0') then
    r_count              <= 0;
  elsif(rising_edge(i_clk)) then
    if  i_data_ena = '1' then  
    	r_count        <= r_count + 1;
      	o_data          <= i_data(r_count);
	end if;
	  
	  if r_count = 24 then
		o_data_valid <= '1';
	  else
		o_data_valid <= '0';
	 end if;	
	  
  end if;
end process p_paralle2serial;

 

Будут вопросы спрашивайте :)

паралельная pipeline реализация займет больше ресурсов чем представленная последовательная реализация

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


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

2 ТС - у вас какая задача: найти самое часто встречаемое число, или число которое встречается более половины раз? Это как бы разные задачи :)

 

 

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


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

6 часов назад, MrGalaxy сказал:

Евгений Злыднев,

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

Синхронный if не предусматривает else. Разве Квартус на такую конструкцию не ругается? Вроде должен. :dash1:

Вам правильно посоветовали вычислить гистограмму. Я бы это сделал за один такт, т.к. входной массив уже заполнен (это тот случай, когда оператор цикла в ПЛИС уместен). За следующий такт проанализировал бы полученную гистограмму и выдал сигнал на выход. Длительность такта подобрал бы при симуляции.

И не стесняйтесь в коде писать комментарии, самому проще будет, как можно писать код без единого комментария! Else желательно писать под соответствующим then, т.е. с необходимым отступом, так код будет лучше читаться. Потом, когда проект отладите и будете ставить исходники на учёт в ОТД, подробные комментарии уберёте. :)

 

Вот цитата из статьи которую я привел. Она говорит почему  я не хочу таблицы. 

Цитата

 для словаря нам потребуется O(N) дополнительной памяти — в несколько раз больше размера исходного массива, и это при реализации словаря хоть хэш-таблицей, хоть деревом. Что будем делать, если наша цель — обработка сигнала неким устройством с маленькой памятью? Массив — замеры уровня сигнала, из которых один — «настоящий» передаваемый уровень, а остальные — шум и помехи. Неужели придётся для определения «настоящего» уровня возиться с хэш-таблицами и деревьями?

В несколько раз больше исходного массива это слишком. Мне нужно чтобы поменьше ресурсов тратить. 

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

2 ТС - у вас какая задача: найти самое часто встречаемое число, или число которое встречается более половины раз? Это как бы разные задачи :)

 

 

Самое часто встречаемое и в тоже время больше половины раз. Т.е из 13 из 25 если встретилось то это оно. Если даже 12 из 25, то выдавать нули. 

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

Вот моя наброска самой простой реализации (не проверял, но логически вроде верно) - на вход поставить паралельно-последовательный конвертор, чтобы на вход моего модуля данные (Ваши 25 чисел) приходили последовательно)

 


library ieee;
use ieee.std_logic_1164.all;
library work;    

package Const_type is

type my_array is array (0 to 255) of std_logic_vector (7 downto 0);

end package;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
USE ieee.numeric_std.ALL;
use work.Const_type.all;

entity hist is

Port ( 
CLK : in std_logic;
rst : in std_logic;
indata : in  std_logic_vector (7 downto 0);

ready : out std_logic;
outdata : out std_logic_vector (7 downto 0);

 );
end hist;

architecture behavioral of hist is

signal table_index  :  my_array;
signal reg_data : std_logic_vector (7 downto 0);
signal reg_index : std_logic_vector (7 downto 0);
signal reg_state : std_logic_vector (1 downto 0);;

begin

process (all)
begin
if (rst = '1') then
	reg_index <= (OTHERS => (OTHERS => '0'));
	reg_state <=  (others => '0');
	reg_ready <= '0';
	reg_index <= (others => '0');
	reg_data <= (others => '0');
elsif (CLK'event and CLK ='1') then 
	if reg_state = "00" then -- read  data from table
		reg_data <= indata;
		reg_index <= table_index(to_integer(unsigned(indata)));
		reg_state <= std_logic_vector( unsigned(reg_state) + 1);
		reg_ready <= '0';
	
	elsif reg_state = "01" then -- calculation index
		reg_state <= std_logic_vector( unsigned(reg_state) + 1); 
		reg_index <= std_logic_vector( unsigned(reg_index) + 1);
	
	elsif reg_state = "10" then -- write new date to table 
		reg_state <= (OTHERS => '0'); 
		table_index (to_integer(unsigned(reg_data))) <= reg_index; 
		reg_ready <= '1';
	end if;
end if;	
end process;

outdata <= table_index (to_integer(unsigned(reg_data)));
ready <= reg_ready;

end behavioral;

Реализация простая есть так сказать 3 состояния/такта (reg_state). На каждом состоянии/такте происходит соотвующая операция:

1. чтение данных из таблицы;

2 инкремент индекса

3 запись нового значения индекса в таблицу

Далее все начинается сначала...

PS  Далее делаем второй модуль который сделать по сигналу ready сравнивает значение индексов (выход outdata) с предыдущим значение. Внутренний регистр в котором будет храниться максимальное число инициализируете максимальным числом (как то так reg_max <= (others => '1');)

 


не проверял - наброски...

library ieee;
use ieee.std_logic_1164.all;
library work;    

package Const_type is

type my_array is array (0 to 24) of std_logic_vector (7 downto 0);

end package;

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
USE ieee.numeric_std.ALL;
use work.Const_type.all;

entity parallel2serial is
generic(
  num               : integer:= 25 );
port (
  i_clk                          : in  std_logic;
  i_rstb                         : in  std_logic;
  i_data_ena                     : in  std_logic;
  i_data                         : in  my_array;
  o_data_valid                   : out std_logic;
  o_data                         : out std_logic_vector (7 downto 0));
end parallel2serial;
architecture rtl of parallel2serial is
signal r_data                         : my_array;
signal r_count     : integer range 0 to (num-1);
begin

p_paralle2serial : process(all)
begin
  if(i_rstb='0') then
    r_count              <= 0;
  elsif(rising_edge(i_clk)) then
    if  i_data_ena = '1' then  
    	r_count        <= r_count + 1;
      	o_data          <= i_data(r_count);
	end if;
	  
	  if r_count = 24 then
		o_data_valid <= '1';
	  else
		o_data_valid <= '0';
	 end if;	
	  
  end if;
end process p_paralle2serial;

 

Будут вопросы спрашивайте :)

паралельная pipeline реализация займет больше ресурсов чем представленная последовательная реализация

Я обязательно попробую ваш вариант. Хотя бы для сравнения с моим. Спасибо. 

Изменено пользователем ЕвгенийЗлыднев

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


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

 
 
 
 
36 minutes ago, ЕвгенийЗлыднев said:

Я обязательно попробую ваш вариант. Хотя бы для сравнения с моим. Спасибо. 

 

Спасибо, отпишитесь пожалуйста по результатам реализации

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


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

17 часов назад, RobFPGA сказал:

Приветствую!

Основная ошибка в неправильном алгоритме  который вы пытаетесь  повторить. Даже у меня не получится реализовать неправильный алгоритм :unknw: У вас какое условие?

 Как понять что число  "наиболее часто встречается" - естественно надо посчитать эти встречи (вот вам и обьяснение, "а при чем тут гистограммы". А так как какое конкретное число нам будет встречаться мы не знаем то хорошо бы иметь  свой счетчик для каждого возможного значение числа.  Вот вам и таблица на 256x5.

 Ну а дальше начинаем оптимизировать по условиям задачи - ограничение длины последовательности и конкретный порог превышения дают нам уверенность что таких счетчиков достаточно  будет (длина порог)+1 (намекну - что если первые 13 чисел у вас будут все разные? ). 

Удачи! Rob.

Что касается не правильного исходного алгоритма то я попробовал на Матлабе его реализовать.  У меня все  работает как надо. Но на плис не хочет это синтезировать. 

a1 = [46,46,46,46,46,46,46,46,46,46,46,46,46,11,10,9,8,7,6,5,4,3,2,1,0]; %массив
conf = 0;% начальное значение и  количество, не нашедших пары и оставшихся "стоять"
candidate = 1; %начальное значение "кандидата"
b = randsample(a1,25);% перемещиваем исходный массив 
for i=1:length(b)% начинаем алгоритм поиска наиболее частого значения в массиве
    if (conf == 0) % если нет "одиноких" чисел, то присваеиваем значение текущего "одинокому"
       candidate = b(i);
       conf=conf+1;
    elseif candidate == b(i)% если есть "одинокие", то сравниваем рядом стоящие
        conf=conf+1; 
    else 
        conf=conf-1;
    end
    conf
    candidate
end

А можете по коду еще посмотреть в чем может быть ошибка? может с индексами что не так? или из-за того что я i и j ограничил по разрядности? Вчера к сожалению не тот снимок привел. Вот более подробная диаграмма.

Опишу алгоритм подробнее: 

1) По уровню "1" на сигнале Go начинаем сортировать. Когда все по нулям просто увеличиваем счетчики i и j на 1. Значение ibn записываем в регистр temp.

2) Далее, сравниваем предыдущий элемент со следующим. Если равны  то увеличиваем значение j и также в temp перезаписываем значение которое там уже есть. Если не равны то уменьшаем j и переписываем значение ibn(i+1) в temp.  Каждое сравнение это один такт, i увеличиваем каждый такт.

3) Когда алгоритм отработал (i=24)  если j больше нуля то записываем в регистр nomer данные из регистра temp. Если j больше нуля то записываем нули (у меня в коде 1, это для эксперимента было). Когда алгоритм отработал он ставит сигнал done в единицу. 

После этого возникают вопросы:  Почему I не с нуля стартует, а с 3. И  то увеличивается, то уменьшается. Хотя я четко обозначил что на каждом шагу она должна только увеличиваться.    Почему номер не выдается как нужно? 

Кто-то может просто повторить это алгоритм? Был бы очень признателен. Он очень ведь компактный. Всего несколько строк. Видео урок как это подобное реализуется в учебнике и примеры я выложил. Там вроде все доступно. Если честно не думал, что вызовет столько затруднений мой пример у людей.

Снимок работы частых элементов.JPG

 

Что касается других вариантов и  алгоритмов то это круто  что столько отзывов последовало. Но у меня уже какой-то азарт реализовать это алгоритм,  Потому что учебные примеры так легко получились, и так ясно работают что мне как-то обидно за себя что я не могу простейший алгоритм реализовать. Хотя вся информация уже есть, и видео уроки и учебник (( Если получатся несколько вариантов то я хоть сравню их. И выберу лучший, так даже более правильно будет. Если что для другого случая применю потом. Я все компоненты свои сохраняю, и потом как типовые использую. Просто меняю разрядность и т.п. Так что несколько вариантов лишними не будут. 

Изменено пользователем ЕвгенийЗлыднев

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


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

Приветствую!

7 minutes ago, ЕвгенийЗлыднев said:

Что касается не правильного исходного алгоритма то я попробовал на Матлабе его реализовать.  У меня все  работает как надо.

А ежики такие упорные ... :smile:  Этот алгоритм работает только когда вы ТОЧНО знаете что у вас во входном массиве ЕСТЬ >=N/2+1 одинаковых чисел. А по вашему входному условию вы этого не знаете.  Я же предлагал оценить работу этого алгоритма для длины 3. Ведь алгоритм от этого не меняется. 

Удачи! Rob.

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


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

22 минуты назад, RobFPGA сказал:

Приветствую!

А ежики такие упорные ... :smile:  Этот алгоритм работает только когда вы ТОЧНО знаете что у вас во входном массиве ЕСТЬ >=N/2+1 одинаковых чисел. А по вашему входному условию вы этого не знаете.  Я же предлагал оценить работу этого алгоритма для длины 3. Ведь алгоритм от этого не меняется. 

Удачи! Rob.

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

int* majority(int[] array, int N) {
  int confidence = 0; // количество людей, не нашедших пары и оставшихся стоять
  int* candidate = NULL; // последний человек, не нашедший пару -- 
                         // возможно, его элемент встречается чаще всего

  // проходим по массиву и усаживаем пары с разными элементами
  for (int i = 0; i<N; i++) {

    // если до сих пор все сидят, то следующему пока придётся постоять
    if (confidence == 0) {
      candidate = array+i;
      confidence++;
    }

    // иначе следующий либо садится с одним из стоящих,
    // либо будет стоять вместе с ними, если у него такой же элемент
    else if (*candidate == array[i])) 
      confidence++;
    else 
      confidence--;
  }

  return confidence > 0 ? candidate : NULL;
}

В исходном алгоритме в последней строке возвращается candidate, если confidence больше нуля. А если меньше то NULL возращает. 

У меня  там же есть условие что j должно быть больше 0. j аналог confidence. Т.е вроде все соблюдено.

Что такое длина 3 ? не совсем понял. 

Изменено пользователем ЕвгенийЗлыднев

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


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

Input: [1, 4, 3, 3, 2, 5]
Sum = 18 As in this example, we have n = 5:
Sum of 1 to 5 = 1 + 2 + 3 + 4 + 5 = 15=> 18 - 15 = 3 so 3 is the duplicate

но

 

Input: [1, 2, 3, 2, 3, 4]
Sum = 15As in this example we have n = 5,
Sum of 1 to 5 = 1 + 2 + 3 + 4 + 5 = 15/!\ Not working

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


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

17 минут назад, Maverick_ сказал:

Input: [1, 4, 3, 3, 2, 5]
Sum = 18 As in this example, we have n = 5:
Sum of 1 to 5 = 1 + 2 + 3 + 4 + 5 = 15=> 18 - 15 = 3 so 3 is the duplicate

то есть надо просто сложить все числа входные и вычесть их из константы 1+2+3+...225? и получим результат?

 

Не увидел ваших замечаний, и проверил сразу в матлабе. не работает алгоритм если как и вашем примере  сумма элементов меньше.  

Изменено пользователем ЕвгенийЗлыднев

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


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

Приветствую!

27 minutes ago, ЕвгенийЗлыднев said:

Что такое длина 3 ? не совсем понял. 

Поведение алгоритма не должно меняться от размера массива. Ведь так? 

3 hours ago, RobFPGA said:

Проверьте этот же алгоритм для длинны 3 точки  (2 из 3)  Каков будет ответ для входных чисел 1,2,3  и 1,2,1 ?

Еще раз - В оригинальном описании этого  алгоритма говорится что если вы УЖЕ ЗНАЕТЕ что во входной последовательности есть N/2+1 одинаковых чисел то этот алгоритм выдаст это число. А вот если вы этого не знаете - то этот алгоритм выдаст  возможного кандидата на такое число И чтобы убедится что это число действительно встречается N/2+1 вам надо еще раз пройтись по массиву и посчитать число включений этого кандидата.  

13 minutes ago, Maverick_ said:

Input: [1, 4, 3, 3, 2, 5] Sum = 18 As in this example, we have n = 5: Sum of 1 to 5 = 1 + 2 + 3 + 4 + 5 = 15=> 18 - 15 = 3 so 3 is the duplicate

:shok:  Input: [1,4,3,3,2,7]   -> ?? 

Удачи! Rob.

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


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

7 минут назад, RobFPGA сказал:

Приветствую!

Поведение алгоритма не должно меняться от размера массива. Ведь так? 

Еще раз - В оригинальном описании этого  алгоритма говорится что если вы УЖЕ ЗНАЕТЕ что во входной последовательности есть N/2+1 одинаковых чисел то этот алгоритм выдаст это число. А вот если вы этого не знаете - то этот алгоритм выдаст  возможного кандидата на такое число И чтобы убедится что это число действительно встречается N/2+1 вам надо еще раз пройтись по массиву и посчитать число включений этого кандидата.  

:shok:  [1,4,3,3,2,7]   -> ?? 

Удачи! Rob.

Все понял про что вы :-) Про количество входных сигналов .

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

Изменено пользователем ЕвгенийЗлыднев

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


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

On 9/11/2019 at 4:16 PM, ЕвгенийЗлыднев said:

Есть 25 чисел, каждое 8 бит. Надо найти наиболее часто встречающиеся среди них т.е. если число встречается 13 и больше раз, это то что мы ищем.

Вот мой вариант решения:

#include "stdafx.h"

unsigned char src[25] = {46,46,46,46,46,46,46,46,46,46,46,46,46,11,10,9,8,7,6,5,4,3,2,1,0};

unsigned char bits;
unsigned char freq;

int _tmain(int argc, _TCHAR* argv[])
{
	int i,j;

	bits = 0;

	for (i = 0; i < 8; i++)
	{
		freq = 0;

		for (j = 0; j < 25; j++)
		{
			freq += (src[j] >> i) & 1;
		}
	
		if (freq > 12) bits |= (1 << i);
	}

	freq = 0;
	
	for (j = 0; j < 25; j++) if (bits == src[j]) freq++;

	if (freq > 12) printf("Most frequent src = %d",bits);
	else printf("Most frequent src not found!");

	return 0;
}

За три такта на верилоге можно посчитать, КМК.. :)

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


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

13 минут назад, blackfin сказал:

Вот мой вариант решения:


#include "stdafx.h"

unsigned char src[25] = {46,46,46,46,46,46,46,46,46,46,46,46,46,11,10,9,8,7,6,5,4,3,2,1,0};

unsigned char bits;
unsigned char freq;

int _tmain(int argc, _TCHAR* argv[])
{
	int i,j;

	bits = 0;

	for (i = 0; i < 8; i++)
	{
		freq = 0;

		for (j = 0; j < 25; j++)
		{
			freq += (src[j] >> i) & 1;
		}
	
		if (freq > 12) bits |= (1 << i);
	}

	freq = 0;
	
	for (j = 0; j < 25; j++) if (bits == src[j]) freq++;

	if (freq > 12) printf("Most frequent src = %d",bits);
	else printf("Most frequent src not found!");

	return 0;
}

За три такта на верилоге можно посчитать, КМК.. :)

К сожалению, не всегда как видно можно даже простые алгоритмы на Плис реализовать. Хоть за 3 такта хоть за 25. Поэтому ваш потом попробую написать. 

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


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

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

Подсказка: для конкретно этого случая стек на 13 "адресов".

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


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

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

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

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

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

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

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

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

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

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