Jump to content

    
Sign in to follow this  
gosha

Скользящее среднее

Recommended Posts

На входе - сигнал с постоянной состовляющей.

Необходимо получить усредненное значение сигнала (постоянную составляющую). 

Потеря точности НЕ допускается.

Частота дискретизации 30МГц. Период сигнала - от 1Гц до 200КГц

Как экономичнее на verilog реализовать фильтр скользящего среднего ?

Усредняем за время более периода младшей гармоники ?

`include "timescale.v"
/*===========================================================*/
module mean_filter(
    input               clk_i, /* 30.72MHz */
    input               rst_i,  
    input        [23:0] dat_i,   
    input               srst_i,       
    input               valid_i,
    output signed [23:0] dat_o,   
    output reg          valid_o        
    );
/*===========================================================*/    
reg         [14:0] addr_wr, addr_rd;
reg signed  [38:0] S;
reg                wr;    
wire signed [23:0] dat_m;
reg  signed [23:0] dat_average; 
/*===========================================================*/
assign dat_o= dat_average;
mem_24x65536 mem (.clk(clk_i), .a(addr_wr), .d(dat_i), .dpra(addr_rd), .we(wr), .dpo(dat_m));
/*===========================================================*/
always @(posedge clk_i or posedge rst_i)    
begin
if(rst_i)   
     {addr_wr, addr_rd, S, wr, dat_average, valid_o, decimate}<= 0;
else
    begin
    if(srst_i)
        {addr_wr, addr_rd, S, wr, dat_average, valid_o}<= 0;
    else
        begin
        if(&addr_wr)
            valid_o<= 1'b1;
        wr <= valid_i ;
        addr_rd<= addr_rd+ 1'b1;    
        if(valid_i)
            addr_wr<= addr_wr+ 1'b1;
        if(!addr_rd)
            begin
            S<= dat_m;
            dat_average<= S[38:15];
            end
        else
            S<= S + dat_m;   
        end   
    end
end         
/*===========================================================*/   
endmodule

 

Share this post


Link to post
Share on other sites
36 minutes ago, gosha said:

Усредняем за время более периода младшей гармоники ?

у вас не скользящее среднее

37 minutes ago, gosha said:

Как экономичнее на verilog реализовать фильтр скользящего среднего ?

CIC фильтр, одно звено, реализция без преобразования частоты

Share this post


Link to post
Share on other sites

Если задача позволяет, очень просто сделать экспоненциально взвешенное скользящее среднее. https://ru.wikipedia.org/wiki/Скользящая_средняя

Если a брать 1/2, 1/4, 1/8 и т.д.

 

Share this post


Link to post
Share on other sites
35 minutes ago, des00 said:

у вас не скользящее среднее

CIC фильтр, одно звено, реализция без преобразования частоты

Спасибо !

А точность не потеряется ?

По Т.З. погрешность измерения дальности дальномером : 5 метров

Задача фильтра- усреднить разность фаз фазомера.

Нужен децимирующий фильтр на 30000. (30 МГц -> 1 KГц)

IP Xilinx не генерит CIC с дещимацией 30_000. Только децимирующий на 8192 максимум. Еще разрядность повышается: А тама арктангенс после фильтра.

Скользящее среднее не будет ли точнее ?

phi.png

tone_20KHz.slx

Share this post


Link to post
Share on other sites
29 minutes ago, gosha said:

А точность не потеряется ?

По Т.З. погрешность измерения дальности дальномером : 5 метров

Задача фильтра- усреднить разность фаз фазомера.

Нужен децимирующий фильтр на 30000. (30 МГц -> 1 KГц)

IP Xilinx не генерит CIC с дещимацией 30_000. Только децимирующий на 8192 максимум. Еще разрядность повышается: А тама арктангенс после фильтра.

Скользящее среднее не будет ли точнее ?

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

Share this post


Link to post
Share on other sites

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

Отбрасывая измерения, повысить точность? Трудно поверить.

Share this post


Link to post
Share on other sites
16.12.2020 в 08:12, gosha сказал:

Необходимо получить усредненное значение сигнала

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

16.12.2020 в 08:12, gosha сказал:

Усредняем за время более периода младшей гармоники ?

Периодов лучше взять побольше, хотя бы 10.

Share this post


Link to post
Share on other sites

Спасибо !!

Хорошее решение.

Тогда уж кольцевой буфер на основе двухпортовой RAM:  в голову пишется, суммируется, хвост вычитается?

Share this post


Link to post
Share on other sites
On 12/19/2020 at 8:36 PM, MrGalaxy said:

Прибавляется текущее значение, которое пишется в память и вычитается самое старое значение, которое в этот момент вылезает из памяти.

это и есть формула из википедии, по приведенной ссылке) раздел статьи: Простое скользящее среднее, или арифметическое скользящее среднее

Share this post


Link to post
Share on other sites
12 часов назад, des00 сказал:

это и есть формула из википедии, по приведенной ссылке) раздел статьи: Простое скользящее среднее, или арифметическое скользящее среднее

Ради формулы простейшего интегрирования в скользящем окне в Википедию лазить... :mega_shok:  

Вопрос был про реализацию.

 

23 часа назад, gosha сказал:

Тогда уж кольцевой буфер на основе двухпортовой RAM:  в голову пишется, суммируется, хвост вычитается?

Я про это и написал. 

Share this post


Link to post
Share on other sites
15 hours ago, MrGalaxy said:

Ради формулы простейшего интегрирования в скользящем окне в Википедию лазить... :mega_shok:  

Вопрос был про реализацию.

Ну это же не вам совет был, вы в этой теме гуру, а ТС изначально не был. Но прочитав все материалы по теме,  в том числе y(t) = y(t-1) - x(t-N) + x(t), ТС не узнал в описании вашего устройства вот эту простую формулу.

Share this post


Link to post
Share on other sites
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity delay_line is
generic(
  W                 : integer := 8;    -- data width
  L                 : integer := 1200);  -- delay length, shall be > 3
port(
  i_clk             : in  std_logic;
  i_sync_reset      : in  std_logic;
  i_data            : in  std_logic_vector(W-1 downto 0);
  o_data            : out std_logic_vector(W-1 downto 0));
end delay_line;

architecture rtl of delay_line is

type t_ram is array (L-2 downto 0) of std_logic_vector(W-1 downto 0);
signal m_ram : t_ram;

signal r_addr_wr         : integer range 0 to L-2;
signal r_addr_rd         : integer range 0 to L-2;
signal r_enable_read     : std_logic;

begin

p_write : process (i_clk)
begin
  if rising_edge(i_clk) then
    if(i_sync_reset='1') then
      r_addr_wr      <= 0;
      r_enable_read  <= '0';
    else
      m_ram(r_addr_wr) <= i_data;
      if(r_addr_wr<L-2) then
        r_addr_wr      <= r_addr_wr + 1;
      else
        r_addr_wr      <= 0;
        r_enable_read  <= '1';       -- enable reading section
      end if;
    end if;
  end if;
end process p_write;

p_read : process (i_clk)
begin
  if rising_edge(i_clk) then
    if(i_sync_reset='1') then
      r_addr_rd      <= 0;
    else
      if(r_enable_read='1') then
        o_data         <= m_ram(r_addr_rd) ; -- additional delay
        if(r_addr_rd<L-2) then
          r_addr_rd      <= r_addr_rd + 1;
        else
          r_addr_rd      <= 0;
        end if;
      end if;
    end if;
  end if;
end process p_read;


end rtl;
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;

 

Share this post


Link to post
Share on other sites
`include "timescale.v"
/*===========================================================*/
module mean_filter(
    input               clk_i, /* 30.72MHz */
    input               rst_i,  
    input signed [21:0] dat_i,  
    input               srst_i,       
    input               valid_i,
    output signed [21:0] dat_o     
    );
