Codificación de línea y sistema de comunicación digital en banda base: práctica con Python

Informática9,1 KB

Codificación de línea

a) Representar la secuencia binaria en el tiempo. Un bit "1" se representará mediante un pulso cuadrado de amplitud unidad y duración T, mientras que un "0" binario se representará mediante ausencia de pulso. El eje de tiempos ha de representar segundos.

import numpy as np
import matplotlib.pyplot as plt

# Parámetros de Tx
Tb = 1       # tiempo de bit (seg)
Rb = 1/Tb    # régimen binario (bits/seg)
Nb = 128     # muestras por bit
fs = Nb/Tb   # frecuencia de muestreo (Hz o muestras/seg)
At = 1       # amplitud (V)
Nbits = 500  # número de bits
N = Nbits * Nb         # número total de muestras
t = np.arange(0, N) / fs

# Fuente de información
Probbit = 0.5
bits = np.random.rand(Nbits) > Probbit  # genero bits aleatorios
bits = bits + 0

# NRZ unipolar de referencia para representar la secuencia binaria
s1 = At * np.ones(Nb)
s0 = np.zeros(Nb)

# Señal de línea de referencia (secuencia binaria en el tiempo)
x = np.zeros(N)
for k in range(Nbits):
    if bits[k] == 1:
        x[k * Nb : (k+1) * Nb] = s1
    else:
        x[k * Nb : (k+1) * Nb] = s0

plt.figure()
plt.subplot(311)
plt.plot(t, x)
plt.xlabel('tiempo (seg)')
plt.ylabel('amplitud (V)')
plt.title('BITS')

b) Representar la secuencia binaria sk(t) a la salida de la codificación de línea. El eje de tiempos ha de representar segundos.

print('0: NRZ unipolar '
      '1: NRZ polar'
      '2: RZ unipolar'
      '3: RZ polar'
      '4: Manchester'
      '5: RZ AMI')
seleccion = int(input('SELECCIONE EL CÓDIGO DE LÍNEA: '))

if seleccion == 0:
    # NRZ unipolar
    s1 = At * np.ones(Nb)
    s0 = np.zeros(Nb)
elif seleccion == 1:
    # NRZ polar
    s1 = At * np.ones(Nb)
    s0 = -At * np.ones(Nb)
