def generate_padded_sync_words(self, f_min, f_max, preamble_length, rrcos=True): s1 = -1-1j s0 = -s1 sync_word = [s0] * preamble_length + [s0, s1, s1, s1, s1, s0, s0, s0, s1, s0, s0, s1] sync_word_padded = [] for bit in sync_word: sync_word_padded += [bit] sync_word_padded += [0] * (self._samples_per_symbol - 1) #rrcos = True if rrcos: filter = filters.rrcosfilter(161, 0.4, 1./self._symbols_per_second, self._sample_rate)[1] sync_word_padded_filtered = numpy.convolve(sync_word_padded, filter, 'full') else: filter = filters.rcosfilter(161, 0.4, 1./self._symbols_per_second, self._sample_rate)[1] sync_word_padded_filtered = sync_word_padded sync_words_shifted = {} for offset in range(f_min, f_max): shift_signal = numpy.exp(complex(0,-1)*numpy.arange(len(sync_word_padded_filtered))*2*numpy.pi*offset/float(self._sample_rate)) sync_words_shifted[offset] = sync_word_padded_filtered * shift_signal sync_words_shifted[offset] = numpy.conjugate(sync_words_shifted[offset][::-1]) return sync_words_shifted
def __init__(self, center, input_sample_rate, search_depth=7e-3, search_window=50e3, symbols_per_second=25000, verbose=False): self._center = center self._input_sample_rate = int(input_sample_rate) self._output_sample_rate = 500000 if self._input_sample_rate % self._output_sample_rate: raise RuntimeError("Input sample rate must be a multiple of %d" % self._output_sample_rate) self._decimation = self._input_sample_rate / self._output_sample_rate self._search_depth = search_depth self._symbols_per_second = symbols_per_second self._output_samples_per_symbol = self._output_sample_rate/self._symbols_per_second self._verbose = verbose #self._verbose = True self._input_low_pass = scipy.signal.firwin(401, float(search_window)/self._input_sample_rate) self._low_pass2= scipy.signal.firwin(401, 10e3/self._output_sample_rate) self._rrc = filters.rrcosfilter(51, 0.4, 1./self._symbols_per_second, self._output_sample_rate)[1] self._sync_search = complex_sync_search.ComplexSyncSearch(self._output_sample_rate, verbose=self._verbose) self._pre_start_samples = int(0.1e-3 * self._output_sample_rate) if self._verbose: print 'input sample_rate', self._input_sample_rate print 'output sample_rate', self._output_sample_rate
def main(): print "\n","*"*80 print "*** Python: Generate Root-Raised Cosine taps ***" if len(sys.argv) < 2: print "Exit: must enter the Length of the filter in samples" return elif len(sys.argv) < 3: print("Exit: must enter the roll-off factor Alpha in the range (0,1)") return elif len(sys.argv) < 4: print("Exit: must enter the symbol period Ts in seconds (1/baud_rate)") return elif len(sys.argv) < 5: print("Exit: must enter the sample rate Fs in Hertz") return elif len(sys.argv) < 6: print("Exit: must enter a value for the Maximum Tap") return elif len(sys.argv) < 7: print("Exit: must enter an output file") return length = int(sys.argv[1]) alpha = float(sys.argv[2]) if alpha <= 0.0 or alpha > 1.0: print("Exit: alpha out of range (0,1)") return Ts = float(sys.argv[3]) Fs = float(sys.argv[4]); max_tap = int(sys.argv[5]); import filters time_idx, h_rrc = filters.rrcosfilter(length, alpha, Ts, Fs) #print time_idx #print h_rrc #set taps scale to integers scale = max(abs(h_rrc)) print scale taps = (np.int16)(h_rrc * max_tap / scale) print taps print sum(taps) print (float)(sum(taps))/(float)(max_tap) #print taps[0:int(np.ceil(length/2.0))] fo = open(sys.argv[6], 'w') #print "\tName of the output file:", fo.name for i in taps[0:int(np.ceil(length/2.0))]: stringy = ''.join(str(i)+'\n') fo.write(stringy) fo.close()
def main(): print "\n","*"*80 print "*** Python: Generate Root-Raised Cosine taps ***" if len(sys.argv) < 2: print "Exit: must enter the Length of the filter in samples" return elif len(sys.argv) < 3: print("Exit: must enter the roll-off factor Alpha in the range (0,1)") return elif len(sys.argv) < 4: print("Exit: must enter the symbol period Ts in seconds (1/baud_rate)") return elif len(sys.argv) < 5: print("Exit: must enter the sample rate Fs in Hertz") return elif len(sys.argv) < 6: print("Exit: must enter a value for the Maximum Tap") return elif len(sys.argv) < 7: print("Exit: must enter an output file") return length = int(sys.argv[1]) alpha = float(sys.argv[2]) if alpha <= 0.0 or alpha > 1.0: print("Exit: alpha out of range (0,1)") return Ts = float(sys.argv[3]) Fs = float(sys.argv[4]); max_tap = int(sys.argv[5]); import filters time_idx, h_rrc = filters.rrcosfilter(length, alpha, Ts, Fs) #print time_idx #print h_rrc #set taps scale to integers scale = max(abs(h_rrc)) print scale taps = (np.int16)(h_rrc * max_tap / scale) print taps print sum(taps) print (float)(sum(taps))/(float)(max_tap) #print taps[0:np.ceil(length/2.0)] fo = open(sys.argv[6], 'w') #print "\tName of the output file:", fo.name for i in taps[0:np.ceil(length/2.0)]: stringy = ''.join(str(i)+'\n') fo.write(stringy) fo.close()
def generate_padded_sync_words(self, f_min, f_max, preamble_length, rrcos=True): s1 = -1 - 1j s0 = -s1 sync_word = [s0] * preamble_length + [ s0, s1, s1, s1, s1, s0, s0, s0, s1, s0, s0, s1 ] sync_word_padded = [] for bit in sync_word: sync_word_padded += [bit] sync_word_padded += [0] * (self._samples_per_symbol - 1) #rrcos = True if rrcos: filter = filters.rrcosfilter(161, 0.4, 1. / self._symbols_per_second, self._sample_rate)[1] sync_word_padded_filtered = numpy.convolve(sync_word_padded, filter, 'full') else: filter = filters.rcosfilter(161, 0.4, 1. / self._symbols_per_second, self._sample_rate)[1] sync_word_padded_filtered = sync_word_padded sync_words_shifted = {} for offset in range(f_min, f_max): shift_signal = numpy.exp( complex(0, -1) * numpy.arange(len(sync_word_padded_filtered)) * 2 * numpy.pi * offset / float(self._sample_rate)) sync_words_shifted[ offset] = sync_word_padded_filtered * shift_signal sync_words_shifted[offset] = numpy.conjugate( sync_words_shifted[offset][::-1]) return sync_words_shifted
def __init__(self, center, input_sample_rate, search_depth=7e-3, search_window=50e3, symbols_per_second=25000, verbose=False): self._center = center self._input_sample_rate = int(input_sample_rate) self._output_sample_rate = 500000 if self._input_sample_rate % self._output_sample_rate: raise RuntimeError("Input sample rate must be a multiple of %d" % self._output_sample_rate) self._decimation = self._input_sample_rate / self._output_sample_rate self._search_depth = search_depth self._symbols_per_second = symbols_per_second self._output_samples_per_symbol = self._output_sample_rate / self._symbols_per_second self._verbose = verbose #self._verbose = True self._input_low_pass = scipy.signal.firwin( 401, float(search_window) / self._input_sample_rate) self._low_pass2 = scipy.signal.firwin(401, 10e3 / self._output_sample_rate) self._rrc = filters.rrcosfilter(51, 0.4, 1. / self._symbols_per_second, self._output_sample_rate)[1] self._sync_search = complex_sync_search.ComplexSyncSearch( self._output_sample_rate, verbose=self._verbose) self._pre_start_samples = int(0.1e-3 * self._output_sample_rate) if self._verbose: print 'input sample_rate', self._input_sample_rate print 'output sample_rate', self._output_sample_rate
def noise_vector(signal_power): n_var = signal_power * 10**(-SNR_dB / 10) # calculate noise power w1 = np.random.normal(0, 1, N) # complex gaussian noise w2 = np.random.normal(0, 1, N) w = ((np.sqrt(n_var / 2)) * (w1 + 1j * w2)) return w # In[5]: alpha = 0.5 # Raised cosine (RRC) filter Fs = 40000000 Ts = 0.000002 #Fs=40000;Ts=0.00005 time_idx, g = filters.rrcosfilter(N, alpha, Ts, Fs) g = np.roll(g, N // 2) #print("Filter Coefficients",g) G, G_indices = GFDM_modulation_matrix(g) # N x N #G = threshold(G, e-16) #print("G Indices", G_indices) #print(np.linalg.det(G)) plt.plot(g) plt.grid(True) plt.show() # In[6]:
def cut_and_downmix(self, signal, search_offset=None, search_window=None, frequency_offset=0): #iq.write("/tmp/foo.cfile", signal) shift_signal = numpy.exp(complex(0,-1)*numpy.arange(len(signal))*2*numpy.pi*search_offset/float(self._input_sample_rate)) signal_filtered = numpy.convolve(signal * shift_signal, self._input_low_pass, mode='same') #iq.write("/tmp/bar.cfile", signal_filtered) signal = signal_filtered[::self._decimation] #iq.write("/tmp/baz.cfile", signal) center = self._center + search_offset #print "new center:", center search_offset = 0 if center + search_offset > 1626000000: preamble_length = 64 else: preamble_length = 16 self._fft_length = int(math.pow(2, int(math.log(self._output_samples_per_symbol*preamble_length,2)))) self._fft_step = self._fft_length / 10 if self._verbose: print 'fft_length', self._fft_length self._update_search_window(search_window) #signal_mag = [abs(x) for x in signal] #plt.plot(normalize(signal_mag)) #begin, signal = self._signal_start(signal, search_offset) #t0 = time.time() begin = self._signal_start(signal[:int(self._search_depth * self._output_sample_rate)], search_offset) #print "_signal_start:", time.time() - t0 if self._verbose: print 'begin', begin signal = signal[begin:] #t0 = time.time() preamble = signal[:self._fft_length] """ preamble = signal[:self._fft_length] preamble_black = numpy.repeat(preamble * numpy.blackman(len(preamble)), 16) result = numpy.correlate(preamble_black, preamble_black, 'full') #result = numpy.correlate(signal, signal, 'full') result = numpy.angle(result[result.size/2:]) print len(result) start_angle = result[0] count = 0 if result[1] > 0: dir = 1 else: dir = -1 #for i in range(int(len(result) * 0.75)): for i in range(len(result)): if i == 0: continue if dir == 1: if result[i] > 0 and result[i-1] < 0: count += 1 max_i = i else: if result[i] < 0 and result[i-1] > 0: count += 1 max_i = i x0 = float(max_i - 1) x1 = float(max_i) y0 = result[max_i - 1] y1 = result[max_i] int_i = -y0 * (x1-x0)/(y1-y0) + x0 guessed = dir * self._output_sample_rate / ((int_i)/float(count)) * 16 print "guessed offset", guessed #plt.plot(result) #plt.show() """ #signal = signal[:begin + self._fft_length/4] #preamble = signal[:self._fft_length] #plt.plot([begin+skip, begin+skip], [0, 1], 'r') #plt.plot([begin+skip+self._fft_length, begin+skip+self._fft_length], [0, 1], 'r') preamble = preamble * numpy.blackman(len(preamble)) # Increase size of FFT to inrease resolution fft_result, fft_freq = self._fft(preamble, len(preamble) * 16) if self._verbose: print 'binsize', (fft_freq[101] - fft_freq[100]) * self._output_sample_rate # Use magnitude of FFT to detect maximum and correct the used bin mag = numpy.absolute(fft_result) max_index = numpy.argmax(mag) if self._verbose: print 'max_index', max_index print 'max_value', fft_result[max_index] print 'offset', fft_freq[max_index] * self._output_sample_rate #see http://www.dsprelated.com/dspbooks/sasp/Quadratic_Interpolation_Spectral_Peaks.html alpha = abs(fft_result[max_index-1]) beta = abs(fft_result[max_index]) gamma = abs(fft_result[max_index+1]) correction = 0.5 * (alpha - gamma) / (alpha - 2*beta + gamma) real_index = max_index + correction #print "fft:", time.time() - t0 #t0 = time.time() offset_freq = (fft_freq[math.floor(real_index)] + (real_index - math.floor(real_index)) * (fft_freq[math.floor(real_index) + 1] - fft_freq[math.floor(real_index)])) * self._output_sample_rate offset_freq+=frequency_offset if self._verbose: print 'correction', correction print 'corrected max', max_index - correction print 'corrected offset', offset_freq #print 'File:',basename,"f=%10.2f"%offset_freq #single_turn = self._output_sample_rate / offset_freq #offset_freq = guessed # Generate a complex signal at offset_freq Hz. shift_signal = numpy.exp(complex(0,-1)*numpy.arange(len(signal))*2*numpy.pi*offset_freq/float(self._output_sample_rate)) # Multiply the two signals, effectively shifting signal by offset_freq signal = signal*shift_signal #print "shift:", time.time() - t0 #t0 = time.time() #print "Sync word start after shift:", complex_sync_search.estimate_sync_word_start(signal, self._output_sample_rate) offset2, phase = self._sync_search.estimate_sync_word_freq(signal[:(preamble_length+16)*self._output_samples_per_symbol], preamble_length) offset2 = -offset2 shift_signal = numpy.exp(complex(0,-1)*numpy.arange(len(signal))*2*numpy.pi*offset2/float(self._output_sample_rate)) signal = signal*shift_signal #offset2 = complex_sync_search.estimate_sync_word_freq(signal[:32*self._output_samples_per_symbol], self._output_sample_rate) offset_freq += offset2 #print "shift2:", time.time() - t0 #plt.plot([cmath.phase(x) for x in signal[:self._fft_length]]) if self._verbose: sin_avg = numpy.average(numpy.sin(numpy.angle(signal[:self._fft_length]))) cos_avg = numpy.average(numpy.cos(numpy.angle(signal[:self._fft_length]))) preamble_phase = math.atan2(sin_avg, cos_avg) print "Original preamble phase", math.degrees(preamble_phase) # Multiplying with a complex number on the unit circle # just changes the angle. # See http://www.mash.dept.shef.ac.uk/Resources/7_6multiplicationanddivisionpolarform.pdf #signal = signal * cmath.rect(1,math.pi/4 - preamble_phase) signal = signal * cmath.rect(1,-phase) #plt.plot([cmath.phase(x) for x in signal[:self._fft_length]]) if self._verbose: sin_avg = numpy.average([math.sin(cmath.phase(x)) for x in signal[:self._fft_length]]) cos_avg = numpy.average([math.cos(cmath.phase(x)) for x in signal[:self._fft_length]]) preamble_phase = math.atan2(sin_avg, cos_avg) print "Corrected preamble phase", math.degrees(preamble_phase) #print numpy.average([x.real for x in signal[:self._fft_length]]) #print numpy.average([x.imag for x in signal[:self._fft_length]]) #print max(([abs(x.real) for x in signal])) #print max(([abs(x.imag) for x in signal])) ntaps= 161 # 10001, 1001, 161, 41 ntaps= 2*int(self._output_sample_rate/20000)+1 rrc = filters.rrcosfilter(ntaps, 0.4, 1./self._symbols_per_second, self._output_sample_rate)[1] signal = numpy.convolve(signal, rrc, 'same') #plt.plot([x.real for x in signal]) #plt.plot([x.imag for x in signal]) if self._verbose: print "preamble I avg",numpy.average(signal[:self._fft_length].real) print "preamble Q avg",numpy.average(signal[:self._fft_length].imag) #print max(([abs(x.real) for x in signal])) #print max(([abs(x.imag) for x in signal])) #plt.plot(numpy.absolute(fft_result)) #plt.plot(fft_freq, numpy.absolute(fft_result)) #plt.plot([], [bins[bin]], 'rs') #plt.plot(mag) #plt.plot(preamble) #plt.show() return (signal, center+offset_freq)
def cut_and_downmix(self, signal, search_offset=None, search_window=None, frequency_offset=0): self._update_search_window(search_offset, search_window) #signal_mag = [abs(x) for x in signal] #plt.plot(normalize(signal_mag)) begin = self._signal_start(signal) if self._verbose: print 'begin', begin # Skip a few samples to have a clean signal signal = signal[begin + self._skip:] preamble = signal[:self._fft_length] #plt.plot([begin+skip, begin+skip], [0, 1], 'r') #plt.plot([begin+skip+self._fft_length, begin+skip+self._fft_length], [0, 1], 'r') preamble = preamble * numpy.blackman(len(preamble)) # Increase size of FFT to inrease resolution fft_result, fft_freq = self._fft(preamble, len(preamble) * 16) if self._verbose: print 'binsize', (fft_freq[100] - fft_freq[101]) * self._sample_rate # Use magnitude of FFT to detect maximum and correct the used bin mag = numpy.absolute(fft_result) max_index = numpy.argmax(mag) if self._verbose: print 'max_index', max_index print 'max_value', fft_result[max_index] print 'offset', fft_freq[max_index] * self._sample_rate #see http://www.dsprelated.com/dspbooks/sasp/Quadratic_Interpolation_Spectral_Peaks.html alpha = abs(fft_result[max_index - 1]) beta = abs(fft_result[max_index]) gamma = abs(fft_result[max_index + 1]) correction = 0.5 * (alpha - gamma) / (alpha - 2 * beta + gamma) real_index = max_index + correction offset_freq = (fft_freq[math.floor(real_index)] + (real_index - math.floor(real_index)) * (fft_freq[math.floor(real_index) + 1] - fft_freq[math.floor(real_index)])) * self._sample_rate offset_freq += frequency_offset if self._verbose: print 'correction', correction print 'corrected max', max_index - correction print 'corrected offset', offset_freq #print 'File:',basename,"f=%10.2f"%offset_freq single_turn = self._sample_rate / offset_freq # Generate a complex signal at offset_freq Hz. shift_signal = numpy.exp( complex(0, -1) * numpy.arange(len(signal)) * 2 * numpy.pi * offset_freq / float(self._sample_rate)) # Multiply the two signals, effectively shifting signal by offset_freq signal = signal * shift_signal #plt.plot([cmath.phase(x) for x in signal[:self._fft_length]]) sin_avg = numpy.average( numpy.sin(numpy.angle(signal[:self._fft_length]))) cos_avg = numpy.average( numpy.cos(numpy.angle(signal[:self._fft_length]))) preamble_phase = math.atan2(sin_avg, cos_avg) if self._verbose: print "Original preamble phase", math.degrees(preamble_phase) # Multiplying with a complex number on the unit circle # just changes the angle. # See http://www.mash.dept.shef.ac.uk/Resources/7_6multiplicationanddivisionpolarform.pdf signal = signal * cmath.rect(1, math.pi / 4 - preamble_phase) #plt.plot([cmath.phase(x) for x in signal[:self._fft_length]]) #sin_avg = numpy.average([math.sin(cmath.phase(x)) for x in signal[:self._fft_length]]) #cos_avg = numpy.average([math.cos(cmath.phase(x)) for x in signal[:self._fft_length]]) #preamble_phase = math.atan2(sin_avg, cos_avg) #print "Corrected preamble phase", math.degrees(preamble_phase) #print numpy.average([x.real for x in signal[:self._fft_length]]) #print numpy.average([x.imag for x in signal[:self._fft_length]]) #print max(([abs(x.real) for x in signal])) #print max(([abs(x.imag) for x in signal])) ntaps = 161 # 10001, 1001, 161, 41 rrc = filters.rrcosfilter(ntaps, 0.4, 1. / self._symbols_per_second, self._sample_rate)[1] signal = numpy.convolve(signal, rrc, 'same') #plt.plot([x.real for x in signal]) #plt.plot([x.imag for x in signal]) if self._verbose: print "preamble I avg", numpy.average( signal[:self._fft_length].real) print "preamble Q avg", numpy.average( signal[:self._fft_length].imag) #print max(([abs(x.real) for x in signal])) #print max(([abs(x.imag) for x in signal])) #plt.plot(numpy.absolute(fft_result)) #plt.plot(fft_freq, numpy.absolute(fft_result)) #plt.plot([], [bins[bin]], 'rs') #plt.plot(mag) #plt.plot(preamble) #plt.show() return (signal, self._center + offset_freq)