/*===========================================================*/    
reg  [3:0] addr_wr; 
reg  [3:0] addr_rd;
reg signed  [25:0] S;   
wire signed  [25:0] S0;   
wire signed [21:0] dat_m;
reg                init_done;
/*===========================================================*/
assign dat_o= S[25:4]; 
assign S0= S- dat_m;
mem_x22 mem (.clk(clk_i), .a(addr_wr), .d(dat_i), .dpra(addr_rd), .we(valid_i), .qdpo(dat_m));
/*===========================================================*/
always @(posedge clk_i or posedge rst_i)    
begin 
if(rst_i)   
      S<= 0;
else
    begin
    if(srst_i)
        S<= 0;
    else
        begin           
        if(valid_i)
			begin
			if(init_done)
				S<= S0 + dat_i;
			else
				S<= S+ dat_i;
			end
        end    
    end
end     
/*===========================================================*/
always @(posedge clk_i or posedge rst_i)    
begin 
if(rst_i)  
     {addr_wr, addr_rd, init_done}<= 0;
else
	begin
    if(srst_i)
        {addr_wr, addr_rd, init_done}<= 0;
	else
		begin
		if(&addr_wr)
			init_done<= 1'b1;
		if(valid_i)
			begin
			addr_rd<= addr_wr+ 2'd2;
			addr_wr<= addr_wr+ 1'b1;
			end
		end
	end
end       
/*===========================================================*/   
endmodule
On 12/26/2020 at 11:09 AM, des00 said:

Ну это же не вам совет был, вы в этой теме гуру, а ТС изначально не был. Но прочитав все материалы по теме,  в том числе y(t) = y(t-1) - x(t-N) + x(t), ТС не узнал в описании вашего устройства вот эту простую формулу.

Если с двух- портовой RAM, так оптимально ?

Share this post


Link to post
Share on other sites
4 hours ago, gosha said:

Если с двух- портовой RAM, так оптимально ?

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

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this