elif seleccion == 2:
    # RZ unipolar
    s1 = np.append(At * np.ones(Nb//2), np.zeros(Nb//2))
    s0 = np.zeros(Nb)
elif seleccion == 3:
    # RZ polar
    s1 = np.append(At * np.ones(Nb//2), np.zeros(Nb//2))
    s0 = np.append(-At * np.ones(Nb//2), np.zeros(Nb//2))
elif seleccion == 4:
    # MANCHESTER
    s1 = np.append(At * np.ones(Nb//2), -At * np.ones(Nb//2))
    s0 = np.append(-At * np.ones(Nb//2), At * np.ones(Nb//2))
elif seleccion == 5:
    # RZ AMI
    s1 = np.append(At * np.ones(Nb//2), np.zeros(Nb//2))
    s0 = np.zeros(Nb)
else:
    print('Codificación de línea no disponible')
    exit(0)

# Señal de línea sk(t) a la salida del codificador de línea
s = np.zeros(N)
for k in range(Nbits):
    if bits[k] == 1:
        s[k * Nb : (k+1) * Nb] = s1
        if seleccion == 5:
            s1 = -s1   # alternancia en RZ-AMI
    else:
        s[k * Nb : (k+1) * Nb] = s0

plt.subplot(312)
plt.plot(t, s)
plt.xlabel('tiempo (seg)')
plt.ylabel('amplitud (V)')
plt.title('Señal de línea')

c) Representar la transformada de Fourier S(f) a la salida del codificador de línea para una mejor observación de la distribución de la energía en la banda de frecuencia. El eje de frecuencia ha de representar hercios, mientras que el eje de ordenadas representará magnitud.

# TRANSFORMADA DE FOURIER de la señal de línea
S = np.abs(np.fft.fft(s, 10 * len(s)) / len(s))
f = np.arange(-fs/2, fs/2, fs/len(S))

plt.subplot(313)
plt.plot(f, np.fft.fftshift(S))
plt.xlabel('frecuencia (Hz)')
plt.ylabel('Magnitud')
plt.title('TF')

plt.tight_layout()
plt.show()

Sistema de comunicación digital en banda base

import numpy as np
import matplotlib.pyplot as plt
from scipy.special import erfc
from scipy.signal import convolve

# Parámetros de Tx
Tb = 1       # tiempo de bit (seg)
Rb = 1/Tb    # régimen binario (bits/seg)
Nb = 128     # muestras por bit
fs = Nb/Tb   # frecuencia de muestreo (Hz o muestras/seg)
At = 1       # amplitud (V)
Nbits = 5000
N = Nbits * Nb
t = np.arange(0, N) / fs

# Fuente de información
Probbit = 0.5
bits = np.random.rand(Nbits) > Probbit
bits = bits + 0

a) La señal recibida r(t) estará formada por una señal n(t) de ruido (AWGN) con una densidad espectral de potencia η y la señal en línea sk(t). Para este propósito es necesario desnormalizar el vector de salida devuelto por la función np.random.randn(N) de Python, obteniendo una potencia media de ruido (varianza) mediante el código:

n = √(η fs / 2) · np.random.randn(N)

# CODIFICADOR DE LÍNEA (aquí se ha usado Manchester)
# NRZ unipolar
# s1 = At * np.ones(Nb)
# s0 = np.zeros(Nb)

# MANCHESTER
s1 = np.append(At * np.ones(Nb//2), -At * np.ones(Nb//2))
s0 = np.append(-At * np.ones(Nb//2), At * np.ones(Nb//2))

# Señal de línea sk(t)
x = np.zeros(N)
for k in range(Nbits):
    if bits[k] == 1:
        x[k * Nb : (k+1) * Nb] = s1
    else:
        x[k * Nb : (k+1) * Nb] = s0

# Rango de densidades espectrales de potencia (η = nu)
nuvector = np.arange(0.1, 0.01, -0.001) * 10
Pe_prac_all = []
Pe_teor_all = []

for nu in nuvector:
    # MEDIO DE TX: ruido AWGN
    n = np.sqrt(fs * nu / 2) * np.random.randn(N)
    r = x + n          # r(t) = sk(t) + n(t)

b) Genere la señal d(t) a la salida del filtro adaptado, la cual es la señal r(t) filtrada por el filtro adaptado, h(t) = s0(T−t) − s1(T−t).

    # RECEPTOR – FILTRO ADAPTADO
    h = s0[::-1] - s1[::-1]      # h(t) = s0(T-t) - s1(T-t)
    d = convolve(r, h) / fs
    d = d[:N]
    # Aquí d(t) es la salida del filtro adaptado

c) Simule el muestreador, teniendo en cuenta que el instante de muestreo óptimo se produce en t = nT.

    # MUESTREADOR: valores en instantes óptimos t = nT
    F = d[Nb-1::Nb]

F[k] son las muestras d(kTb).

d) En el decisor, el umbral utilizado U = (E0 − E1) / 2 determina los bits de salida con una probabilidad de error óptima, siendo E0 la energía de la señal s0(t) y viceversa.

    # ENERGÍAS DE SÍMBOLO
    E0 = np.sum(s0**2) / fs
    E1 = np.sum(s1**2) / fs

    # UMBRAL ÓPTIMO
    U = (E0 - E1) / 2

    # DECISOR
    bitsrx = F < U

e) Considerando en el transmisor codificación NRZ–unipolar y ruido AWGN cuya densidad espectral de potencia η varía en el rango indicado, represente la probabilidad de error real y teórica en función de (Es/η). Analice los casos con filtro adaptado procedente de distintas codificaciones.

Para este apartado debe usarse NRZ unipolar en el Tx. En el código ya está preparado: basta con activar estas líneas y comentar las de Manchester:

# CODIFICADOR DE LÍNEA – para el apartado (e) NRZ unipolar
s1 = At * np.ones(Nb)
s0 = np.zeros(Nb)

# (comentar las líneas de Manchester):
# s1 = np.append(At * np.ones(Nb//2), -At * np.ones(Nb//2))
# s0 = np.append(-At * np.ones(Nb//2), At * np.ones(Nb//2))

El cálculo de Pe práctico y teórico ya está en el bucle:

    # BER PRÁCTICA
    Pe_prac = np.sum(bits != bitsrx) / Nbits

    Es = E0*0.5 + E1*0.5

    # BER TEÓRICA (para señales antipodales; en el código)
    # Pe_teor = (1/2) * erfc(np.sqrt(Es / (2 * nu)))  # unipolar (comentado)
    Pe_teor = (1/2) * erfc(np.sqrt(Es / nu))         # polar

    Pe_prac_all.append(Pe_prac)
    Pe_teor_all.append(Pe_teor)

Y la representación final:

plt.plot(Es/nuvector, Pe_prac_all, 'o', label="BER práctica")
plt.plot(Es/nuvector, Pe_teor_all, 'x', label="BER teórica")
plt.xlabel('Es/nu (dB)')
plt.ylabel('BER')
plt.legend()
plt.xscale('log')
plt.tight_layout()
plt.show()

f) Considerando en el transmisor codificación Manchester y ruido AWGN cuya densidad espectral de potencia η varía en el rango indicado, represente la probabilidad de error real y teórica en función de (Es/η). Analice qué ocurre cuando se utiliza en el receptor el filtro adaptado procedente de distintas codificaciones.

Este apartado corresponde al código activo: Tx Manchester, filtro adaptado h = s0(T−t) − s1(T−t), bucle sobre nuvector, cálculo de BER práctica (Pe_prac) y teórica (Pe_teor) y la gráfica final.

Las líneas clave son:

# CODIFICADOR DE LÍNEA – Manchester (apartado f)
s1 = np.append(At * np.ones(Nb//2), -At * np.ones(Nb//2))
s0 = np.append(-At * np.ones(Nb//2), At * np.ones(Nb//2))

# ... resto del código igual: ruido, filtro adaptado, muestreador,
# umbral U, bitsrx, Pe_prac, Pe_teor y la gráfica final.

Descargar

PDF Word HTML