def gfdm_filter_taps(filtertype, alpha, M, K, oversampling_factor=1.): N = oversampling_factor if filtertype == "rrc": time_h, h = cp.rrcosfilter(M * K * N, alpha, 1. * K * N, 1.) elif filtertype == "rc": time_h, h = cp.rcosfilter(M * K * N, alpha, 1. * K * N, 1. ) return h
def gfdm_filter_taps(filtertype, alpha, M, K, oversampling_factor=1.): N = oversampling_factor if filtertype == "rrc": time_h, h = cp.rrcosfilter(M * K * N, alpha, 1. * K * N, 1.) elif filtertype == "rc": time_h, h = cp.rcosfilter(M * K * N, alpha, 1. * K * N, 1.) return h
def gfdm_tx_fft2(x, filtertype, alpha, M, K, L, N): ''' x: Input-Array (length: M*K symbols) filtertype: ('rrc'|'rc') alpha: (0,1) float M: number of slots K: number of subcarriers L: freq-domain length of filter Low-complexity transmitter implementation as proposed by G. Fettweis ''' if filtertype == "rrc": time_h, h = cp.rrcosfilter(M * K, alpha, K, 1) elif filtertype == "rc": time_h, h = cp.rcosfilter(M * K, alpha, K, 1) h = np.roll(h, h.shape[-1] / 2) H = np.fft.fft(h) H_sparse = np.concatenate((H[0:(M * L) / 2], H[-(M * L) / 2:])) # Sort Input subcarrierwise x = reshape_input(x, M, K) x_out = np.zeros((M * K) + (L - 1) * M, dtype='complex') for k in xrange(K): # M rows and L columns with respective FFT output # pick symbols per subcarrier x_k = x[k * M:((k + 1) * M)] # perform fft and switch to frequency domain x_f = np.fft.fft(x_k) # copy values of M-point DFT to obtain MK-point DFT x_f_L = np.tile(x_f, L) # make data-vector 'sparse' #x_f_L = np.concatenate((x_f_K[0:(M*L)/2], x_f_K[-(M*L)/2:])) # filter with sparse filter taps in frequency domain x_fil = np.multiply(x_f_L, H_sparse) # Add data-vector to correct position -max neg frequency : 0 : # max_pos_frequency x_out[k * M:(k + L) * M] = x_out[k * M:(L + k) * M] + np.fft.fftshift(x_fil) # Add 'oversampled' parts of first subcarrier to end and 'oversampled' parts # of last subcarrier to start x_first = x_out[0:(L - 1) * M / 2] x_last = x_out[-(L - 1) * M / 2:] x_out = x_out[(L - 1) * M / 2:-(L - 1) * M / 2] x_out[0:(L - 1) * M / 2] = x_out[0:(L - 1) * M / 2] + x_last x_out[-(L - 1) * M / 2:] = x_out[-(L - 1) * M / 2:] + x_first x_t = np.fft.ifft(np.fft.ifftshift(x_out)) x_t = (1.0 / K) * x_t return x_t
def gfdm_tx_fft2(x, filtertype, alpha, M, K, L, N): ''' x: Input-Array (length: M*K symbols) filtertype: ('rrc'|'rc') alpha: (0,1) float M: number of slots K: number of subcarriers L: freq-domain length of filter Low-complexity transmitter implementation as proposed by G. Fettweis ''' if filtertype == "rrc": time_h, h = cp.rrcosfilter(M*K, alpha, K, 1) elif filtertype == "rc": time_h, h = cp.rcosfilter(M*K, alpha, K, 1) h = np.roll(h, h.shape[-1]/2) H = np.fft.fft(h) H_sparse = np.concatenate((H[0:(M*L)/2], H[-(M*L)/2:])) # Sort Input subcarrierwise x = reshape_input(x, M, K) x_out = np.zeros((M*K)+(L-1)*M, dtype='complex') for k in xrange(K): # M rows and L columns with respective FFT output # pick symbols per subcarrier x_k = x[k*M:((k+1)*M)] # perform fft and switch to frequency domain x_f = np.fft.fft(x_k) # copy values of M-point DFT to obtain MK-point DFT x_f_L = np.tile(x_f, L) # make data-vector 'sparse' #x_f_L = np.concatenate((x_f_K[0:(M*L)/2], x_f_K[-(M*L)/2:])) # filter with sparse filter taps in frequency domain x_fil = np.multiply(x_f_L, H_sparse) # Add data-vector to correct position -max neg frequency : 0 : # max_pos_frequency x_out[k*M:(k+L)*M] = x_out[k*M:(L+k)*M] + np.fft.fftshift(x_fil) # Add 'oversampled' parts of first subcarrier to end and 'oversampled' parts # of last subcarrier to start x_first = x_out[0:(L-1)*M/2] x_last = x_out[-(L-1)*M/2:] x_out = x_out[(L-1)*M/2:-(L-1)*M/2] x_out[0:(L-1)*M/2] = x_out[0:(L-1)*M/2] + x_last x_out[-(L-1)*M/2:] = x_out[-(L-1)*M/2:] + x_first x_t = np.fft.ifft(np.fft.ifftshift(x_out)) x_t = (1.0/K)*x_t return x_t
def gfdm_tx_fft(x, filtertype, alpha, M, K): ''' Realization of GFDM-Transmitter in FFT: Required input: x a np.array of length M*K FFT is applied in shifted version (zero-frequency term is centered) First symbol is on -freq_max and last symbol ist on freq_max h: Prototype-filter impulse response s_e[n]:[s_0[n] 0{M-1} s_1[n] .... s_N-1[n] 0{M-1}] x[n] = h (*) (IFFT(s_e[n])) x_gfdm = sum_M(circshift(x[n],nN)) ''' if filtertype == "rrc": time_h, h = cp.rrcosfilter(M*K, alpha, K, 1) elif filtertype == "rc": time_h, h = cp.rcosfilter(M*K, alpha, K, 1) # Initialization of output vector x_out = np.zeros(M*K, dtype='complex') # circulary move filter window to symbol 0 h = np.roll(h, -(M*K/2)) # for each gfdm-block # for each timeslot for m in xrange(M): # select the K next symbols #symbols = np.fft.ifftshift(x[(m*K):(m+1)*K]) symbols = np.fft.ifftshift(np.array([x[k*M+m] for k in xrange(K)])) # transform K symbols to K carriertones in time-domain sym_t = np.fft.ifft(symbols) sym_te = np.array([]) # Repeat result M-times in a vector for m2 in xrange(M): sym_te = np.concatenate((sym_te, sym_t)) # multipy with transmit filter -> better convolve? sym_te = np.convolve(sym_te, h, mode='same') #sym_te = np.multiply(sym_te,h) # shift result m*K samples to the right and add it up to the result # vector x_out = np.add(x_out, np.roll(sym_te, m*K)) return x_out
def gfdm_tx_fft(x, filtertype, alpha, M, K): ''' Realization of GFDM-Transmitter in FFT: Required input: x a np.array of length M*K FFT is applied in shifted version (zero-frequency term is centered) First symbol is on -freq_max and last symbol ist on freq_max h: Prototype-filter impulse response s_e[n]:[s_0[n] 0{M-1} s_1[n] .... s_N-1[n] 0{M-1}] x[n] = h (*) (IFFT(s_e[n])) x_gfdm = sum_M(circshift(x[n],nN)) ''' if filtertype == "rrc": time_h, h = cp.rrcosfilter(M * K, alpha, K, 1) elif filtertype == "rc": time_h, h = cp.rcosfilter(M * K, alpha, K, 1) # Initialization of output vector x_out = np.zeros(M * K, dtype='complex') # circulary move filter window to symbol 0 h = np.roll(h, -(M * K / 2)) # for each gfdm-block # for each timeslot for m in xrange(M): # select the K next symbols #symbols = np.fft.ifftshift(x[(m*K):(m+1)*K]) symbols = np.fft.ifftshift(np.array([x[k * M + m] for k in xrange(K)])) # transform K symbols to K carriertones in time-domain sym_t = np.fft.ifft(symbols) sym_te = np.array([]) # Repeat result M-times in a vector for m2 in xrange(M): sym_te = np.concatenate((sym_te, sym_t)) # multipy with transmit filter -> better convolve? sym_te = np.convolve(sym_te, h, mode='same') #sym_te = np.multiply(sym_te,h) # shift result m*K samples to the right and add it up to the result # vector x_out = np.add(x_out, np.roll(sym_te, m * K)) return x_out
def transmitMatrix(filtertype, alpha, M, K, N): ''' Create Convolution Matrix for pulse shaping filtertype : (rrc,rc) alpha : roll-off-factor sampling_rate : sampling rate (in Hz) symbol_period : symbol period (in s) M : number of symbol time slots K : number of subcarriers h_matrix: array of impulse responses for time slot (0...M-1) ''' if filtertype == "rrc": time_h, h = cp.rrcosfilter(M * K * N, alpha, N * K, 1) elif filtertype == "rc": time_h, h = cp.rcosfilter(M * K * N, alpha, N * K, 1) # Move filter cyclic G_tx = np.array( [np.roll(h, m - (M * K * N / 2)) for m in xrange(M * K * N)]) S_mn = samplingMatrix(M, K * N) S_nm = samplingMatrix(K, M) if N > 1: # if oversampling is specified add zeros to samplingMatrix S_nm = np.insert(S_nm, M * K / 2, np.zeros((M * K * (N - 1), K), dtype='complex'), axis=0) W_H = fourierMatrix(M * K * N).conj().transpose() # Resample Filter G_tx_s = np.dot(G_tx, S_mn) # Resample FourierMatrix W_s = np.dot(S_nm.transpose(), W_H) # compute and use all elements of the main diagonal W_s.dot(G_tx_s) A = np.array([(np.kron(W_s.transpose()[n], G_tx_s[n])) for n in xrange(K * M * N)]) return A
def transmitMatrix(filtertype, alpha, M, K, N): ''' Create Convolution Matrix for pulse shaping filtertype : (rrc,rc) alpha : roll-off-factor sampling_rate : sampling rate (in Hz) symbol_period : symbol period (in s) M : number of symbol time slots K : number of subcarriers h_matrix: array of impulse responses for time slot (0...M-1) ''' if filtertype == "rrc": time_h, h = cp.rrcosfilter(M*K*N, alpha, N*K, 1) elif filtertype == "rc": time_h, h = cp.rcosfilter(M*K*N, alpha, N*K, 1) # Move filter cyclic G_tx = np.array([np.roll(h, m - (M*K*N/2)) for m in xrange(M*K*N)]) S_mn = samplingMatrix(M, K*N) S_nm = samplingMatrix(K, M) if N > 1: # if oversampling is specified add zeros to samplingMatrix S_nm = np.insert( S_nm, M * K / 2, np.zeros((M * K * (N - 1), K), dtype='complex'), axis=0) W_H = fourierMatrix(M*K*N).conj().transpose() # Resample Filter G_tx_s = np.dot(G_tx, S_mn) # Resample FourierMatrix W_s = np.dot(S_nm.transpose(), W_H) # compute and use all elements of the main diagonal W_s.dot(G_tx_s) A = np.array([(np.kron(W_s.transpose()[n], G_tx_s[n])) for n in xrange(K*M*N)]) return A