3.1 Generación de una señal senoidal (DDS)
En este apartado se describe la técnica de generación de señales basada en la síntesis digital directa (DDS). El artículo siguiente describe su funcionamiento:
Algunas aplicaciones incluyen:
Generadores de señal programables: Para crear formas de onda precisas en instrumentación y equipos de prueba.
Síntesis de frecuencia: En transceptores de radio y sistemas de comunicaciones para generar portadoras y tonos de referencia.
Modulación digital: Para implementar técnicas de modulación FSK, PSK y QAM en sistemas de comunicación.
Sistemas de audio: Generación de tonos, efectos sonoros y síntesis musical en dispositivos embebidos.
Radar y sonar: Para generar chirps (barridos de frecuencia) y pulsos con características temporales específicas.
Control de motores: En drives de motores síncronos para generar referencias de velocidad y posición con alta resolución.
3.1.1 DDS:
Direct Digital Synthesis (DDS) es una técnica que a partir de un reloj de precisión y frecuencia fija, y utilizando bloques digitales, permite obtener una señal sinusoidal ajustable en fase y frecuencia.
En su forma más simple un DDS puede ser implementado como muestra la Figura 3-1, utilizando una señal de reloj, un contador, una tabla, y un conversor digital analógico D/A.
Figura 3-1. Algoritmo DDS.
La tabla SINE LOOKUP, almacena las amplitudes correspondientes a un ciclo completo de una senoide. La salida del contador, ADDRESS COUNTER, se utiliza como dirección de acceso a dicha tabla. A medida que el contador incrementa su valor, se obtienen secuencialmente las amplitudes que conforman la forma de onda generada. Finalmente, esta señal digital es transformada en una señal analógica mediante el conversor digital-analógico (D/A).
La frecuencia de salida, \(f_{o}\), depende de la frecuencia de la señal de reloj (frecuencia de muestreo), \(f_c\), y del número de muestras, \(2^N\), en que se ha codificado un periodo de la senoide (tamaño de la tabla):
Esta implementación no permite realizar ajustes en la frecuencia de salida de forma sencilla, para mejorarla se introduce un acumulador de fase, que permite ajustar la frecuencia de la señal de salida (fig. 3-2):
Figura 3-2. DDS con acumulador de fase.
En esta implementación se ha sustituido el contador de direcciones, por un contador de N bits con incremento (\(M\)) variable (acumulador de fase).
El acumulador de fase es un contador módulo \(2^N\), su funcionamiento es equivalente al de un vector rotando en un círculo de fase (ver figura 3-3). Cada punto en el círculo de fase corresponde con una muestra:
Figura 3-3. Acumulador de fase.
La frecuencia de la señal de salida viene dada por la expresión:
donde:
\(M\): incremento de fase
\(N\): número de bits del acumulador de fase
\(f_c\): frecuencia de reloj (frecuencia de muestreo)
3.1.2 Implementación:
Utilizaremos la clase DDS16Bits para modelar un DDS con acumulador de fase
de 16 bits.
Figura 3-4. Clase DDS16Bits.
Atributos:
phaseAccumulator: Valor del acumulador de fase
phaseIncrement: Valor del incremento de fase
SinLookupTbl (estático): Tabla con 257 valores de amplitud del primer cuadrante de un seno, codificados en 16 bits.
Métodos:
setPhase(): Asigna valor al acumulador de fase
setPhaseInc(): Asigna valor al incremento de fase
getNextSample(): Devuelve el valor de amplitud de un tono generado por DDS
SineTbl() (privado): Conversor fase → amplitud
Acumulador e incremento de fase:
El acumulador de fase y el incremento de fase se codifican en 16 bits (uint16_t).
El acumulador es un contador que se incrementa en cada ciclo de reloj con el valor del incremento de fase.
Un incremento de fase mayor dará lugar en una frecuencia de salida más alta, mientras que un incremento de fase menor a una frecuencia de salida más baja.
Veamos cómo obtener el valor del incremento de fase con un ejemplo:
Si se codifica como uint16_t: \(M = \text{round}(2229.589) = 2230\)
Conversión fase → amplitud:
Utilizaremos una tabla de 1024 posiciones, pero para ahorrar recursos, sólo se guardarán en memoria los 257 valores de amplitud del primer cuadrante de la senoide, el resto se obtendrán aprovechando la simetría de la forma de onda.
Para crear la tabla y guardarla en un fichero de texto, podemos utilizar el siguiente script:
fases=0:pi/512:pi/2;
sine_tbl_257=round((2^15-1)*sin(fases));
dlmwrite("dds_sine_tbl257.dat",sine_tbl_257);
import numpy as np
fases = np.arange(0, np.pi/2 + np.pi/512, np.pi/512)
sine_tbl_257 = np.round((2**15 - 1) * np.sin(fases)).astype(int)
np.savetxt("dds_sine_tbl257.dat", sine_tbl_257, fmt='%d,')
El método SineTbl(uint16_t fase) obtiene los valores de amplitud en los 4
cuadrantes a partir del valor de fase.
La fase se codifica en en 16 bits, como la tabla es de 1024 posiciones (10 bits), se tomarán los 10 bits mas significativos de fase para acceder a la tabla.
fase10 = fase >> 6
- 1er cuadrante: 0 ≤ fase ≤ 16384: amplitud = SinLookupTbl [fase10]‡.
- 2º cuadrante: 16384 < fase ≤ 32768: amplitud = SinLookupTbl [512-fase10].
- 3er cuadrante: 32768 < fase ≤ 49152: amplitud = -SinLookupTbl [fase10-512].
- 4º cuadrante: 49152 < fase < 65536: amplitud = -SinLookupTbl [1024–fase10].
‡ SinLookupTbl [] → tabla con los valores de amplitud del primer cuadrante.
Diseño y pruebas clase DDS16Bits
Preparación del entorno.
Descarga y descomprime el archivo de recursos
lab3en tu espacio de trabajo.Los archivos
dds.hydds.cque implementan la clase DDS16Bits están ubicados en la carpetasrc.Crea el archivo
dds_sine_tbl257.daten la carpetasrcutilizando el script de Matlab proporcionado.
Configuración del proyecto.
Abre el proyecto lab3.
Selecciona el target
Test_DDS, que utiliza un simulador para la depuración del código. Esto permite desarrollar y validar el software sin necesidad de disponer del hardware físico.
Tareas a realizar.
Escribe el código de la clase
DDS16Bitsen el archivodds.c.Asegúrate de que el código compila correctamente y no genera errores.
Revisa los casos de prueba definidos en la función
main(), ubicada en el archivotest/test_dds.c.
Herramientas de análisis.
Inicializa el debugger
y abre la herramienta
Analyzer desde el menú:.
Analyzer mostrará la evolución temporal de las variables globales:
g_sample: número de muestra.g_amp: amplitud de la señal.
Ejecuta la aplicación
y corrige cualquier error funcional hasta que la
clase DDS16Bitscumpla con la especificación deseada.
Test y Resultados esperados.
El fichero
test/test_dds.cincluye los siguientes casos de prueba:Test1 — Señal 1 kHz durante 10 ms.
Test2 — Señal 2 kHz durante 5 ms.
Test3 — Cambios de fase 0°-180°-0°-180°-0° con fo = 1 kHz.
Test4 — Oscilador parado (fo = 0 Hz) durante 5 ms.
Test5 — Chirp lineal (phase_inc incremental) durante 20 ms.
Asegúrate de que todos los casos se ejecutan correctamente y producen los resultados esperados. Verifica que el periodo de la señal de 1 kHz corresponda con 48 muestras, y el de 2 kHz con 24 muestras.