Phases in UVM

UVM introduces the concept of phases to ensure that all objects are properly configured and connected before starting the runtime simulation. Phases contribute to a better synchronised simulation and enable to the verification engineer to get better modularity of the testbench.

UVM phases consists of:

  1. build
  2. connect
  3. end_of_elaboration
  4. start_of_simulation
  5. run
    1. reset
    2. configure
    3. main
    4. shutdown
  6. extract
  7. check
  8. report
  9. final

The run phase has been simplified to get a better picture of how phases worked. Nevertheless, all subphases in the run phase have a pre_ and post_ phase to add flexibility. Therefore, the run phase is actually composed by the following phases:

  1. run
    1. pre_reset
    2. reset
    3. post_reset
    4. pre_configure
    5. configure
    6. post_configure
    7. pre_main
    8. main
    9. post_main
    10. pre_shutdown
    11. shutdown
    12. post_shutdown

Although all phases play an important role, the most relevant phases are:

  • build_phase: objects are created
  • connect_phase: interconnection between objects are hooked
  • run_phase: the test starts. The run_phase is the only phase which is a task instead of a function, and therefore is the only one that can consume time in the simulation.

UVM phases are executed from a hierarchical point of view from top to down fashion. This means that the first object that executes a phase is the top object, usually

testbench  test  environment agent {monitor, driver, sequencer, etc}

Nevertheless, in the connect phase, this happens the other way round in a down to top fashion.

{monitor, driver, sequencer} agent environment test testbench

How to add UVM in your Verilog test bench

To use UVM in your Verilog test bench, you need to compile the UVM package top. To do so, you need to include it on your file by using:

The uvm_pkg is contained in the uvm_pkg.sv that must be passed to the compiler. Therefore, it is necessary to indicate the UVM path to the compiler. In Cadence Incisive Enterprise Simulator (IES) is as easy as to specify -uvm switch.

In Modelsim, from Modelsim console, run:

After compilation, click on Simulate > Start simulation and select the tb in the work library. Then, run the simulation for the desired time.

Operation with different size operands in Verilog/SystemVerilog

When an operation such as an addtion or a substraction is done using different size operands than final variable, it is necessary to extend sign to ensure the operation is done properly.

Example:

Wrong:

Sign on data_in will not be respected. data_in will be filled with 0 before doing the operation and won’t be taken as negative (if applies).

Correct:

Extend sign to match number of acc_add bits before doing operation

Instalar minted en Windows 10

minted es un paquete de LaTeX que permite añadir código a tu documento y mostrarlo resaltado. Minted utiliza Python para compilar, por lo que el primer paso es instalar Python 2.6 o superior.

  1. Instalar Python
  2. Añadir la ruta de Python a las variables del entorno de Windows.
    1. Botón derecho en el icono de Windows.
    2. Sistema
    3. En el buscador añadir “variables” y clickar en “Editar variables del sistema”.
    4. Clickar en Variables del entorno.
    5. En Variables del sistema, añadir a la entrada Path la localización de la carpeta Scripts de Python. En mi caso está en D:\Windows\Python\Python36-32\Scripts. Es muy probable que este paso no sea necesario en tu sistema y que al instalar Python ya se haya añadido la ruta a las variables del sistema. Si al ejecutar python en CMD da un error, entonces este paso es obligatorio.
    6. Instalar pip.
    7. Instalar pygments:
      1. Abrir CMD en Windows y escribir: pip install Pygments
      2. Probar que se ha instalado correctamente escribiendo en CMD pygmentize -h
    8. Ahora desde TexStudio hay que modificar la llamada al compilador de LaTeX.
      1. Opciones > Configurar TeXStudio > Órdenes
      2. Modificar las entradas LaTeX y PdfLaTeX por: latex.exe -src -interaction=nonstopmode -shell-escape %.tex y pdflatex.exe -synctex=1 -interaction=nonstopmode -shell-escape %.tex respectivamente. De esta manera se añade la etiqueta -shell-escape después de -interaction=nonstopmode
      3. Cerrar TeXStudio
      4. Abrir de nuevo

Y si no ha habido ningún problema en los pasos anteriores, se debería poder compilar utilizando minted. Para más información, visitad la guía de instalación de minted.

 

Parameter sweep en Orcad Capture PSpice

  1. Instanciar PARAMETERS de la librería SPECIAL.
  2. Editar propiedades de PARAMETERSS (doble click).
  3. Click en “New property”.
  4. Añadir parámetro. Ejemplo: Name: Vin_variable, Value: 0.7
  5. Modificar valor del componente asignando el nuevo parámetro entre {}. Ejemplo: VAMPL: {Vin_variable}
  6. Añadir “Parametric sweep” en la configuración del perfil de simulación.
  7. Por último, realizar la simulación.

Memoria M9K en Cyclone IV

