openofdm/scripts/commpy/channels.py
2017-04-03 12:52:21 -04:00

176 lines
5.5 KiB
Python

# Authors: Veeresh Taranalli <veeresht@gmail.com>
# License: BSD 3-Clause
"""
============================================
Channel Models (:mod:`commpy.channels`)
============================================
.. autosummary::
:toctree: generated/
bec -- Binary Erasure Channel.
bsc -- Binary Symmetric Channel.
awgn -- Additive White Gaussian Noise Channel.
"""
from numpy import complex, sum, pi, arange, array, size, shape, real, sqrt
from numpy import matrix, sqrt, sum, zeros, concatenate, sinc
from numpy.random import randn, seed, random
#from scipy.special import gamma, jn
#from scipy.signal import hamming, convolve, resample
#from scipy.fftpack import ifft, fftshift, fftfreq
#from scipy.interpolate import interp1d
__all__=['bec', 'bsc', 'awgn']
def bec(input_bits, p_e):
"""
Binary Erasure Channel.
Parameters
----------
input_bits : 1D ndarray containing {0, 1}
Input arrary of bits to the channel.
p_e : float in [0, 1]
Erasure probability of the channel.
Returns
-------
output_bits : 1D ndarray containing {0, 1}
Output bits from the channel.
"""
output_bits = input_bits.copy()
output_bits[random(len(output_bits)) <= p_e] = -1
return output_bits
def bsc(input_bits, p_t):
"""
Binary Symmetric Channel.
Parameters
----------
input_bits : 1D ndarray containing {0, 1}
Input arrary of bits to the channel.
p_t : float in [0, 1]
Transition/Error probability of the channel.
Returns
-------
output_bits : 1D ndarray containing {0, 1}
Output bits from the channel.
"""
output_bits = input_bits.copy()
flip_locs = (random(len(output_bits)) <= p_t)
output_bits[flip_locs] = 1 ^ output_bits[flip_locs]
return output_bits
def awgn(input_signal, snr_dB, rate=1.0):
"""
Addditive White Gaussian Noise (AWGN) Channel.
Parameters
----------
input_signal : 1D ndarray of floats
Input signal to the channel.
snr_dB : float
Output SNR required in dB.
rate : float
Rate of the a FEC code used if any, otherwise 1.
Returns
-------
output_signal : 1D ndarray of floats
Output signal from the channel with the specified SNR.
"""
avg_energy = sum(abs(input_signal) * abs(input_signal))/len(input_signal)
snr_linear = 10**(snr_dB/10.0)
noise_variance = avg_energy/(2*rate*snr_linear)
if input_signal.dtype == complex:
noise = (sqrt(noise_variance) * randn(len(input_signal))) + (sqrt(noise_variance) * randn(len(input_signal))*1j)
else:
noise = sqrt(2*noise_variance) * randn(len(input_signal))
output_signal = input_signal + noise
return output_signal
# =============================================================================
# Incomplete code to implement fading channels
# =============================================================================
#def doppler_jakes(max_doppler, filter_length):
# fs = 32.0*max_doppler
# ts = 1/fs
# m = arange(0, filter_length/2)
# Generate the Jakes Doppler Spectrum impulse response h[m]
# h_jakes_left = (gamma(3.0/4) *
# pow((max_doppler/(pi*abs((m-(filter_length/2))*ts))), 0.25) *
# jn(0.25, 2*pi*max_doppler*abs((m-(filter_length/2))*ts)))
# h_jakes_center = array([(gamma(3.0/4)/gamma(5.0/4)) * pow(max_doppler, 0.5)])
# h_jakes = concatenate((h_jakes_left[0:filter_length/2-1],
# h_jakes_center, h_jakes_left[::-1]))
# h_jakes = h_jakes*hamming(filter_length)
# h_jakes = h_jakes/(sum(h_jakes**2)**0.5)
# -----------------------------------------------------------------------------
# jakes_psd_right = (1/(pi*max_doppler*(1-(freqs/max_doppler)**2)**0.5))**0.5
# zero_pad = zeros([(fft_size-filter_length)/2, ])
# jakes_psd = concatenate((zero_pad, jakes_psd_right[::-1],
# jakes_psd_right, zero_pad))
#print size(jakes_psd)
# jakes_impulse = real(fftshift(ifft(jakes_psd, fft_size)))
# h_jakes = jakes_impulse[(fft_size-filter_length)/2 + 1 : (fft_size-filter_length)/2 + filter_length + 1]
# h_jakes = h_jakes*hamming(filter_length)
# h_jakes = h_jakes/(sum(h_jakes**2)**0.5)
# -----------------------------------------------------------------------------
# return h_jakes
#def rayleigh_channel(ts_input, max_doppler, block_length, path_gains,
# path_delays):
# fs_input = 1.0/ts_input
# fs_channel = 32.0*max_doppler
# ts_channel = 1.0/fs_channel
# interp_factor = fs_input/fs_channel
# channel_length = block_length/interp_factor
# n1 = -10
# n2 = 10
# filter_length = 1024
# Generate the Jakes Doppler Spectrum impulse response h[m]
# h_jakes = doppler_jakes(max_doppler, filter_length)
# Generate the complex Gaussian Random Process
# g_var = 0.5
# gain_process = zeros([len(path_gains), block_length], dtype=complex)
# delay_process = zeros([n2+1-n1, len(path_delays)])
# for k in xrange(len(path_gains)):
# g = (g_var**0.5) * (randn(channel_length) + 1j*randn(channel_length))
# g_filt = convolve(g, h_jakes, mode='same')
# g_filt_interp = resample(g_filt, block_length)
# gain_process[k,:] = pow(10, (path_gains[k]/10.0)) * g_filt_interp
# delay_process[:,k] = sinc((path_delays[k]/ts_input) - arange(n1, n2+1))
#channel_matrix = 0
# channel_matrix = matrix(delay_process)*matrix(gain_process)
# return channel_matrix, gain_process, h_jakes