Audio filter

From Hamsterworks Wiki!

Jump to: navigation, search

I'm going to try implement an audio filter by a numerical approximation of current flow within an analogue RC filter, driven by an 0 Ohm source, driving an output of infinite impedance.

Vout(n) = Vout(n-1)+(Vin(n-1) - Vout(n-1))* K

Here is what it looks like when modelled in Excel:

K = 0.05, 600 samples per cycle Filter1.jpg

K = 0.05, 120 samples per cycle Filter2.jpg

K = 0.05, 60 samples per cycle Filter3.jpg

Looking at those graphs it looks to be a pretty close approximation filter with a 3db frequency of about 120 samples / cycle.

Because it only uses one value to set the critical frequency it can be tuned in real time.

filter.vhd

----------------------------------------------------------------------------------
-- Engineer:   Mike Field <hamster@snap.net.nz> 
-- 
-- Create Date:    21:04:44 04/12/2013 
-- Module Name:    filter - Behavioral 
--
-- Description:  A selectable -3db / -6db / -9db / -12 db per octave digital filter
--
-- When clocked at 32MHz the filter is in the audio range. Originally it was loosely 
-- based on the charge flow in an analogue RC filter. 
--
-- It is an Infinite Input Response (IIR) filter - see 'Transfer function  
-- derivation' section of http://en.wikipedia.org/wiki/Infinite_impulse_response
--
----------------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

Library UNISIM;
use UNISIM.vcomponents.all;

entity filter is
    Port ( clk           : in  STD_LOGIC;
           slope         : in  STD_LOGIC_VECTOR (1 downto 0);  -- 0,-3,-6,-9db filter slope
           sample_in     : in  STD_LOGIC_VECTOR (15 downto 0); -- unsigned 16 bit sample
           sample_out    : out STD_LOGIC_VECTOR (15 downto 0); -- unsigned 16 bit sample
           time_constant : in  STD_LOGIC_VECTOR (7 downto 0)); 
end filter;

architecture Behavioral of filter is
   -- multiplier signals
   signal delta         : signed(17 DOWNTO 0);
   signal b             : std_logic_vector (17 downto 0);    
   signal mult_out      : std_logic_vector (35 downto 0);    

   -- what is the current stage being processed
   signal stage         : std_logic_vector (1 downto 0) := (others => '0');    

   -- the filter stage signals 
   signal stage0,   stage1,   stage2,   stage3     : signed (15 downto 0) := (others => '0');
   signal stage0_l, stage1_l, stage2_l, stage3_l   : signed (17 downto 0) := (others => '0');
   signal accumulator1, accumulator2, accumulator3 : signed (31 downto 0) := (others => '0');
begin
   b <= "000000" & time_constant & "0000";

filter_MULT: MULT18X18SIO generic map (
      B_INPUT => "DIRECT", -- Don't use the cascade input 
      AREG => 1,  BREG => 1, PREG => 1)      -- Enable the input registers on the A,B and P port
   port map (
      CLK => CLK,                              -- Clock input
      P => mult_out,                           -- 36-bit multiplier output
      A => std_logic_vector(delta),            -- 18-bit multiplier input
      B => b,                                  -- 18-bit multiplier input
      CEA => '1',    CEB  => '1', CEP  => '1',  -- Clock enables
      RSTA => '0',   RSTB => '0', RSTP => '0', -- Synchronous resets input for the P port
      BCOUT => open, BCIN => (others => '0')   -- unused cascade ports   
   );

   stage0    <= signed(sample_in);           stage0_l  <= "00" & stage0;   
   stage1    <= accumulator1(31 downto 16);  stage1_l  <= "00" & stage1;
   stage2    <= accumulator2(31 downto 16);  stage2_l  <= "00" & stage2;
   stage3    <= accumulator3(31 downto 16);  stage3_l  <= "00" & stage3;

process(clk)
   begin
      if rising_edge(clk) then
         -- set the output signal
         case slope is
            when "00"   =>  sample_out <= std_logic_vector(stage0);
            when "01"   =>  sample_out <= std_logic_vector(stage1);
            when "10"   =>  sample_out <= std_logic_vector(stage2);
            when others =>  sample_out <= std_logic_vector(stage3);
         end case;

         case stage is 
            when "00"   =>  --  0db / octave
               delta        <= stage0_l - stage1_l;
               accumulator2 <= accumulator2 + signed(mult_out(35 downto 4));
               stage        <= "01";
               
            when "01"   =>  -- -3db / octave
               delta        <= stage1_l - stage2_l;
               accumulator3 <= accumulator3 + signed(mult_out(35 downto 4));
               stage        <= "10";
               
            when "10"   =>  -- -6db / octave
               delta        <= stage2_l - stage3_l;
               stage        <= "11";
               
            when others =>  -- -9db / octave
               accumulator1 <= accumulator1 + signed(mult_out(35 downto 4));
               stage        <= "00";
         end case;         
      end if;
   end process;
end Behavioral;

Personal tools