Práctica 2: Conversión A/D y D/A
Señales y Sistemas Lineales
1 Introducción
En esta práctica recorremos con MATLAB la cadena completa de digitalización de una señal: partimos de una señal analógica, la muestreamos, la cuantizamos y finalmente la reconstruimos para volver al mundo continuo. Son los tres bloques que forman cualquier conversor A/D y D/A real.
Damos por supuesto que ya has hecho las prácticas 0 y 1, así que manejas variables, vectores, operaciones elemento a elemento y los comandos básicos de representación gráfica. Aquí los aplicaremos a un problema concreto de la asignatura. Las funciones propias en archivos .m, que en esta práctica usarás a menudo, se explican en el trabajo previo.
Como en la práctica anterior, el documento está pensado para que lo sigas escribiendo tú mismo el código en un script: no basta con leerlo, tienes que reproducir cada ejercicio y experimentar cambiando valores.
1.1 Objetivos
Al terminar deberías ser capaz de:
- Distinguir entre una señal “continua” (un vector de tiempos muy denso) y una señal discreta (las muestras tomadas cada \(T_s = 1/f_s\) segundos), y representar cada una con el comando adecuado:
plotostem. - Reconocer el fenómeno del aliasing, explicar por qué dos señales distintas pueden dar las mismas muestras, aplicar el criterio de Nyquist (\(f_s > 2f_{\max}\)) para evitarlo y calcular la frecuencia del alias a partir de la frecuencia digital.
- Cuantizar una señal con un número dado de bits, distinguir el redondeo del truncamiento y medir la degradación que introduce mediante el error de cuantización y la relación señal-ruido de cuantización (SQNR), relacionándola con el número de bits.
- Reconstruir una señal a partir de sus muestras con la interpolación ideal (sinc), entender en qué se diferencia del retenedor de orden cero (ZOH) y comprobar cuándo deja de funcionar, como predice el teorema de muestreo de Nyquist-Shannon.
1.2 Estructura de la práctica
El documento se divide en dos partes:
- El trabajo previo debes prepararlo antes de acudir al laboratorio. Repasa la teoría que vas a necesitar, presenta las funciones que se proporcionan y propone unos ejercicios breves. Cada ejercicio va acompañado de su solución, que puedes desplegar para comprobar tu respuesta. Intenta resolverlos por tu cuenta antes de mirarla.
- El trabajo de laboratorio es lo que realizarás durante la sesión. En él escribirás tu propia función,
calcula_sqnr, y usarás las que se proporcionan en el trabajo previo,cuant_redondeoeinterp_ideal: guárdalas en tu carpeta de trabajo, cada una en su archivo.m. Si llegas con el trabajo previo hecho, la sesión te cundirá mucho más.
Debes seguir las siguientes pautas:
Trabaja en una carpeta dedicada solo para esta práctica
Asegúrate de que coincide con el directorio de trabajo de MATLAB
Usa scripts de MATLAB (ficheros
.m). No uses Live Scripts (.mlx).Crea un script
ejercicioX.mindividual por cada ejercicio.Siempre ejecuta el script completo (botón “Run” o
F5).
Recuerda completar el cuestionario en Aula Virtual antes de acudir al laboratorio, cuando termines el trabajo previo. El cuestionario no tiene límite de tiempo. Puedes tenerlo abierto mientras trabajas en los ejercicios. El cuestionario es evaluable y constituye el 20% de la nota de evaluación continua de prácticas.
Debes completar el trabajo de laboratorio durante la sesión y entregarlo al final. La entrega es obligatoria y se hace en Aula Virtual, subiendo a la tarea correspondiente un único archivo comprimido .zip que contenga todos tus ficheros .m. Solamente es necesaria una entrega por pareja. La nota máxima a la que puedes optar depende del número de ejercicios que hayas completado y entregado correctamente:
| Fichero | Ejercicio | Nota máxima |
|---|---|---|
ejercicio5.m |
Aliasing | 5 |
calcula_sqnr.m |
Función para calcular SQNR | 6 |
ejercicio7.m |
Cuantización y SQNR | 8 |
ejercicio8.m |
Reconstrucción ideal | 10 |
El/la profesor/a evaluará los ejercicios de la práctica mediante preguntas orales durante la sesión. Asegúrate de comprender tu código y los resultados que obtienes, porque tendrás que responder a preguntas sobre ellos. Las preguntas son individuales aunque trabajéis en parejas. Cuando completes un ejercicio, pide al/a la profesor/a que te lo evalúe.
2 Trabajo previo
2.1 Señales “continuas”
Cuando usamos el comando plot con un vector de tiempos muy denso parece que dibujamos una curva continua y suave. Pero MATLAB en realidad solo conoce los valores de la señal en los puntos del vector t, y une esos puntos con segmentos rectos. La “continuidad” es una ilusión que mejora cuanto más puntos usamos.
Veámoslo dibujando la misma señal senoidal con un número creciente de puntos:
2.2 Muestreo (señales discretas)
Cuando hablamos de “muestrear” en MATLAB nos referimos simplemente a quedarnos con algunos de los puntos de la señal continua. Por ejemplo, si queremos muestrear una señal a 5 Hz (o sea, cada 0.2 s), tomamos solo sus valores en los instantes \(t = \{0, 0.2, 0.4, 0.6, 0.8, 1\}\) s.
Comprueba que el siguiente código genera dicho vector de tiempos:
fs = 5; % frecuencia de muestreo (Hz)
Ts = 1/fs; % periodo de muestreo (s)
t = 0:Ts:1; % instantes de muestreolinspace vs. operador :
Ambas formas nos permiten generar vectores de tiempo, pero normalmente las usamos con propósitos distintos:
Para muestrear señales es más cómodo usar
t1:Ts:t2, lo cual genera un vector de tiempos desdet1hastat2con periodo de muestreoTs.Sin embargo, si nos piden dibujar una señal “continua” con N puntos, entonces sí conviene usar
linspace(t1, t2, N).
Recuerda que si muestreamos una señal continua de frecuencia \(f\) Hz a una frecuencia de muestreo \(f_s\) Hz, entonces la señal discreta resultante tiene una frecuencia digital:
\[ \Omega = \pi \frac{f}{f_{nyq}} \quad \text{rad/muestra} \]
donde \(f_{nyq} = f_s/2\) es la frecuencia de Nyquist.
2.3 Funciones en MATLAB
Las funciones son bloques de código que reciben entradas y devuelven salidas:
las usamos para reutilizar código y organizarlo mejor.
se definen en un archivo
.mindependienteel archivo debe tener el mismo nombre que la función
el archivo debe estar dentro del directorio de trabajo
se pueden llamar desde cualquier script y también desde la línea de comandos.
Aquí tienes un ejemplo de una función que calcula la potencia de una señal discreta:
function p = potencia(x)
% POTENCIA Calcula la potencia de una señal discreta.
p = sum(x.^2) / length(x);
end2.4 Redondeo y truncamiento
Las operaciones de redondeo y truncamiento son habituales en computación y procesamiento de señales. MATLAB dispone de las funciones:
round(x): aproximaxal entero más cercanofloor(x): aproximaxal entero más próximo por debajo
En ambos casos, se pueden aplicar directamente a un vector, y la operación se realiza elemento a elemento. En ese caso, devuelven un vector de la misma dimensión que el original, solamente con valores enteros.
2.5 Aliasing
Si muestreamos demasiado despacio, dos señales continuas de frecuencias distintas pueden producir exactamente las mismas muestras. Al mirar solamente los puntos muestreados, se vuelven indistinguibles.
Para que las muestras representen sin ambigüedad una señal, la frecuencia de muestreo debe ser mayor que el doble de la frecuencia máxima de la señal:
\[ f_s > 2\,f_{\max} \]
Dicho de otra manera, \(f_{\max} < f_s/2 =f_{nyq}\), la frecuencia máxima de la señal debe ser menor que la frecuencia de Nyquist.
El efecto de aliasing aparece cuando no se cumple el criterio de Nyquist, es decir, cuando la señal tiene componentes de frecuencia mayor que la frecuencia de Nyquist \(f_{nyq} = f_s/2\). Como resultado, el muestreo da lugar a una frecuencia “fantasma” (alias) que no es real.
Si se produce aliasing y reconstruimos la señal a partir de sus muestras, no recuperaremos la señal original, sino un alias de la misma. Recuerda que la frecuencia digital equivalente \(\Omega'\) se obtiene restando múltiplos de \(2\pi\) a \(\Omega\) hasta que quede dentro del rango \([-\pi, \pi]\):
\[ \Omega' = \Omega - 2\pi k, \qquad k \in \mathbb{Z} \]
La frecuencia de la señal reconstruida (el alias) es entonces:
\[ f' = \frac{|\Omega'|}{\pi} f_{nyq} \]
\(\Omega'\) puede salir negativa, pero la frecuencia \(f'\) se expresa siempre como positiva; por eso se toma el valor absoluto.
2.6 Cuantización
Se ha visto en teoría que uno de los pasos en la digitalización de una señal es la cuantización, que consiste en aproximar cada valor de la señal a un nivel discreto dentro de un rango determinado.
Se proporciona la siguiente función, que permite cuantizar una señal en el rango [Amin, Amax] por redondeo al nivel más cercano:
function xq = cuant_redondeo(x, Amin, Amax, N)
% CUANT_REDONDEO Cuantización uniforme por redondeo al nivel más cercano.
% xq = CUANT_REDONDEO(x, Amin, Amax, N) cuantiza x en el rango [Amin, Amax]
% con N bits (2^N niveles), redondeando al nivel más cercano.
L = 2^N;
Delta = (Amax - Amin) / (L - 1);
xq = Amin + Delta * round((x - Amin)/Delta);
xq = min(max(xq, Amin), Amax);
end2.7 Error de cuantización y SQNR
Tanto si se utiliza redondeo como truncamiento, la señal cuantizada será diferente de la original y por tanto se introduce un error de cuantización. Este error puede medirse de varias formas, siendo una de las más comunes la relación señal-ruido de cuantización (SQNR), que compara la potencia de la señal original (\(x\)) con la potencia del error de cuantización (\(e\)): \[ SQNR = 10 \log_{10} \left( \frac{\sum x[n]^2}{\sum e[n]^2} \right)\, \text{dB}\]
siendo \[ e[n] = x_q[n] - x[n] \] el error entre la señal cuantizada y la original.
2.8 Reconstrucción D/A
Generalmente muestreamos una señal para almacenarla o procesarla digitalmente, y luego la reconstruimos para escucharla o visualizarla. Una señal discreta solamente existe en los instantes de muestreo, y para poder generar una señal continua necesitamos interpolar entre las muestras.
Existe un interpolador trivial, conocido como retenedor de orden cero, comúnmente ZOH (por sus iniciales en inglés, zero-order hold), que consiste en mantener cada muestra constante a lo largo del tiempo hasta la siguiente muestra. Tienes un ejemplo en la siguiente figura:
La señal original es una senoide de 1 Hz (azul)
La señal muestreada a 10 Hz da lugar a la senoide discreta (rojo)
La reconstrucción ZOH a partir de las muestras consiste en mantener el último valor constante (verde)
El ZOH es el interpolador más sencillo posible. Sin embargo, existe un interpolador ideal, capaz de reconstruir la señal original a partir de sus muestras, si se cumplen unas condiciones:
Si una señal no contiene frecuencias mayores que \(f_{\max}\), entonces puede ser perfectamente reconstruida a partir de sus muestras si la frecuencia de muestreo \(f_s\) cumple \[ f_s > 2 f_{\max} \] mediante la siguiente fórmula de interpolación: \[ x(t) = \sum_{n=-\infty}^{\infty} x[n] \cdot \text{sinc}\left(\frac{t - nT_s}{T_s}\right) \] donde \(\text{sinc}(x) = \frac{\sin(\pi x)}{\pi x}\) y \(T_s = 1/f_s\) es el periodo de muestreo.
Se proporciona la siguiente función, que implementa la fórmula de la interpolación ideal:
function xc_ideal = interp_ideal(xn, tn, tc)
% INTERP_IDEAL Interpolación ideal mediante sinc.
% xn : valores de la señal discreta
% tn : instantes de tiempo de cada muestra (mismo tamaño que xn)
% tc : instantes de tiempo "continuos" donde queremos interpolar la señal
Ts = tn(2) - tn(1); % periodo de muestreo
xc_ideal = zeros(1, length(tc)); % inicializamos el vector de salida
for k = 1:length(tc)
u = (tc(k) - tn)/Ts; % argumento de la sinc para cada muestra
s = sin(pi*u)./(pi*u); % sinc(u) = sin(pi u)/(pi u)
s(u == 0) = 1; % sinc(0) = 1 (evita 0/0)
xc_ideal(k) = sum(xn .* s); % suma de las muestras ponderadas
end
end3 Trabajo de laboratorio
Debes seguir las siguientes pautas:
Trabaja en una carpeta dedicada solo para esta práctica
Asegúrate de que coincide con el directorio de trabajo de MATLAB
Usa scripts de MATLAB (ficheros
.m). No uses Live Scripts (.mlx).Crea un script
ejercicioX.mindividual por cada ejercicio.Siempre ejecuta el script completo (botón “Run” o
F5).