El dispositivo Cyclone IV de Altera dispone de unas memorias embebidas llamadas M9K. Estas memorias son configuradas por el sintetizador (Quartus) y dependiendo del tamaño necesario, se pueden combinar varias. Estas memorias siempre son síncronas, por lo que para que el sintenizador utilice una memoria M9K a partir del código, la memoria en cuestión debe estar gobernada por la señal de reloj.

Estas memorias pueden funcionar con un puerto puerto simple (entrada-salida) o un puerto doble. La configuración de puerto doble consiste en leer de manera independiente una misma memoria por dos puertos. Otra de los modos de funcionamiento es ROM, en el que se escribe el contenido al programar la FPGA y solo es posible leer su contenido.

Dependiendo de la configuración, la capacidad disponible las memorias M9K puede variar. Para anchos de palabra de 1, 2 y 4 bits la capacidad disponible es de 8k (8192 bits). Para tamaños de palabra mayores (8+1), (16+2), (32+4), la capacidad disponible es de 9k (9216 bits).

Las configuraciones en modo ROM son:

  • 8k x 1 bit
  • 4k x 2 bits
  • 2k x 4 bits
  • 1k x (8+1) bits
  • 512 x (16+2) bits
  • 256 x (32+4) bits

Las configuraciones en modo puerto doble son:

  • 8k x 1 bit
  • 4k x 2 bits
  • 2k x 4 bits
  • 1k x (8+1) bits
  • 512 x (16+2) bits

En el caso de los anchos de palabra no potencias de 2, se puede utilizar estos bits extras para control de errores.

Ejemplo de memoria 1k x 16

La primera opción está más optimizada ya que se necesita menos hardware para obtener el mismo resultado.

Modelado de precisión finita

El modelado de precisión finita consiste en la representación de números decimales mediante una codificación que no alcanza a representar el número exacto. Antes de entrar en detalles, será mejor repasar qué formatos de codificación binaria existen.

Codificación binaria con punto fijo

En la representación en punto fijo, el valor del número representado depende de la posición de los 1’s y los 0’s. Ejemplo:

\[ (10010)_2 = 1 \cdot  2^4 + 0 \cdot 2^3 + 0 \cdot 2^2 + 1 \cdot 2^1 + 0 \cdot 2^0 = 18 \]

El rango dinámico de esta codificación viene determinado por el número de bits que se utilizan. Sin embargo, la suma de números representados en punto fijo es muy sencilla.

Codificación binaria con punto flotante

El valor de un número no depende de la posición de cada uno de los bits, sino que dentro de la secuencia de binaria existe 3 partes: el signo, la mantisa y el exponente.

El valor del número se calcula como:

\[ \text{Valor} = S \cdot M \cdot 2^{E-cte} \]

La codificación con punto flotante ofrece un rango dinámico más grande que con el punto fijo. Además, la resolución de la codificación puede ser variable. Sin embargo, realizar una suma de dos números en coma flotante es más complejo que en punto fijo.

Para representar números enteros, existen dos codificaciones muy utilizadas. La primera es la explicada anteriormente, en el que la posición de cada bit representa un múltiplo de potencias de 2. Sin embargo, con esta codificación no es posible representar números negativos. Para representar números negativos la codificación más utilizada es la conocida como complemento a 2.

Codificación en punto fijo de enteros

La codificación de números con N bits y sin signo tiene un rango de \(\left[0, 2^N -1 \right]\). En este caso, la resolución es de 1.

Para calcular el valor de un número:

\[ X = \sum_{i=0}^{N-1} x_i 2^i\]

Codificación en punto fijo de enteros con signo

La codificación de números con N bits y con signo se puede realizar mediante la codificación complemento a 2. En esta codificación, cada bit tiene un peso, exactamente igual que en la codificación sin signo, con la particularidad de el bit más significativo tiene signo menos y el peso como potencia de 2 que le corresponda. Es decir:

Como vemos, el MSB (most significant bit) representa el peso \(2^4\) pero además tiene signo negativo.

El complemento a 2 tiene un rango de \(\left[-2^{N-1}, 2^{N-1}-1 \right] \) y una resolución de 1.

Equivalencia entre números sin signo y complemento a 2

En la tabla vemos la representación sin signo y la representación con signo y su equivalencia al formato decimal. En este caso N = 3, ya que se utilizan 3 bits para representar todos los números. El rango de los números sin signo es [0, 7] y en el caso de con signo [-4,3].

Los valores que son menores de \(2^{N-1} = 2^{3-1} = 2^2 = 4\) tienen una equivalencia directa entre ambas codificaciones, representados con fondo azul en la tabla. Es decir, 3 se escribe en formato binario en ambos casos \((011)_2\).

Para el caso de valores sin signo mayores a \(2^{N-1}\), su lectura en complemento a 2 sería:

