def gfdm_rx_fft2(y, filtertype, alpha, M, K, L, N, QAM, J): """ y: transmitted gfdm-block (length: M*K samples) filtertype: ('rrc'|'rc') alpha: (0,1) float M: number of slots K: number of subcarriers L: freq-domain length of filter Low-complexity receiver implementation as proposed by G.Fettweis (based on sparse frequency Domain Processing) output: demodulated samples in original order (first K samples in timeslot 1, second K ...) """ h = gfdm_filter_taps(filtertype, alpha, M, K, 1) h = np.roll(h, h.shape[-1] / 2) H_rx = np.fft.fft(h) H_sparse = np.concatenate((H_rx[0:M * L / 2], H_rx[-M * L / 2:])) y_ifft = np.array([]) y = (1.0 / K) * y # Transfer input to frequency domain and center around 0th frequency bin y_f = np.fft.fftshift(np.fft.fft(y)) # Filter and superposition in frequency domain Y_fs = gfdm_rx_filsup(y_f, H_sparse, M, K, L) # Demodulate per subcarrier y_ifft = gfdm_rx_demod(Y_fs, K) if J > 0: y_ifft = gfdm_rx_sic(K, M, J, H_sparse, y_ifft, Y_fs, QAM) y_ifft = np.reshape(y_ifft, (K * M)) # Sort output in timeslot,subcarrier order y_ifft = reshape_input(y_ifft, K, M) return y_ifft
def gfdm_rx_fft2(y, filtertype, alpha, M, K, L, N, QAM, J): ''' y: transmitted gfdm-block (length: M*K samples) filtertype: ('rrc'|'rc') alpha: (0,1) float M: number of slots K: number of subcarriers L: freq-domain length of filter Low-complexity receiver implementation as proposed by G.Fettweis (based on sparse frequency Domain Processing) output: demodulated samples in original order (first K samples in timeslot 1, second K ...) ''' h = gfdm_filter_taps(filtertype, alpha, M, K, 1) h = np.roll(h, h.shape[-1] / 2) H_rx = np.fft.fft(h) H_sparse = np.concatenate((H_rx[0:M * L / 2], H_rx[-M * L / 2:])) y_ifft = np.array([]) y = (1.0 / K) * y # Transfer input to frequency domain and center around 0th frequency bin y_f = np.fft.fftshift(np.fft.fft(y)) # Filter and superposition in frequency domain Y_fs = gfdm_rx_filsup(y_f, H_sparse, M, K, L) # Demodulate per subcarrier y_ifft = gfdm_rx_demod(Y_fs, K) if J > 0: y_ifft = gfdm_rx_sic(K, M, J, H_sparse, y_ifft, Y_fs, QAM) y_ifft = np.reshape(y_ifft, (K * M)) # Sort output in timeslot,subcarrier order y_ifft = reshape_input(y_ifft, K, M) return y_ifft
def compare_subcarrier_location(alpha, M, K, overlap, oversampling_factor): import matplotlib.pyplot as plt import matplotlib.cm as cm goofy_ordering = False taps = gfdm_filter_taps('rrc', alpha, M, K, oversampling_factor) A0 = gfdm_modulation_matrix(taps, M, K, oversampling_factor, group_by_subcarrier=goofy_ordering) n = np.arange(M * K * oversampling_factor, dtype=np.complex) colors = iter(cm.rainbow(np.linspace(0, 1, K))) for k in range(K): color = next(colors) f = np.exp(1j * 2 * np.pi * (float(k) / (K * oversampling_factor)) * n) F = abs(np.fft.fft(f)) fm = np.argmax(F) / M plt.plot(F, '-.', label=k, color=color) data = get_zero_f_data(k, K, M) x0 = gfdm_gr_modulator(data, 'rrc', alpha, M, K, overlap, compat_mode=goofy_ordering) * (2. / K) f0 = 1. * np.argmax(abs(np.fft.fft(x0))) / M plt.plot(abs(np.fft.fft(x0)), label='FFT' + str(k), color=color) xA = A0.dot(get_data_matrix(data, K, group_by_subcarrier=goofy_ordering).flatten()) * (1. / K) fA = np.argmax(abs(np.fft.fft(xA))) / M plt.plot(abs(np.fft.fft(xA)), '-', label='matrix' + str(k), color=color) print fm, fA, f0 plt.legend() plt.show()
def validate_subcarrier_location(alpha, M, K, overlap, oversampling_factor): goofy_ordering = False taps = gfdm_filter_taps('rrc', alpha, M, K, oversampling_factor) A0 = gfdm_modulation_matrix(taps, M, K, oversampling_factor, group_by_subcarrier=goofy_ordering) n = np.arange(M * K * oversampling_factor, dtype=np.complex) for k in range(K): f = np.exp(1j * 2 * np.pi * (float(k) / (K * oversampling_factor)) * n) F = abs(np.fft.fft(f)) fm = 1. * np.argmax(F) / M data = get_zero_f_data(k, K, M) x0 = gfdm_gr_modulator( data, 'rrc', alpha, M, K, overlap, compat_mode=goofy_ordering) * (2. / K) f0 = 1. * np.argmax(abs(np.fft.fft(x0))) / M xA = A0.dot( get_data_matrix( data, K, group_by_subcarrier=goofy_ordering).flatten()) * (1. / K) fA = 1. * np.argmax(abs(np.fft.fft(xA))) / M if not fm == fA == f0: raise RuntimeError( 'ERROR: subcarriers are not located at the same bins!')
def implementation_validation(): M = 33 K = 32 alpha = .5 overlap = 2 H = get_frequency_domain_filter('rrc', alpha, M, K, overlap) taps = gfdm_filter_taps('rrc', alpha, M, K, 1) A = gfdm_modulation_matrix(taps, M, K) tests = 100 max_rel_error = 0.0 for t in range(tests): d = get_random_samples(M * K) xmat = A.dot(d) / np.sqrt(len(d)) D = get_data_matrix(d, K, group_by_subcarrier=True) xfft = gfdm_modulate_block(D, H, M, K, overlap, False) / np.sqrt( len(d)) rel_err = np.linalg.norm(xmat - xfft) / np.linalg.norm(xmat) if rel_err > max_rel_error: max_rel_error = rel_err if rel_err > 1e-3: raise RuntimeError( 'Relative error between FFT and Matrix implementation is above 1e-3!' ) print 'maximum relative error is:', max_rel_error
def main(): ''' This is a comparison for 3 different demodulation approaches. matched filter matrix being the 'benchmark' The other two should converge towards the matrix approach for overlap -> subcarriers Actually, there's a bug in the 'GR' approach, thus it only works for overlap==2 ''' timeslots = 25 subcarriers = 16 overlap = 2 time_taps = gfdm_filter_taps('rrc', .5, timeslots, subcarriers, 1) freq_taps = gfdm_freq_taps(time_taps) sparse_freq_taps = gfdm_freq_taps_sparse(freq_taps, timeslots, overlap) A = gfdm_modulation_matrix(time_taps, timeslots, subcarriers, 1, True) Ainv = np.linalg.inv(A) Amf = np.conjugate(A).T tx_syms = get_random_qpsk(timeslots * subcarriers) rx_syms = A.dot(tx_syms) mf_matrix_rx = Amf.dot(rx_syms) inv_matrix_rx = Ainv.dot(rx_syms) gr_res = gfdm_demodulate_block(rx_syms, sparse_freq_taps, subcarriers, timeslots, overlap) fft_res = gfdm_demodulate_fft_loop(rx_syms, timeslots, subcarriers, overlap, sparse_freq_taps) mf_matrix_rx *= np.sqrt( calculate_average_signal_energy(fft_res) / calculate_average_signal_energy(mf_matrix_rx)) inv_matrix_rx *= np.sqrt( calculate_average_signal_energy(fft_res) / calculate_average_signal_energy(inv_matrix_rx)) gr_res *= np.sqrt( calculate_average_signal_energy(fft_res) / calculate_average_signal_energy(gr_res)) print 'compare demodulation accuracy for different approaches' for e in range(11): em = 10**(-1. * e) matrixvsloop = np.all(np.abs(fft_res - mf_matrix_rx) < em) grvsmatrix = np.all(np.abs(gr_res - mf_matrix_rx) < em) grvsloop = np.all(np.abs(gr_res - fft_res) < em) print 'error margin {:.1e}\tMFmatriXvsGR: {}\tMFmatriXvsLoop: {}\tGRvsLoop: {}'.format( em, grvsmatrix, matrixvsloop, grvsloop)
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 ''' h = gfdm_filter_taps(filtertype, alpha, M, K, 1) H = gfdm_freq_taps(h) H_sparse = gfdm_freq_taps_sparse(H, M, L) # 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 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 ''' h = gfdm_filter_taps(filtertype, alpha, M, K, 1) H = gfdm_freq_taps(h) H_sparse = gfdm_freq_taps_sparse(H, M, L) # 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 return x_t
def preamble_auto_corr_test(): K = 32 pn_seq = get_random_qpsk(K) pn_symbols = np.tile(pn_seq, 2) D = get_data_matrix(pn_symbols, K, True) # print np.shape(D) print 'subcarriers bear same symbols:', np.all(D[0] == D[1]) pl, p = generate_sync_symbol(pn_seq, 'rrc', .5, K, 2, K, K / 2) # print np.shape(p) acc = auto_correlate_halfs(p) print acc, np.angle(acc) taps = gfdm_filter_taps('rrc', .5, 2, K, 1) A = gfdm_modulation_matrix(taps, 2, K) x = A.dot(pn_symbols) # print np.shape(x) acc = auto_correlate_halfs(x) print acc, np.angle(acc)
def preamble_auto_corr_test(): K = 32 pn_seq = get_random_qpsk(K) pn_symbols = np.tile(pn_seq, 2) D = get_data_matrix(pn_symbols, K, True) # print np.shape(D) print 'subcarriers bear same symbols:', np.all(D[0] == D[1]) pl, p = generate_sync_symbol(pn_seq, 'rrc', .5, K, 2, K, K / 2) # print np.shape(p) acc = auto_correlate_halfs(p) print acc, np.angle(acc) taps = gfdm_filter_taps('rrc', .5, 2, K, 1) A = gfdm_modulation_matrix(taps, 2, K) x = A.dot(pn_symbols) # print np.shape(x) acc = auto_correlate_halfs(x) print acc, np.angle(acc)
def validate_subcarrier_location(alpha, M, K, overlap, oversampling_factor): goofy_ordering = False taps = gfdm_filter_taps('rrc', alpha, M, K, oversampling_factor) A0 = gfdm_modulation_matrix(taps, M, K, oversampling_factor, group_by_subcarrier=goofy_ordering) n = np.arange(M * K * oversampling_factor, dtype=np.complex) for k in range(K): f = np.exp(1j * 2 * np.pi * (float(k) / (K * oversampling_factor)) * n) F = abs(np.fft.fft(f)) fm = 1. * np.argmax(F) / M data = get_zero_f_data(k, K, M) x0 = gfdm_gr_modulator(data, 'rrc', alpha, M, K, overlap, compat_mode=goofy_ordering) * (2. / K) f0 = 1. * np.argmax(abs(np.fft.fft(x0))) / M xA = A0.dot(get_data_matrix(data, K, group_by_subcarrier=goofy_ordering).flatten()) * (1. / K) fA = 1. * np.argmax(abs(np.fft.fft(xA))) / M if not fm == fA == f0: raise RuntimeError('ERROR: subcarriers are not located at the same bins!')
def implementation_validation(): M = 33 K = 32 alpha = .5 overlap = 2 H = get_frequency_domain_filter('rrc', alpha, M, K, overlap) taps = gfdm_filter_taps('rrc', alpha, M, K, 1) A = gfdm_modulation_matrix(taps, M, K) tests = 100 max_rel_error = 0.0 for t in range(tests): d = get_random_samples(M * K) xmat = A.dot(d) / np.sqrt(len(d)) D = get_data_matrix(d, K, group_by_subcarrier=True) xfft = gfdm_modulate_block(D, H, M, K, overlap, False) / np.sqrt(len(d)) rel_err = np.linalg.norm(xmat - xfft) / np.linalg.norm(xmat) if rel_err > max_rel_error: max_rel_error = rel_err if rel_err > 1e-3: raise RuntimeError('Relative error between FFT and Matrix implementation is above 1e-3!') print 'maximum relative error is:', max_rel_error
def main(): ''' This is a comparison for 3 different demodulation approaches. matched filter matrix being the 'benchmark' The other two should converge towards the matrix approach for overlap -> subcarriers Actually, there's a bug in the 'GR' approach, thus it only works for overlap==2 ''' timeslots = 25 subcarriers = 16 overlap = 2 time_taps = gfdm_filter_taps('rrc', .5, timeslots, subcarriers, 1) freq_taps = gfdm_freq_taps(time_taps) sparse_freq_taps = gfdm_freq_taps_sparse(freq_taps, timeslots, overlap) A = gfdm_modulation_matrix(time_taps, timeslots, subcarriers, 1, True) Ainv = np.linalg.inv(A) Amf = np.conjugate(A).T tx_syms = get_random_qpsk(timeslots * subcarriers) rx_syms = A.dot(tx_syms) mf_matrix_rx = Amf.dot(rx_syms) inv_matrix_rx = Ainv.dot(rx_syms) gr_res = gfdm_demodulate_block(rx_syms, sparse_freq_taps, subcarriers, timeslots, overlap) fft_res = gfdm_demodulate_fft_loop(rx_syms, timeslots, subcarriers, overlap, sparse_freq_taps) mf_matrix_rx *= np.sqrt(calculate_average_signal_energy(fft_res) / calculate_average_signal_energy(mf_matrix_rx)) inv_matrix_rx *= np.sqrt(calculate_average_signal_energy(fft_res) / calculate_average_signal_energy(inv_matrix_rx)) gr_res *= np.sqrt(calculate_average_signal_energy(fft_res) / calculate_average_signal_energy(gr_res)) print 'compare demodulation accuracy for different approaches' for e in range(11): em = 10 ** (-1. * e) matrixvsloop = np.all(np.abs(fft_res - mf_matrix_rx) < em) grvsmatrix = np.all(np.abs(gr_res - mf_matrix_rx) < em) grvsloop = np.all(np.abs(gr_res - fft_res) < em) print 'error margin {:.1e}\tMFmatriXvsGR: {}\tMFmatriXvsLoop: {}\tGRvsLoop: {}'.format(em, grvsmatrix, matrixvsloop, grvsloop)
def transmitMatrix(filtertype, alpha, M, K, oversampling_factor=1): # replaces old definition. taps = gfdm_filter_taps(filtertype, alpha, M, K, oversampling_factor) return gfdm_modulation_matrix(taps, M, K, oversampling_factor, False)
def transmitMatrix(filtertype, alpha, M, K, oversampling_factor=1): # replaces old definition. taps = gfdm_filter_taps(filtertype, alpha, M, K, oversampling_factor) return gfdm_modulation_matrix(taps, M, K, oversampling_factor, False)
def transmitMatrix(filtertype, alpha, M, K, N): # replaces old definition. taps = gfdm_filter_taps(filtertype, alpha, M, K, N) return gfdm_modulation_matrix(taps, M, K, N, False)