# Authors: Veeresh Taranalli # 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