\[ \text{Signed} = \text{Unsigned} – 2^N \]

Por ejemplo, 6 en formato sin signo es \((110)_2\). Sin embargo, \((110)_2\) leído como un número en complemento a 2 es:

\[ \text{Signed} = 6 – 2^3 = 6 – 8 = -2 \]

Por tanto,

\[ S = \left\{\begin{matrix}
U; & U < 2^{N-1} \\
U – 2^N ;& U \geq 2^{N-1}
\end{matrix}\right.\]

Codificación de reales con punto fijo

Los números decimales también pueden ser representados mediante la codificación de punto fijo. Sin embargo, la precisión con la que se pueden representar depende del número de bits y de la posición del punto.

La posición del punto es imaginaria ya que no se especifica de ninguna manera. A partir de este punto, los números a su izquierda son potencias de 2 positivas y a la derecha potencias de dos negativas. La resolución de esta representación la da el LSB (least significant bit).

\[ X =  \left(\sum_{i=0}^{N-1} x_i 2^i  \right) \cdot 2^{-b} \]

La notación para describir esta codificación es \([N,b]\), donde \(N\) es el número total de bits y \(b\) es el número de bits fraccionales. Por ejemplo, \([6,3]\) significan 6 bits totales de los cuales 3 son fraccionales. En este caso, la resolución es \(2^{-3 }= 0.125\).

Codificación de reales con punto fijo en complemento a 2

Para representar números reales con signo mediante complemento a 2, el rango de estos números es \( [-2^{N-1}\cdot Q, (2^{N-1}-1)\cdot Q]\), donde N es el número total de bits y Q es la resolución, que equivale a \(Q= 2^{-b}\).

\[ X = \left(-x_{N-1} 2^{N-1} + \sum_{i=0}^{N-2} x_i 2^i  \right) \cdot 2^{-b} \]

  • Ejemplo 1:
    • N = 6, b = 3, formato [6,3].
    • El rango es \(\left[2^{6-1}\cdot 2^{-3}, (2^{6-1}-1)\cdot 2^{-3} \right] = \left[-4, 3.875\right] \).
    • La resolución es de \(2^{-3} = 0.125\).
  • Ejemplo 2:
    • N = 5, b = 2, formato [5,2].
    • El rango es \(\left[2^{5-1}\cdot 2^{-2}, (2^{5-1}-1)\cdot 2^{-2} \right] = \left[-4, 3.75\right] \).
    • La resolución es de \(2^{-2} = 0.25\)

Rango dinámico de una codificación

El rango dinámico determina la cantidad de números que existen para codificar un rango de números. Es decir, en la codificación punto fijo sin signo, el rango es \([0, \left(2^{N}-1\right)\cdot Q]\) y la resolución es \(Q=2^{-b}\).

El rango dinámico es la relación entre la máxima excursión de la codificación (\(N_{max}-N_{min}\) y la resolución de la codificación.

\[ DR = \frac{N_{max}-N_{min}}{Q} = \frac{ \left(2^{N}-1\right)-0}{Q} = 2^{N}-1 \]

Para el caso de complemento a 2 donde el rango es \([-2^{N-1},2^{N-1}-1]\) y la resolución sigue siendo \(Q= 2^{-b}\) el rango dinámico es también \(2^{N}-1\).

Si se calcula en dB, definiendo el rango dinámico como \(20\log_{10}\{·\}\), obtenemos que el rango dinámico es aproximadamente, 6.02N dB. Por tanto, cada bit que se añada aumentará 6 dB el rango dinámico de la codificación.

Efectos de la precisión finita

El hecho de trabajar con precisión finita a la hora de representar los números, tiene efectos en la señal que estamos tratando. Los efectos pueden ser de dos tipos:

  • Disminuir el número de bits de enteros, lo cual reduce el rango de la codificación. Esto puede llevar a que la señal no pueda ser representada dentro de nuestra codificación. Es decir, un seno que tiene un rango de [0,8] no puede ser codificado con U[4,3] ya que números mayores de \(2^{4}\cdot 2^{-3} = 2\) no pueden ser representados. Esto puede tener dos tipos de consecuencias en la señal:
    • Wrap: la señal se desdobla y números superiores al máximo del rango se representan como valores cercanos al mínimo del rango.Ejemplo: S[4,3], rango [-1, 0.875], resolución \(2^{-3} = 0.125\). Si representa un número fuera del rango, \(1.125 = (01.001)_2 \). Solo tenemos 1 bit para representar la parte entera, por tanto el número quedará sesgado a \((1.001)_2\) que de Ca2 a decimal es \( \left(-2^{3} + 2^{0} \right) \cdot 2^{-3} = -0.875\)
    • Overflow: si se intentan representar números que están fuera del rango de la codificación la señal se satura en el valor máximo. Para que la señal se represente como overflow hay que añadir explícitamente electrónica que controle estos casos.
  • Cuantificación: al tener una precisión finita todos los valores deben ser representados mediante múltiplos de la resolución. Todo número real que se encuentre entre estos múltiplos de la resolución será mapeado directamente a uno de estos múltiplos. Por tanto, la señal quedará escalonada. Dependiendo de la técnica que se utilice para realizar este mapeada (redondeo o truncado) los efectos son distintos. Desde el punto de vista frecuencial, la cuantificación añade ruido blanco que se extiende por toda la banda de la señal (desde 0 Hz hasta la mitad de la frecuencia de muestreo \(\frac{f_s}{2}\).
    • Truncado: truncar significa redondear hacia abajo un valor. Esto hace que el error que se comete sea como máximo -Q y de media sea -Q/2. Sin embargo, computacionalmente es sencillo.
    • Redondeo:  se redondea al número más cercano. Es decir, se redondea hacia arriba si supera Q/2 y hacia abajo si el valor está por debajo de Q/2.

Implementación del redondeo o del truncado

En MATLAB tenemos las funciones floor() o round() que hacen el truncado o el redondeo respectivamente de la parte entera del número. Por tanto, si queremos redondear a 2 decimales el número 12.5432 lo que hay que hacer es:

  • Desplazamos dos dígitos hace la izquierda el número multiplicando por 100: 12.5432 · 100 = 1254.32
  • Aplicamos la función de truncado o redondedo: floor(1254.32) = 1254
  • Desplazamos de nuevo dos dígitos hacia la derecha el resultado diviendo por 100: 1254/100 = 12.54

En binario ocurre lo mismo, con la diferencia de que en lugar de multiplicar por potencias de 10 (100 en el caso anterior) hay que hacer por potencias de 2.

Ejemplo: truncar a 3 bits fraccionales \(1.28515625 = (01.01001001)_2\)

  • Desplazamos hacia la izquierda 3 posiciones multiplicando por \(2^3\): \(1.28515 \cdot 2^3 =  10.2812\)
  • Se aplica la función floor() al resultado: floor(10.2812) = 10
  • Se desplaza hacia la derecha 3 posiciones multiplicando por \(2^{-3}\): \( 10 \cdot 2^{-3} = 1.25 = (01.010)_2\)

Cuantificación de números en punto fijo con MATLAB

En MATLAB existe la función quantize(q, a) que sirve para calcular cuál va a ser el número con el que se va a cuantificar en binario un número. La función quantize() tiene donde argumentos:

  • q: es el cuantificador que define la codificación a utilizar. Se define con la función quantize(Format, Mode, Roundmode, Overflowmode), donde:
    • Format: [N b]
    • Mode: ‘fixed’ o ‘ufixed’ para codificación de punto fijo con signo o sin signo.
    • Roundmode: ‘floor’ para truncado, ‘round’ para redondeo.
    • Overflowmode: ‘saturate’ para saturar o ‘wrap’ para que desdoble el valor.
  • a: número a cuantificar.

Definición de punto fijo en Simulink

En Simulink se utiliza la función fixdt(Signed, WordLength, FractionLength) para definir el formato de la codificación.

Modificación de la resolución o escalado

Ampliación de la resolución

Se da cuando pasamos a representar la parte fraccional del número con más bits de los originales. Esta operación es tan sencilla como rellenar con ceros a la derecha del número.

Reducción de la resolución

La parte fraccional del númnero se represetnará con menos bits que los originales y por tanto, la resolución disminuye.

Ejemplo:

\(A = 2.625 = (010.101)_2\)

\(A [6,3] \rightarrow A =  A_e \cdot 2^{-3} =(010101)_2 ~~A_e = (010101)_2 21 \)

\(A’ [4,1] \rightarrow A’ =  A’_e \cdot 2^{-2} =(0101)_2~~A’_e = (0101)_2 = 5 \)

Esta operación se puede entender intuitivamente como que la parte entera del número cambia. Es decir, en el número original \(A_e = 21\) porque se utilizan 6 bits. Si truncamos con 4 bits y reinterpretamos la parte entera (leyendo los bits como un número binario entero), la parte entera \(A’_e\) disminuye. Finalmente, si se reescala en función de la posición del punto fijo, se obtiene el nuevo número.

Ejemplo:

\(A’_e = floor\left(A_e \cdot 2^{-2}\right) = 5\)

En este caso, se multiplica por \(2^{-2}\) porque hay que pasar de escala \(2^3\) a \(2^1\). Por tanto, hay que mover el punto a la derecha 2 posiciones.

Suma/resta

Sin pérdida de resolución

Ambos sumandos deben tener el mismo tamaño y escalado. Si no lo tienenm hay que extender el rango del número con menos bits en la parte fraccional.

El número total de bits del resultado es la suma de:

  • Máximo número de bits en la parte entera de los dos sumandos
  • Máximo número de bits en la parte fraccional de los dos sumandos
  • \(ceil\left[ \log_2{\left(\text{numero de sumas}\right)}\right]\). Si solo se hace una suma, el resultado es 1 bit extra.

Ejemplo:

A[6,5], B[8,2], S[12,5]

A = 0.53125, B = 3.25

\(A_e = A \cdot 2^5 = 17\), \(B_e = B \cdot 2^2 = 13\)

La suma que tenemos que realizar se puede visualizar de la siguiente manera:

Como vemos, hay que rellenar con 0’s en la parte baja de B. Si no lo hacemos, y sumamos las partes enteras directamente, estaremos sumando bits con pesos diferentes. En decimal sería equivalente a sumar decenas con centenas y centenas con millares. Obviamente, el resultado de esta operación será erroneo. Es por ello, que al añadir 0, hay que reinterpretar el número decimal que obtenemos. Es decir:

De esta manera, el LSB de B ya no tendrá un peso de \(2^0\), sino que pasará a tener un peso de \(2^3\).

Esta operación se puede realizar en decimal como multiplicar por una potencia de 2 elevado al número de desplazamientos hacia la izquierda que queramos. En este caso:

\[ B’_e = B_e \cdot 2^3 = 104 \]

De esta manera ya podemos hacer la suma de \(S_e = A_e + B’_e = 17 + 104 = 121\). Con este resultado, podemos calcular S subiendo el coma 5 posiciones multiplicando por \(2^{-s}\). Es decir, \(S = S_e \cdot 2^{-b} = 121 \cdot 2^{-5} = 3.78125\)

Con pérdida de precisión

El crecimiento natural de la operación suma es el que habíamos dicho en el apartado anterior. Sin embargo, es posible que en nuestro diseño queramos que el resultado de la operación tenga un formato menor al que marca el crecimiento natural. En este caso, tenemos que hacer la suma de la misma manera que habíamos explicado en el apartado anterior y una vez obtenido el resultado, realizar el truncado (o redondeo) del número.

Ejemplo: S = A + B

A[6,5] = 0.53125, B[8,3] = 3.125, S[9,2]

Sin perder precisión, el resultado de la suma es S = 3.65625.

\(A_e = 0.53125 \cdot 2^5 = 17 \)

\(B_e = 3.125 \cdot 2^3 = 25 \)

Primero, tenemos que alinear los pesos de \(A_e\) y \(B_e\). Para ello, hay que añadir 2 ceros a la derecha de \(B_e\), por lo que hay que desplazar hacia la izquierda dos posiciones los bits de \(B_e\).

\(B’_e = 25 \cdot 2^2 = 100 \)

Ahora, ya podemos sumar las partes enteras de A y B obteniendo:

\(S’e = A_e + B’_e = 17 + 100 = 117\)

Ahora hay que realizar el truncado (o redondeo, dependiendo de la aplicación). Al resultado de \(S’e\), debemos quitarle los tres últimos bits. Para ello, desplazamos hacia de derecha 3 posiciones, hacemos la operación floor() y finalmente calculamos S multiplicando por su escalado:

\[ S = floor\left( S’_e \cdot 2^{-3} \right) 2^{-2} = 3.5 \]

Multiplicación

Al multiplicar dos números, el formato del resultado equivale a la suma de bits de ambos operandos. Es decir:

A[Na, a], B[Nb, b], P[Np,p]

Np = Na + Nb

p = a + b

A diferencia de la suma, no es necesario alinear los pesos de los operandos, sino que es suficiente con multiplicar bit a bit y realizar el escalado correspondiente al final.

Sin embargo, debido a que el crecimiento de esta operación es tan grande, normalmente se recorta la precisión de la salida.

Ejemplo:

A[6,5], B[8,2], P = A·B [12,5], P = 1.7265625

A = 0.53125, Ae = 17

B = 3.25, Be = 13

\(P = floor(A \cdot B \cdot 2^5) \cdot 2^{-5} = 1.71875 \)

Caso extremo

Como sabemos, la representación en complemento a 2 (2’C) es asimétrica. Es decir, los números con formato [3,2] tienen un rango [-1, 0.75] y no [-1, 1]. En el caso de multiplicar 2 números con formato [3,2], existe un caso extremo que se da cuando los dos números son -1. P = (-1)·(-1) = 1, que resulta estar fuera del rango que este formato puede codificar. Para poder codificarlo, es necesario añadir un bit más en la parte real ([4,2]) cuyo rango es (-2, 1.75). Sin embargo, este bit extra solo se utilizará en el caso de que ambos operandos sean -1. Por tanto, si se conoce que en la aplicación no es posible obtener esos dos valores como operandos de la multiplicación, se puede dimensionar la salida con 1 solo bit entero.

Multiplicación por constante: P = A · K

En el caso de multiplicar por una constante, es posible conocer cuál será el crecimiento máximo del resultado. Debido a que se conoce el rango de A y el valor de K, no todos los valores del rango de P van a ser utilizados. De esta manera, es posible optimizar el formato del resultado.

Ejemplo:

A[8,4], K[5,2], P = A·K [13,6]

K = 2.25, Ke = 9

Para representar Ke solo hacen falta \(ceil(\log_2{Ke}) = 4\) bits. Este será el crecimiento que aportará K y no el que marca su formato (5). Por tanto, cualquier valor de P se podrá representar con [8+4, 4+2] = [12,6], ya que el MSB nunca se utilizará.

 

Sistemas temporales discretos

La definición de sistema discreto en el tiempo corresponde a una transformación o operador que relaciona un conjunto de valor de entrada \(x[n]\) con un conjunto de valores de salida \(y[n]\).
\[ y[n] = T\{x[n]\} \]

Sistemas sin memoria

Son aquellos en los que los valores de salida \(y[n]\) solo dependen de valores presentes de la entrada \(x[n]\). Es decir, no dependen de \(x[n-1]\), \(x[n-2]\), …
Un sistema sin memoria podría ser:
\[ y[n] = \left( x[n] \right)^2 \]

Sistemas lineales

Los sistemas lineales cumplen la propiedad de superposición. Esto significa que la salida será  igual a la suma proporcional de las entradas.

\[ T\{a\cdot x_1[n] + b\cdot x_2[n] \} = a\cdot T\{x_1[n]\} + b\cdot T\{x_[n]\} \]

Sistemas invariantes en tiempo

Un sistema invariante en el tiempo es aquel cuya salida se ve desplazada en tiempo si así lo hace la entrada. Por tanto, un desplazamiento temporal de la señal de entrada, provocará un desplazamiento en la señal de salida. De esta manera, un sistema será invariante si para todo \(n_0\), la señal \(x_1 = x[n-n_0]\) produce una señal a la salida cuyo valor se \(y_1[n] = y[n-n_0]\).

Un ejemplo de un sistema no invariante en tiempo es:
\[ y[n] = x[Mn]\]
La respuesta \(y_1[n-n_0]\) a la entrada \(x_1[n-n_0]\) es:
\[ y_1[n] = x_1[Mn] = x[Mn-n_0] \]
Como vemos, \[ y[n-n_0] = x[M(n-n_0)] \neq y_1[n] \]
Por tanto, el sistema no el invariante.

Sistemas causales

Un sistema causal es aquel que para determinar los valores de salida del sistema, solo se necesiten los valores presentes o pasados de la entrada.

Sistemas estables

Son aquellos que para cada una de las posibles entradas finitas del sistema, la salida siempre es finita. Cada una de las posibles entradas finitas del sistema significa:
\[ |x[n]| \leq B_x < \infty \] Una salida finitia signfica: \[ |y[n]| \leq B_y < \infty \]

Sistemas lineales invariantes en el tiempo

Los sistemas que son invariantes en tiempo y a la vez lineales se pueden estudiar fácilmente a través del operador convolución. De esta manera, es posible obtener cuál va a ser la salida de un sistema en función de su entrada.

Un sistema queda completamente descrito a través de su función de transferencia \(h[n]\). Esta función de transferencia es la salida que obtenemos cuando a la entrada aplicamos un impulso \(\delta[n]\).

Autofunciones en sistemas lineales invariantes

Como hemos visto, los sistemas lineales invariantes son de especial interés debido a que tienen ventajas sobre los sistemas no lineal o no invariantes y es que se puede describir mediante su respuesta impulsional.

Por propiedades de la función \(\delta [n]\), es posible describir la secuencia \(x[n]\) como:
\[ x[n] = \sum_{k=-\infty}^{+\infty} x[k]\cdot \delta[n-k] \]

De este modo, al aplicar la secuencia \(x[k]\) a la entrada de un sistema, su salida será:
\[ y[n] =  T\left\{x[n] \right\} = T\left\{\sum_{k=-\infty}^{+\infty} x[k]\cdot \delta[n-k] \right\} =\sum_{k=-\infty}^{+\infty} x[k]\cdot  T\left\{ \delta[n-k] \right\} \]

Si identificamos la transformación del tren de deltas \( T\left\{ \delta[n-k] \right\}\) como su respuesta impulsional \(h[n]\), obtenemos lo que se conoce como su ecuación de convolución:
\[ y[n] =  \sum_{k=-\infty}^{+\infty} x[k]\cdot  h[n-k] \]

Como ya se explicó en otra entrada, las autofunciones son útiles para la caracterización de sistemas. Las autofunciones son aquellas que al aplicarse en la entrada de un sistema, su salida es la misma que la función de la entrada multiplicada por una constante. Es decir, si \(x[n]\) es una autofunción de \(y[n]\):

\[ y[n] =  T\left\{x[n] \right\} = a \cdot x[n]  \]

donde \(a\) es una constante.

Una de las autofunciones de los sistemas invariantes es la exponencial compleja \(x[n] = z^n\) donde \(z\) es un número complejo cualquiera. Esta función es autofunción de cualquier sistema lineal invariante ya que:
\[ y[n] = \sum_{k=-\infty}^{+\infty} z^{n-k} h[k] = z^n\sum_{k=-\infty}^{+\infty} z^{-k} h[k]   \]

Si esta serie converge, ya que el sumatorio no depende de \(n\), \(y[n]\) puede escribirse como:
\[ y[n] = H(z) z^n\]

Este es lo mismo que decir que si a la entrada de un sistema lineal invariante se aplica una secuencia exponencial \(z^n\), a la salida se obtiene la misma secuencia multiplicada por una constante. Por tanto, queda demostrado que las exponenciales complejas \(z^n\) son autofunciones de un sistema lineal invariante cuyos autovalores están determiandos por:
\[ H(z) =  \sum_{k=-\infty}^{+\infty} z^{-k} h[k] \]

Si se interpreta \(z\) como una variable, \(H(z)\) es una función compleja de variable independiente compleja que se conoce como función de transferencia y describe el comportamiento del sistema frente a cualquier entrada.

Sistemas definidos por ecuaciones en diferencias finitas

Los sistemas discretos se pueden caracterizar, además de por su respuesta impulsional, por ecuaciones en diferencias finitas lineales con coeficientes constantes. Una ecuación en diferencias finitas lineal con coeficientes constantes corresponde a:
\[ \sum_{k=0}^P a_k y[n-k] = \sum_{k=0}^{Q} b_k x[n-k] \]
donde \(x[n]\) es una dato (ya que es la secuencia de entrada), \(y[n]\) es la incógnita de la ecuación y \(a_k\) y \(b_k\) son los coeficientes independientes de \(n\). El orden de la ecuación corresponde al mayor entre \(P\) y \(Q\).

No obstante, si se describe un sistema mediante ecuaciones en diferencias finitas, este no queda totalmente caracterizado debido a la falta de información sobre el estado del sistema antes de aplicar ninguna secuencia a la entrada. Es por eso, que para poder determinar cuál será la salida del sistema a una determinada secuencia, es necesario conocer también las condiciones iniciales del sistema. Por ejemplo, en el sistema que define un sumador:
\[ y[n] = x[n] + y[n-1]\]
si se le aplica una secuencia constante \(x[n] = 1\) para \(n\geq 0\), el valor de \(y[0]\) será:
\[ y[0] = x[0] + y[-1] = 1 + y[-1] \]
Solo se podrá determinar el valor de \(y[0]\) si conocemos \(y[-1]\). Normalmente, el sistema se supone que estaba en reposo y que las condiciones iniciales son \(y[n] = 0\) para \(n<0\). De esta manera, \(y[0] = 1\)
\subsubsection{Sistemas recurrentes y no recurrentes}

Los sistemas recurrentes son aquellos que proporcionan valores de \(y[n]\) en función de valores de la propia salida calculados anteriormente. Es decir:
\[ y[n] = \frac{1}{a_0}\left( \sum_{k=0}^{Q} b_k x[n-k] – \sum_{k=1}^{P} a_k y[n-k]  \right) \]

Si la salida \(y[n]\) solo depende de los valores presentes y pasados de \(x[n]\), o lo que es lo mismo, P = 0, el sistema es no recurrente.

\[ y[n] = \sum_{k=0}^{Q} \frac{b_k}{a_0} x[n-k] \]

Respuesta impulsional

Para obtener la respuesta impulsional de un sistema lineal invariante definido por diferencias finitas, basta con aplicar a la entrada la secuencia exponencial \(x[n] = z^n\). Como hemos visto, esta secuencia es autofunción del sistema y por tanto la salida será:
\[ y[n] = H(z) z^n \]

\(H(z)\) no tiene por qué existir siempre ya que el sumatorio que lo define debe converger.

Un sistema lineal invariante definido por ecuaciones de diferencias finitas, como hemos visto, corresponde a la ecuación:

\[ \sum_{k=0}^P a_k y[n-k] = \sum_{k=0}^{Q} b_k x[n-k] \]

Al sustituir \(x[n]\) e \(y[n]\) en la ecuación, se obtiene:
\[ \sum_{k=0}^P a_k H(z)z^{n-k} = \sum_{k=0}^{Q} b_k z^{n-k} \]

\(H(z)\) no depende de k, por lo que puede salir fuera del sumatorio.

\[ H(z) \sum_{k=0}^P a_k z^{n-k} = \sum_{k=0}^{Q} b_k z^{n-k} \]

Si despejamos \(H(z)\) obtenemos:

\[ H(z) = \frac{\sum_{k=0}^{Q} b_k z^{n-k}}{\sum_{k=0}^P a_k z^{n-k}} = \frac{\sum_{k=0}^{Q} b_k z^{-k}}{\sum_{k=0}^P a_k z^{-k}} \]

Por tanto, la función de transferencia de un sistema caracterizado por una ecuación en diferencias finitas es un cociente de polinomios en \(z^{-1}\) cuyos coeficientes son directamente los coeficientes de la ecuación.

Por ejemplo, si queremos diseñar un sistema de orden 2 no recurrente que cancele un tono a la frecuencia \(\omega_0 = \frac{\pi}{4}\), la ecuación en diferencias finitas debe seguir la siguiente expresión:
\[ y[n] = \sum_{k=0}^Q b_k x[n-k] \]

ya que el sistema es no recurrente. Por ser de orden 2, \(Q=2\). Por tanto, queda calcular los coeficiente \(b_k\).

La entrada del sistema será:
\[ x[n] = \cos{\left(\frac{\pi}{4}n\right)} = \frac{1}{2} \left( e^{j \frac{\pi}{4} n} + e^{-j \frac{\pi}{4} n} \right) \]

Debido a la fórmula de Euler (\(e^{jx} = \cos{x} + j \sin{x}\)), la entrada puede escribirse como combinación lineal de dos exponenciales. Como se ha demostrado, este tipo de funciones son autofunciones del sistema lineal invariante y por tanto la salida será:
\[ y[n] = \frac{1}{2} e^{j \frac{\pi}{4} n} H\left(e^{j \frac{\pi}{4}} \right) + \frac{1}{2} e^{-j \frac{\pi}{4} n} H\left(e^{-j \frac{\pi}{4}} \right)  \]

Para cancelar un tono a esta frecuencia la salida debe ser nula, \( y[n] = 0\). Esto ocurre si:
\[ H\left(e^{j \frac{\pi}{4}} \right) = H\left(e^{-j \frac{\pi}{4}} \right) = 0\]

La función de transferencia \(H(z)\) será:
\[ H(z) = \sum_{k=0}^{Q=2} b_k z^{-k}\]
ya que \(P = 0\) por ser un sistema no recurrente.

Podemos desarrollar \(H(z)\) como:
\[H(z) = b_0 + b_1 z^{-1} + b_2 z^{-2} \]

Esta expresión se puede escribir como un producto de raíces y es equivalente a:
\[ H(z) = b_0 \prod_{i=0}^1 \left(1-z_i z^{-1}\right) = b_0 \left( 1 -z_0 z^{-1}\right) \left(1-z_1 z^{-1} \right)  \]

donde \(z_0 = e^{j \frac{\pi}{4}}\) y \(z_1 = e^{-j \frac{\pi}{4}}\).

Podemos identificar ambas expresiones si desarrollamos este producto:
\[ H(z) = b_0 \left(1 + \left(-z_0-z_1\right) z^{-1} + z_0 z_1 z^{-2} \right) \]

El término \(b_0\) solo determina la ganancia del sistema y puede valer simplemente 1. Por tanto:
\[ b_0 = b_0 = 1\]
\[ b_1 = -z_0 -z_1 = -e^{j \frac{\pi}{4}}-e^{-j \frac{\pi}{4}} = 2\cdot \cos{\frac{\pi}{4}} = \sqrt{2}\]
\[ b_2 = z_0 z_1 = e^{j \frac{\pi}{4}}\cdot e^{-j \frac{\pi}{4}} = 1\]

Finalmente, \(H(z)\) queda como:
\[ H(z) = 1 +  \sqrt{2}z^{-1} + z^{-2} \]

y:

\[ y[n] = 1 + \sqrt{2} z^{-1} + z^{-2} \]

Añadir bibliografía en LaTeX

Para añadir bibliografía en LaTeX a partir de un archivo BibTeX .bib, el archivo BibTeX debe tener la siguiente estrutura:

En el archivo .tex, hay que añadir las siguientes intrucciones:

En \bibliographystyle{unsrt} el argumento puede ser:

plain Estilo normal. Se listan en orden alfabético
unsrt Igual que plain pero aparecen en orden de citación
alpha Igual que plain pero utiliza las etiquetas para identificar la cita en lugar de números
abbrv Igual que plain pero utiliza abreviaciones para los nombres, meses o nombres de revistas

Ahora para citar la referencia en el texto, hay que hacerlo con:

Solo aquellas citas que se hayan llamado en el texto aparecerán en el apartado de referencias.
Si se está usando TexMaker, será necesario compilar varias veces BibTeX y varias veces la compilación rápida para ver los cambios reflejados.