mercoledì 16 maggio 2012

Direct Digital Synthesizer - Crea la Tua onda...

In questo breve articolo, descriverò una tecnica semplice quanto efficace per generare una forma d'onda arbitraria e periodica. Per fare ciò dobbiamo prendere in esame i sintetizzatori digitali.
Partiamo da una considerazione: una forma d'onda è l'espressione di una funzione nel dominio del tempo. Se pensiamo ad una sinusoide, ad esempio, la funzione sarà: sin(wt); per wt (omega * T) che va da 0 a 2 PI.

(Onde sinusoidali)

(Onde triangolari)

(Onda a Dente di Sega)

Come possiamo realizzare attraverso un circuito elettronico una simile funzione?
La risposta più immediata è: creiamo una tabella ROM (Read Only Memory) al cui interno siamo presenti tutti i valori della funzione matematica desiderata e, poi, estraiamo uno per volta tali valori fino al completamento di un periodo temporale preimpostato, convertiamo i valori numerici in un segnale analogico (es. mediante un DAC - Digital to Analog Converter) e ...avremo ottenuto la nostra forma d'onda sintetica.

Nella realtà avremo bisogno di un Circuito Integrato dedicato (ASSP - Application Specific Standard Circuit) oppure potremo realizzare il sintetizzatore di forme d'onda mediante un circuito integrato programmabile (es. un FPGA - Field Programmable Gate Array).

Nelle prossime immagini vediamo lo schema di una implementazione su FPGA:

(FPGA Top - Click per ingrandire)

(Blocco DPRAM su FPGA - Click per ingrandire)

Il circuito DDS si basa sul principio dell'Accumulatore di Fase, tale accumulatore può agevolmente essere implementato in linguaggio VHDL (VLSI Hardware Description Language) ...di cui Vi riporto il codice:

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;


entity PHASE_ACC is
    Port ( clock : in  STD_LOGIC;
           reset : in  STD_LOGIC;
           load : in  STD_LOGIC;
           data : in  STD_LOGIC_VECTOR (31 downto 0);
           addr : out  STD_LOGIC_VECTOR (10 downto 0));
end PHASE_ACC;

architecture Behavioral of PHASE_ACC is
    signal phase_accum : STD_LOGIC_VECTOR (31 downto 0);
    signal phase_delta : STD_LOGIC_VECTOR (31 downto 0);
begin

    process (clock, reset)
    begin
        if reset='1' then
            addr <= (others => '0');
        elsif clock='1' and clock'event then
            addr <= phase_accum (31 downto 21);
        end if;
    end process;

    process (clock, load)
    begin
        if load = '1' then
            phase_delta <= data;
        elsif clock='0' and clock'event then
            phase_accum <= phase_accum + phase_delta;
        end if;
    end process;

end Behavioral;

Ma come è possibile generare una sinusoide?
Semplice, quardiamo questa funzione in codice ANSI C:

/* load a sine wave in FPGA wavetable*/
void load_sine(void) {

  const float pi = 3.141592f;
  float phase_vector = 0.0f;
  float phase_delta = 0.0f;
 
  unsigned int i;         //generic counter
 
  /* reset DPRAM address generator */
  WriteEXB(0x01, 0x02); //bit 0, addr 2

  phase_delta = (2.0f * pi) / 2048.0f;

  for (i=0; i<2048; i++) {
    WriteEXB((unsigned char)(round(sin(phase_vector) * 127.5f)
    + 127.0f), 0x01);
    phase_vector = phase_vector + phase_delta;
  }
   
  return;
}

Tornerò prossimamanete a parlare delle applicazioni del DDS ...adesso sono in partenza, nuove avventure mi attendono.

Qui Pianeta Terra, un mondo analogico... a presto!


Nessun commento:

Posta un commento