class Rtl_threading(threading.Thread): def __init__(self, addr, fc, fs, size, times, corr): threading.Thread.__init__(self) self.sdr = RtlSdr(addr) # configure device self.sdr.sample_rate = fs # Hz self.sdr.center_freq = fc # Hz # self.freq_correction = corr; # PPM self.gain_index = 21 # self.sdr.gain='auto' # 36.4 the stdev=0.04 # init param self.addr = addr self.size = size self.times = times self.counter = 0 self.output = np.array(maxn * [0.0], dtype=np.float64) self.keep = True def run(self): # start lock to avoid reading the same data # self.tlock.acquire() while self.keep: self.sdr.gain = gain_list[self.gain_index] output = self.sdr.read_samples(self.size) self.output = output time.sleep(0.05)
def main(): sdr = RtlSdr() print 'Configuring SDR...' sdr.rs = 2.4e6 sdr.fc = 100e6 sdr.gain = 10 print ' sample rate: %0.6f MHz' % (sdr.rs/1e6) print ' center frequency %0.6f MHz' % (sdr.fc/1e6) print ' gain: %d dB' % sdr.gain print 'Reading samples...' samples = sdr.read_samples(256*1024) print ' signal mean:', sum(samples)/len(samples) print 'Testing callback...' sdr.read_samples_async(test_callback, 256*1024) try: import pylab as mpl print 'Testing spectrum plotting...' mpl.figure() mpl.psd(samples, NFFT=1024, Fc=sdr.fc/1e6, Fs=sdr.rs/1e6) mpl.show() except: # matplotlib not installed/working pass print 'Done\n' sdr.close()
class Rtl_threading(threading.Thread): def __init__(self, addr, fc, fs, size, corr): '''Add one more augument, corr''' threading.Thread.__init__(self) self.sdr = RtlSdr(addr) # configure device self.sdr.sample_rate = fs; # Hz self.sdr.center_freq = fc; # Hz # self.freq_correction = corr; # PPM if addr==1: self.sdr.gain = 32.8 else: #0 self.sdr.gain = 32.8 # init param self.addr = addr; self.size = size self.counter = 0; #0.0 0.9 1.4 2.7 3.7 7.7 8.7 12.5 14.4 15.7 16.6 19.7 20.7 22.9 25.4 28.0 29.7 32.8 33.8 36.4 37.2 38.6 40.2 42.1 43.4 43.9 44.5 48.0 49.6 def run(self): # start lock to avoid reading the same data global event, output; #init the synchronization if event.isSet(): event.clear() event.wait() else: event.set() output[self.addr] = self.sdr.read_samples(self.size); def close(self): self.sdr.close();
class Rtl_threading(threading.Thread): def __init__(self, addr, fc, fs, size, times, corr): threading.Thread.__init__(self) self.sdr = RtlSdr(addr) # configure device self.sdr.sample_rate = fs; # Hz self.sdr.center_freq = fc; # Hz # self.freq_correction = corr; # PPM if addr==1: self.sdr.gain = 32.8 # 36.4 the stdev=0.04 else: #0 self.sdr.gain = 32.8 #15.7 0.725 # init param self.addr = addr; self.size = size self.times = times self.counter = 0; #0.0 0.9 1.4 2.7 3.7 7.7 8.7 12.5 14.4 15.7 16.6 19.7 20.7 22.9 25.4 28.0 29.7 32.8 33.8 36.4 37.2 38.6 40.2 42.1 43.4 43.9 44.5 48.0 49.6 def run(self): # start lock to avoid reading the same data # self.tlock.acquire() for x in range(0, self.times): timestamp = int(time.time()); global event; #init the synchronization if event.isSet(): event.clear() event.wait() else: event.set() #read time_str_read = int(time.time()); output = self.sdr.read_samples(self.size); i=0 for value in output: if self.addr == 0: rsamples[i] = value.real; isamples[i] = value.imag; else: rsamples1[i] = value.real; isamples1[i] = value.imag; i+=1;
class Rtl_threading(threading.Thread): def __init__(self, addr): global params threading.Thread.__init__(self) self.sdr = RtlSdr(addr) # configure device self.sdr.sample_rate = params.fs # Hz self.sdr.center_freq = params.fc # Hz self.is_ref = addr == params.ref_addr # self.freq_correction = corr; # PPM if self.is_ref: self.sdr.gain = params.ref_gain else: # 0 self.sdr.gain = params.ech_gain # init param self.addr = addr self.size = params.size # loop self.loop_sw = True def run(self): global event, wf_ech, wf_ref, dsp # init the synchronization # start lock to avoid reading the same data if event.isSet(): event.clear() event.wait() else: event.set() while self.loop_sw: # read print "reading new data~~~" output = self.sdr.read_samples(self.size) if self.is_ref: # ref wf_ref = np.array(output, dtype=np.complex128) else: wf_ech = np.array(output, dtype=np.complex128) if event.isSet(): event.clear() event.wait() else: dsp.new_data() event.set() self.loop_sw = False
def get_data(freq): sdr = RtlSdr() sdr.sample_rate = 2.048e6 sdr.center_freq = int(decimal.Decimal(str(freq) + 'e6')) sdr.freq_correction = 60 sdr.gain = 'auto' data = sdr.read_samples(512) if not data.any(): app.abort(404, 'No data!') d = [] for item in data: d.append(str(item)) js = json.dumps(d) return js
def main(): sdr = RtlSdr() print 'Configuring SDR...' sdr.rs = 2.4e6 sdr.fc = 70e6 sdr.gain = 4 print ' sample rate: %0.6f MHz' % (sdr.rs/1e6) print ' center frequency %0.6f MHz' % (sdr.fc/1e6) print ' gain: %d dB' % sdr.gain print 'Reading samples...' samples = sdr.read_samples(1024) print ' signal mean:', sum(samples)/len(samples) print 'Testing callback...' sdr.read_samples_async(test_callback) sdr.close()
class FMRadio: sample_buffer = Queue.Queue(maxsize=100) base_spectrum = np.ones(5780) def __init__(self,freq,N_samples): self.sample_rate = 1e6 self.decim_r1 = 1e6/2e5 # for wideband fm self.decim_r2 = 2e5/44100 # for baseband recovery self.center_freq = freq+250e3 self.gain = 36 self.N_samples = N_samples self.is_sampling = False self.sdr = RtlSdr() self.sdr.direct_sampling = 1 self.sdr.sample_rate = self.sample_rate self.sdr.center_freq = self.center_freq self.sdr.gain = self.gain self.pa = pyaudio.PyAudio() self.stream = self.pa.open( format = pyaudio.paFloat32, channels = 1, rate = 44100, output = True) adj = 0 hamming = 10*signal.hamming(self.N_samples*.10 + adj) lpf = np.append( np.zeros(self.N_samples*.45),hamming) self.lpf = np.roll(np.fft.fftshift(np.append(lpf,np.zeros(self.N_samples*.45))),int(-.25*self.N_samples)) def __del__(self): print "sdr closed" self.sdr.close() print "pyaudio terminated" self.pa.terminate() def getSamples(self): #N_samples = self.N_samples # 1/24.4 seconds ~46336 #approximately a 2048/44100 amount's time return self.sdr.read_samples(self.N_samples) def getSamplesAsync(self): #Asynchronous call. Meant to be put in a loop w/ a calback fn #print 'gonna sample' self.is_sampling = True samples = self.sdr.read_samples_async(self.sampleCallback,self.N_samples,context=self) def sampleCallback(self,samples,sself): self.is_sampling = False self.sample_buffer.put(samples) #print 'put some samples in the jar' # recursive loop #sself.getSamplesAsync() def demodulate_th(self): while(1): try: samples = self.sample_buffer.get() #samples2 = self.sample_buffer.get() # print 'gottum' except: print "wtf idk no samples?" break out1 = self.demodulate(samples) self.sample_buffer.task_done() #out2 = self.demodulate(samples2) #self.sample_buffer.task_done() audio_out = out1 #np.append(out1,out2) self.play(audio_out) print 'gonna try to finish off the to-do list' sample_buffer.join() def demodulate(self,samples): # DEMODULATION CODE #samples = #self.sample_buffer.get() # LIMITER goes here # low pass & down sampling via fft spectrum = np.fft.fft(samples)*self.lpf toplot = False if(toplot): fig = plt.figure() plt.plot(np.abs(spectrum)) plt.show() # Decimate in two rounds. One to 200k, another to 44.1k # DECIMATE HERE. Note that we're looking at 1MHz bandwidth. n_s = spectrum.size channel_spectrum = spectrum[int(n_s*.75-.5*n_s/self.decim_r1):int(.75*n_s+.5*n_s/self.decim_r1)] #np.append(spectrum[0:int(n_s/self.decim_r1*.5)],spectrum[n_s-int(n_s/self.decim_r1*.5):n_s]) #radio_spectrum -= np.mean(radio_spectrum) #attempt to remove dc bias #print channel_spectrum.size toplot = False if(toplot): fig = plt.figure() plt.plot(np.abs(np.fft.ifftshift(channel_spectrum))) plt.show() lp_samples = np.fft.ifft(np.fft.ifftshift(channel_spectrum)) #lp_samples = self.lowpass_filter(lp_samples,4) power = np.abs(self.rms(lp_samples)) lp_samples /= power #print np.abs(self.rms(lp_samples)) # polar discriminator dphase = np.zeros(lp_samples.size) A = lp_samples[1:lp_samples.size] B = lp_samples[0:lp_samples.size-1] dphase = ( A * np.conj(B) ) #dpm = np.mean(np.abs(dphase)) # normalize # dphase /= dpm #dphase.resize(dphase.size+1) dphase[dphase.size-1] = dphase[dphase.size-2] rebuilt = signal.medfilt(np.angle(dphase)/np.pi,21) # np.cos(dphase) #phase = np.sin(rebuilt) #phase = self.lowpass_filter(phase,8) #rebuilt= self.lowpass_filter(rebuilt,8) toplot = False if toplot: fig = plt.figure() ax = fig.add_subplot(111) ax.plot(rebuilt) plt.show() spectrum = np.fft.fft(rebuilt) #* self.lpf2 n_z = spectrum.size #base_spectrum = np.append(spectrum[0:1024],spectrum[n_z-1024:n_z]) self.base_spectrum = np.append(spectrum[0:int(n_z/self.decim_r2*.5)],spectrum[n_z-int(n_z/self.decim_r2*.5):n_s]) output = np.fft.ifft(self.base_spectrum) output = self.lowpass_filter(np.real(output),8) # just the tip (kills the 19k pilot) # toplot = False # if(toplot): # fig = plt.figure() # plt.plot(np.real(output)) # plt.show() return np.real(output) def updateimg(self,base_spectrum): spectralimg = np.zeros((base_spectrum.size/20,base_spectrum.size/10)) for i in np.r_[0:base_spectrum.size/10]: spectralimg[np.abs(np.fft.fftshift(base_spectrum)[i*10]/10),i] = 1 cv2.imshow('spectrum',spectralimg) def demodulate2(self,samples): # DEMODULATION CODE # LIMITER goes here # low pass & down sampling lp_samples = signal.decimate(self.lowpass_filter(samples,16),int(self.decim_r1)) # polar discriminator A = lp_samples[1:lp_samples.size] B = lp_samples[0:lp_samples.size-1] dphase = ( A * np.conj(B) ) dphase.resize(dphase.size+1) dphase[dphase.size-1] = dphase[dphase.size-2] rebuilt = signal.medfilt(np.angle(dphase)/np.pi,15) # np.cos(dphase) output = signal.decimate(rebuilt,int(self.decim_r2)) return np.real(output) # utility functions # def lowpass_filter(self,x,width): #wndw = np.sinc(np.r_[-15:16]/np.pi)/np.pi wndw = np.kaiser(width,6) #wndw /= np.sum(wndw) new_array = signal.fftconvolve(x, wndw) return new_array[int(width/2):x.size+int(width/2)] # calculate mean average deviation # def mad(self,samples): ave = np.mean(samples) return np.mean(np.abs(samples-ave)) # calculate rms for power # def rms(self,samples): meansq = np.mean(np.square(samples)) return np.sqrt(meansq) def play(self,samples): self.stream.write( samples.astype(np.float32).tostring() ) def start(self): streamer = MakeDaemon(self.demodulate_th) # run demodulation in the 'background' streamer.start() self.count = 0 while(1): if not self.is_sampling: self.getSamplesAsync() # sampler loop
def run_gpu_spectrum_int(num_samp, nbins, gain, rate, fc, t_int): ''' Inputs: num_samp: Number of elements to sample from the SDR IQ per call; use powers of 2 nbins: Number of frequency bins in the resulting power spectrum; powers of 2 are most efficient, and smaller numbers are faster on CPU. gain: Requested SDR gain (dB) rate: SDR sample rate, intrinsically tied to bandwidth in SDRs (Hz) fc: Base center frequency (Hz) t_int: Total effective integration time (s) Returns: freqs: Frequencies of the resulting spectrum, centered at fc (Hz), numpy array p_avg_db_hz: Power spectral density (dB/Hz) numpy array ''' import cupy as cp import cusignal # Force a choice of window to allow converting to PSD after averaging # power spectra WINDOW = 'hann' # Force a default nperseg for welch() because we need to get a window # of this size later. Use the scipy default 256, but enforce scipy # conditions on nbins vs. nperseg when nbins gets small. if nbins < 256: nperseg = nbins else: nperseg = 256 print('Initializing rtl-sdr with pyrtlsdr:') sdr = RtlSdr(device_index=0) try: sdr.rs = rate # Rate of Sampling (intrinsically tied to bandwidth with SDR dongles) sdr.fc = fc sdr.gain = gain print(' sample rate: %0.6f MHz' % (sdr.rs / 1e6)) print(' center frequency %0.6f MHz' % (sdr.fc / 1e6)) print(' gain: %d dB' % sdr.gain) print(' num samples per call: {}'.format(num_samp)) print(' PSD binning: {} bins'.format(nbins)) print(' requested integration time: {}s'.format(t_int)) N = int(sdr.rs * t_int) num_loops = int(N / num_samp) + 1 print(' => num samples to collect: {}'.format(N)) print(' => est. num of calls: {}'.format(num_loops - 1)) # Set up arrays to store power spectrum calculated from I-Q samples freqs = cp.zeros(nbins) p_xx_tot = cp.zeros(nbins, dtype=complex) # Create mapped, pinned memory for zero copy between CPU and GPU gpu_iq = cusignal.get_shared_mem(num_samp, dtype=np.complex128) cnt = 0 # Set the baseline time start_time = time.time() print('Integration began at {}'.format( time.strftime('%a, %d %b %Y %H:%M:%S', time.localtime(start_time)))) # Time integration loop for cnt in range(num_loops): # Move USB-collected samples off CPU and onto GPU for calc gpu_iq[:] = sdr.read_samples(num_samp) freqs, p_xx = cusignal.welch(gpu_iq, fs=rate, nperseg=nperseg, nfft=nbins, noverlap=0, scaling='spectrum', window=WINDOW, detrend=False, return_onesided=False) p_xx_tot += p_xx end_time = time.time() print('Integration ended at {} after {} seconds.'.format( time.strftime('%a, %d %b %Y %H:%M:%S'), end_time - start_time)) print('{} spectra were measured at {}.'.format(cnt, fc)) print('for an effective integration time of {:.2f}s'.format( num_samp * cnt / rate)) half_len = len(freqs) // 2 freqs = np.fft.fftshift(freqs) p_xx_tot = np.fft.fftshift(p_xx_tot) # Compute the average power spectrum based on the number of spectra read p_avg = p_xx_tot / cnt # Convert to power spectral density # See the scipy docs for _spectral_helper(). win = get_window(WINDOW, nperseg) p_avg_hz = p_avg * ((win.sum()**2) / (win * win).sum()) / rate p_avg_db_hz = 10. * cp.log10(p_avg_hz) # Shift frequency spectra back to the intended range freqs = freqs + fc # nice and tidy sdr.close() except OSError as err: print("OS error: {0}".format(err)) raise (err) except: print('Unexpected error:', sys.exc_info()[0]) raise finally: sdr.close() return cp.asnumpy(freqs), cp.asnumpy(p_avg_db_hz)
def run_fswitch_int(num_samp, nbins, gain, rate, fc, fthrow, t_int, fswitch=10): ''' Note: Because a significant time penalty is introduced for each retuning, a maximum frequency switching rate of 10 Hz is adopted to help reduce the fraction of observation time spent retuning the SDR for a given effective integration time. As a consequence, the minimum integration time is 2*(1/fswitch) to ensure the user gets at least one spectrum taken on each frequency of interest. Inputs: num_samp: Number of elements to sample from the SDR IQ timeseries: powers of 2 are most efficient nbins: Number of frequency bins in the resulting power spectrum; powers of 2 are most efficient, and smaller numbers are faster on CPU. gain: Requested SDR gain (dB) rate: SDR sample rate, intrinsically tied to bandwidth in SDRs (Hz) fc: Base center frequency (Hz) fthrow: Alternate frequency (Hz) t_int: Total effective integration time (s) Kwargs: fswitch: Frequency of switching between fc and fthrow (Hz) Returns: freqs_fold: Frequencies of the spectrum resulting from folding according to the folding method implemented in the f_throw_fold (post_process module) p_fold: Folded frequency-switched power, centered at fc,(uncalibrated V^2) numpy array. ''' from .post_process import f_throw_fold import rtlsdr.helpers as helpers # Check inputs: assert t_int >= 2.0 * ( 1.0 / fswitch ), '''At t_int={} s, frequency switching at fswitch={} Hz means the switching period is longer than integration time. Please choose a longer integration time or shorter switching frequency to ensure enough integration time to dwell on each frequency.'''.format( t_int, fswitch) if fswitch > 10: print( '''Warning: high frequency switching values mean more SDR retunings. A greater fraction of observation time will be spent retuning the SDR, resulting in longer wait times to reach the requested effective integration time.''' ) print('Initializing rtl-sdr with pyrtlsdr:') sdr = RtlSdr() try: sdr.rs = rate # Rate of Sampling (intrinsically tied to bandwidth with SDR dongles) sdr.fc = fc sdr.gain = gain print(' sample rate: %0.6f MHz' % (sdr.rs / 1e6)) print(' center frequency %0.6f MHz' % (sdr.fc / 1e6)) print(' gain: %d dB' % sdr.gain) print(' num samples per call: {}'.format(num_samp)) print(' requested integration time: {}s'.format(t_int)) # Total number of samples to collect N = int(sdr.rs * t_int) # Number of samples on each frequency dwell N_dwell = int(sdr.rs * (1.0 / fswitch)) # Number of calls to SDR on each frequency num_loops = N_dwell // num_samp # Number of dwells on each frequency num_dwells = N // N_dwell print(' => num samples to collect: {}'.format(N)) print(' => est. num of calls: {}'.format(N // num_samp)) print(' => num samples on each dwell: {}'.format(N_dwell)) print(' => est. num of calls on each dwell: {}'.format(num_loops)) print(' => num dwells total: {}'.format(num_dwells)) # Set up arrays to store power spectrum calculated from I-Q samples freqs_on = np.zeros(nbins) freqs_off = np.zeros(nbins) p_xx_on = np.zeros(nbins) p_xx_off = np.zeros(nbins) cnt = 0 # Set the baseline time start_time = time.time() print('Integration began at {}'.format( time.strftime('%a, %d %b %Y %H:%M:%S', time.localtime(start_time)))) # Swap between the two specified frequencies, integrating signal. # Time integration loop for i in range(num_dwells): tick = (i % 2 == 0) if tick: sdr.fc = fc else: sdr.fc = fthrow for j in range(num_loops): iq = sdr.read_samples(num_samp) if tick: freqs_on, p_xx = welch(iq, fs=rate, nperseg=nbins, noverlap=0, scaling='spectrum', detrend=False, return_onesided=False) p_xx_on += p_xx else: freqs_off, p_xx = welch(iq, fs=rate, nperseg=nbins, noverlap=0, scaling='spectrum', detrend=False, return_onesided=False) p_xx_off += p_xx cnt += 1 end_time = time.time() print('Integration ended at {} after {} seconds.'.format( time.strftime('%a, %d %b %Y %H:%M:%S'), end_time - start_time)) print('{} spectra were measured, split between {} and {}.'.format( cnt, fc, fthrow)) print('for an effective integration time of {:.2f}s'.format( num_samp * cnt / rate)) half_len = len(freqs_on) // 2 freqs_on = np.fft.fftshift(freqs_on) freqs_off = np.fft.fftshift(freqs_off) p_xx_on = np.fft.fftshift(p_xx_on) p_xx_off = np.fft.fftshift(p_xx_off) # Compute the average power spectrum based on the number of spectra read p_avg_on = p_xx_on / cnt p_avg_off = p_xx_off / cnt # Shift frequency spectra back to the intended range freqs_on = freqs_on + fc freqs_off = freqs_off + fthrow # Fold switched power spectra freqs_fold, p_fold = f_throw_fold(freqs_on, freqs_off, p_avg_on, p_avg_off) # nice and tidy sdr.close() except OSError as err: print("OS error: {0}".format(err)) raise (err) except: print('Unexpected error:', sys.exc_info()[0]) raise finally: sdr.close() return freqs_fold, p_fold
sdr.center_freq = 462562500 print("Current Frequency: ", sdr.center_freq) sdr.freq_correction = 1 sdr.gain = 6 #time = 21 snr_vals = [] #num_samples = int(sdr.sample_rate*time) #print("Collecting ", num_samples, " samples") #while(1): #for i in range(5): while (1): values = sdr.read_samples(1024000) #Calculate Signal Power #SigPower = 20*np.log10(abs(values)/32768) SigPower = 10 * np.log10(10 * ((values.real**2) + (values.imag**2))) #FFT = np.fft.fft(values) #print(FFT) #print('\n') mean = np.mean(SigPower) st_dev = np.std(SigPower) dist_mean = abs(SigPower - mean) max_dev = 1 not_outlier = dist_mean < (max_dev * st_dev) no_outliers = SigPower[not_outlier] Pmax = max(no_outliers) floor = -36 Pmin = min(no_outliers)
print args.output_path + '--' + csvfile + '.csv' sys.stdout.flush() for x in range(0, 1000000): time.sleep(5) cent_freq = (int(low_freq) + (x%steps)) # configure device sample_rate = samp_rate # sdr.freq_correction = 82 #freq = 1379.913e6 # freq = [freq_int*10)+stepsize*x*10 if freq_int*10<(freq_int*10+int(bw)) else cent_freq] print 'low_freq,',low_freq sdr.sample_rate = sample_rate # Hz sdr.center_freq = cent_freq # Hz sdr.gain = 'auto' sampnumber = 8192*2*2*2*2*2*2 samples2 = sdr.read_samples(sampnumber) #ser.write("\x8f\x78" + freq_str + stepsize_str + samples_str) # print freq time.sleep(1) #print "please wait..." #print s # byte_list = map(ord,t) bdrate = 2000 phasesarr=[] phases=np.arctan2((samples2.imag),(samples2.real)) codeword="001001011101010111000000110011101000100110010000111101101100100101000110000110111111011110011100110110100010101000111111001100010111011001101111000010010011011010111001111001000000100001100011" interp = sample_rate/bdrate print 'interp=',interp for qrs in range(0,len(codeword)-1):
class FMRadio: # num samplesmust be multiple of 256 def __init__(self,freq,N_samples): self.sample_rate = 1e6 self.decim_r1 = 1e6/2e5 # for wideband fm self.decim_r2 = 2e5/44100 # for baseband recovery self.center_freq = freq+250e3 self.gain = 36 self.N_samples = N_samples self.sdr = RtlSdr() self.sdr.direct_sampling = 1 self.sdr.sample_rate = self.sample_rate self.sdr.center_freq = self.center_freq self.sdr.gain = 'auto' #self.gain self.pa = pyaudio.PyAudio() self.stream = self.pa.open( format = pyaudio.paFloat32, channels = 2, rate = 44100, output = True) adj = 0 hamming = 10*signal.hamming(self.N_samples*.10 + adj) lpf = np.append( np.zeros(self.N_samples*.45),hamming) self.lpf = np.roll(np.fft.fftshift(np.append(lpf,np.zeros(self.N_samples*.45))),int(-.25*self.N_samples)) def __del__(self): print "sdr closed" self.sdr.close() print "pyaudio terminated" self.pa.terminate() def getSamples(self): #N_samples = self.N_samples # 1/24.4 seconds ~46336 #approximately a blocksize amount's time return self.sdr.read_samples(self.N_samples) # def demodulate_threaded(self,samples): # async_demodulation = self.pool.apply_async(self.demodulate, samples, callback=self.play) def demodulate(self,samples): # DEMODULATION CODE #samples = #self.sample_buffer.get() # LIMITER goes here # low pass & down sampling via fft spectrum = np.fft.fft(samples)*self.lpf toplot = False if(toplot): fig = plt.figure() plt.plot(np.abs(spectrum)) plt.show() # Decimate in two rounds. One to 200k, another to 44.1k # DECIMATE HERE. Note that we're looking at 1MHz bandwidth. n_s = spectrum.size channel_spectrum = spectrum[int(n_s*.75-.5*n_s/self.decim_r1):int(.75*n_s+.5*n_s/self.decim_r1)] #np.append(spectrum[0:int(n_s/self.decim_r1*.5)],spectrum[n_s-int(n_s/self.decim_r1*.5):n_s]) #radio_spectrum -= np.mean(radio_spectrum) #attempt to remove dc bias #print channel_spectrum.size toplot = False if(toplot): fig = plt.figure() plt.plot(np.abs(np.fft.ifftshift(channel_spectrum))) plt.show() lp_samples = np.fft.ifft(np.fft.ifftshift(channel_spectrum)) power = np.abs(self.rms(lp_samples)) lp_samples /= power #lp_samples = self.lowpass_filter(lp_samples,4) # polar discriminator A = lp_samples[1:lp_samples.size] B = lp_samples[0:lp_samples.size-1] dphase = ( A * np.conj(B) ) #dpm = np.mean(np.abs(dphase)) # normalize # dphase /= dpm dphase.resize(dphase.size+1) dphase[dphase.size-1] = dphase[dphase.size-2] rebuilt = signal.medfilt(np.angle(dphase)/np.pi,21) # np.cos(dphase) #phase = np.sin(rebuilt) #phase = self.lowpass_filter(phase,8) #rebuilt= self.lowpass_filter(rebuilt,8) toplot = False if toplot: fig = plt.figure() ax = fig.add_subplot(111) ax.plot(rebuilt) plt.show() modulated = rebuilt * np.sin(2*np.pi*38000/2e5*np.r_[0:rebuilt.size]) spectrum = np.fft.fft(rebuilt) mod_spectrum = np.fft.fft(modulated) #* self.lpf2 n_z = spectrum.size #base_spectrum = np.append(spectrum[0:1024],spectrum[n_z-1024:n_z]) base_spectrum = np.append(spectrum[0:int(n_z/self.decim_r2*.5)],spectrum[n_z-int(n_z/self.decim_r2*.5):n_s]) stereo_spectrum = np.append(mod_spectrum[0:int(n_z/self.decim_r2*.5)],mod_spectrum[n_z-int(n_z/self.decim_r2*.5):n_s]) stereo_spectrum *= np.fft.ifftshift(np.hamming(stereo_spectrum.size)) toplot = False if(toplot): fig = plt.figure() plt.plot(np.linspace(-22050,22050,stereo_spectrum.size),np.abs(np.fft.fftshift(stereo_spectrum)), np.linspace(-22050,22050,base_spectrum.size),.05*np.abs(np.fft.fftshift(base_spectrum))) plt.show() output = np.fft.ifft(base_spectrum) diff =np.fft.ifft(stereo_spectrum) #check: should be 1807 or very close to it. it is!! #output = self.lowpass_filter(np.real(output),8) #[12:8204] stereo = np.zeros(output.size*2,dtype='complex') left = output + 10*diff right = output - 10* diff stereo[0:stereo.size:2] = left stereo[1:stereo.size:2] = right #print 1e6/n_s / 44100 * output.size return np.real(stereo) def demodulate2(self,samples): # DEMODULATION CODE # LIMITER goes here # low pass & down sampling lp_samples = signal.decimate(self.lowpass_filter(samples,16),int(self.decim_r1)) # polar discriminator A = lp_samples[1:lp_samples.size] B = lp_samples[0:lp_samples.size-1] dphase = ( A * np.conj(B) ) dphase.resize(dphase.size+1) dphase[dphase.size-1] = dphase[dphase.size-2] rebuilt = signal.medfilt(np.angle(dphase)/np.pi,15) # np.cos(dphase) output = signal.decimate(rebuilt,int(self.decim_r2)) return np.real(output) def lowpass_filter(self,x,width): #wndw = np.sinc(np.r_[-15:16]/np.pi)/np.pi wndw = np.kaiser(width,6) wndw /= np.sum(wndw) new_array = signal.fftconvolve(x, wndw) return new_array[int(width/2):x.size+int(width/2)] # calculate rms for power # def rms(self,samples): meansq = np.mean(np.square(samples)) return np.sqrt(meansq) def play(self,samples): self.stream.write( samples.astype(np.float32).tostring() ) def start(self): while True: self.play(self.demodulate(self.getSamples()))
from rtlsdr import RtlSdr sdr = RtlSdr() # configure device sdr.sample_rate = 240e3 # Hz sdr.center_freq = 101.7e6 # Hz sdr.freq_correction = 0 # PPM sdr.gain = 'auto' print(sdr.read_samples(512))
# Install rtlsdr package from pyrtlsdr from rtlsdr import RtlSdr import matplotlib.pyplot as plt import numpy as np from plot import opsd # Initiate RtlSdr sdr = RtlSdr() # configure device sdr.sample_rate = 2.4e6 sdr.center_freq = 102.2e6 # Read samples samples = sdr.read_samples(1024) # Close RTLSDR device connection sdr.close() print(samples[1:100]) # Number of samples equals the length of samples sample_length = samples.shape[0] # Get the powerlevels and the frequencies PXX, freqs, _ = opsd(samples, nfft=1024, sample_rate=sdr.sample_rate / 1e6, scale_by_freq=True, sides='twosided')
from scipy import signal from commpy import filters from commpy import impairments from rtlsdr import RtlSdr samples_per_symbol = 8 num_samples = 65536 * 8 sdr = RtlSdr() # configure device sdr.sample_rate = 1e6 # Hz sdr.center_freq = 920e6 # Hz sdr.gain = 'auto' rx = sdr.read_samples(num_samples) rx = sdr.read_samples(num_samples) # Generate root raised cosine num_taps = 50 * samples_per_symbol + int(samples_per_symbol / 2) alpha = 0.35 t, h = filters.rrcosfilter(num_taps, alpha, 1, samples_per_symbol) #FFT of signal s = rx * np.hamming(len(rx)) S = np.fft.fftshift(np.fft.fft(s)) S_mag = np.abs(S) f = np.linspace(-0.5, 0.5, len(rx)) plt.figure(0) plt.plot(f, S_mag, '.-') plt.show()
class Sampler(QtCore.QObject): abortStart = QtCore.pyqtSignal() def __init__(self, gain, samp_rate, freqs, num_samples, q_in, parent=None): super(Sampler, self).__init__(parent) self.gain = gain self.samp_rate = samp_rate self.freqs = freqs self.num_samples = num_samples self.queue = q_in self.offset = 0 self.WORKING = True self.BREAK = False self.MEASURE = False try: self.sdr = RtlSdr() self.sdr.set_manual_gain_enabled(1) self.sdr.gain = self.gain self.sdr.sample_rate = self.samp_rate except IOError: self.WORKING = False print "Failed to initiate device. Please reconnect." def sampling(self): print 'Starting sampler...' while self.WORKING: prev = 0 counter = 0 gain = self.gain num_samples = self.num_samples self.BREAK = False self.sdr.gain = gain start = time.time() #print self.sdr.get_gain() for i in range(len(self.freqs)): if self.BREAK: break else: center_freq = self.freqs[i] #print "frequency: " + str(center_freq/1e6) + "MHz" if center_freq != prev: try: self.sdr.set_center_freq(center_freq) except: self.WORKING = False print "Device failure while setting center frequency" break prev = center_freq else: pass #time.sleep(0.01) try: x = self.sdr.read_samples(2048) data = self.sdr.read_samples(num_samples) except: self.WORKING = False print "Device failure while getting samples" break if self.MEASURE: self.offset = np.mean(data) #print data #self.sdr.close() counter += 1 self.queue.put([i, center_freq, data]) print str(counter) + " samples in " + str(time.time() - start) + " seconds" self.abortStart.emit() @QtCore.pyqtSlot(int) def changeGain(self, gain): self.gain = gain
sampsize = 2048 steps = 10 samples = np.empty((steps, sampsize), 'complex') power = np.zeros((steps, sampsize)) freqstart = 100e6 freqstop = 120e6 #freqstep = (freqstop-freqstart) / steps #cfreqs = np.linspace(freqstop, freqstart, steps) cfreqs = np.arange(freqstart, freqstop, 2.048e6) for a in range(10): for i in range(steps): sdr.center_freq = cfreqs[i] samples[i, :] = sdr.read_samples(sampsize) samplesfft = fft(samples, axis=1) samplesfft[:, 0:2] = samplesfft[:, 3:5] samplesfft[:, -3:-1] = samplesfft[:, -7:-5] power = power + np.abs(samplesfft)**2 power = fftshift(power, axes=(1, )) db = np.ravel(np.log(power)) freq = np.linspace(freqstart - samprate / 2, freqstop + samprate / 2, db.size) #freq = fftfreq(n, d=timestep) plt.figure() #plt.psd(samples[0,:], NFFT=sampsize, Fc=sdr.fc/1e6, Fs=sdr.rs/1e6) #plt.plot(np.log(np.abs(samplesfft[0,:]))) plt.plot(freq, db)
from rtlsdr import RtlSdr sdr = RtlSdr() # configure device sdr.sample_rate = 2.048e6 # Hz sdr.center_freq = 1039e5 # Hz sdr.freq_correction = 60 # PPM sdr.gain = 'auto' for i in sdr.read_samples(512): print(i) print(type(i))
def testPhysical(): ''' Tests the physical execution of commands with the sequencer via serial port ''' from rtlsdr import RtlSdr # for controlling the RTL SDR from multiprocessing.pool import ThreadPool # for simultaneous function execution import matplotlib.pyplot as plt # for plotting import numpy as np # for array math from matplotlib.mlab import psd, specgram # for fft from scipy import signal # for filtering tariUs = 12 # reader data-0 length in us freqMHz = 866.3 # reader center frequency blfMHz = 0.32 # tag backscatter link frequency # generate pulses reader = Reader(tariUs, blfMHz, 'COM4') # init sdr sdr = RtlSdr(serial_number='00000001') sdr.sample_rate = 2.048e6 sdr.center_freq = freqMHz*1e6 sdr.gain = 0 sdr.read_samples(sdr.sample_rate*0.05) # dummy read # get samples asyncronously... pool = ThreadPool(processes=1) sampling = pool.apply_async(sdr.read_samples, (sdr.sample_rate*0.05,)) # ...while sending command reader.enablePower() msg = Query(m=8, trExt=True) print('Testing physically with {}'.format(msg)) reader.sendMsg(msg) msg = Query(m=1, trExt=False, q=1) print('Testing physically with {}'.format(msg)) reader.sendMsg(msg) msg = QueryRep() print('Testing physically with {}'.format(msg)) reader.sendMsg(msg) reader.enablePower(False) # block until samples are aquired samples = sampling.get() # plot _, (ax1, ax2, ax3) = plt.subplots(3, 1, figsize=(12, 10)) blfStyle = {'linewidth': 1, 'linestyle': 'dashed', 'alpha': 0.6} # time domain timeSec = np.arange(len(samples))/sdr.sample_rate ax1.plot(timeSec, np.abs(samples), linewidth=0.5) ax1.set_xlabel('time [s]') ax1.set_ylabel('magnitude') ax1.set_title('Observed communication with \n' 'tari: {}us, freq: {}MHz, blf: {}MHz'.format(tariUs, freqMHz, blfMHz)) ax1.grid() # frequency domain nFFT = 512 maxHold = False if maxHold: traces, _, _ = specgram(samples, NFFT=nFFT) trace = np.max(traces, axis=1) # max hold over time else: trace, _ = psd(samples, NFFT=nFFT) trace = 20*np.log10(trace) # to dB freqsMHz = np.linspace(sdr.center_freq-sdr.sample_rate/2, sdr.center_freq+sdr.sample_rate/2, nFFT)/1e6 ax2.plot(freqsMHz, trace, linewidth=0.5) ax2.set_xlabel('frequency [MHz]') ax2.set_ylabel('magnitude [dB]') ax2.grid() # mark tag response ax2.axvline(freqMHz-blfMHz, color='r', **blfStyle) ax2.axvline(freqMHz+blfMHz, color='r', label='backscatter frequency', **blfStyle) ax2.legend(loc='upper right') # spectrogram traces, _, _ = specgram(samples) traces = np.clip(20*np.log10(traces), -100, -30) ax3.imshow(traces, extent=(timeSec[0], timeSec[-1], freqsMHz[0], freqsMHz[-1]), aspect='auto', cmap='jet') ax3.axhline(freqMHz-blfMHz, color='w', **blfStyle) ax3.axhline(freqMHz+blfMHz, color='w', label='backscatter frequency', **blfStyle) ax3.legend(loc='upper right') ax3.set_xlabel('time [s]') ax3.set_ylabel('frequency [MHz]') # try to parse with tag tag = Tag() edges = tag.samplesToEdges(np.abs(samples), sdr.sample_rate) print('Parsed raising edge durations: {}'.format(edges)) cmds = tag.fromEdges(edges) for cmd in cmds: print('Parsed edges: {}'.format(cmd.edges)) print('Parsed bits: {}'.format(cmd.bits)) print('Parsed message: {}'.format(cmd.message)) if cmd.blf: print('Parsed BLF: {} kHz'.format(int(cmd.blf*1e3))) print('Parsed Tari: {} us'.format(cmd.tari)) ax1.axvline(cmd.start/1e6, color='g') ax1.axvline(cmd.end/1e6, color='g') txt = str(cmd.bits) if not cmd.message else str(cmd.message) txt += '\nTari: {:.1f} us'.format(cmd.tari) if cmd.blf: txt += ', BLF: {} kHz'.format(int(cmd.blf*1e3)) ax1.text(cmd.start/1e6, 0.5*np.max(np.abs(samples)), txt, color='g', backgroundcolor='w') plt.show()
pocet_vzorku = 1024 * 1024 sdr = RtlSdr() pocet_oken = f_stop - f_start f_start = f_start * 1e6 f_stop = f_stop * 1e6 sdr.sample_rate = 1.2e6 # Hz sdr.freq_correction = +30 # korekce ochylky hodin, v PPM sdr.gain = 12 sdr.center_freq = f_start + 0.5e6 # Hz x = np.linspace(f_start, f_stop, pocet_oken * (int(round(pocet_vzorku * (1 / 1.2)))) ) # definice velikosti pole pro vyslednou FFT - jen pro indexy data = sdr.read_samples( pocet_vzorku) # testovaci aktivace prijimace, prvni vzorky nejsou kvalitni provede_mereni = 1 pozadi_temp = 0 if pozadi_volba == 'a': pozadi_temp = 1 raw_input("Probehne mereni pozadi, pro pokracovani stiskni ENTER") while provede_mereni == 1: # test zda-li se provede dvakrat pro kontrolu pozadi fft = np.linspace( 0, 0, pocet_oken * (int(round(pocet_vzorku * (1 / 1.2)))) ) # definice velikosti pole pro vyslednou FFT - zde se zapisuje for aktualni_okno in range(1, pocet_oken + 1): print('Merim') time.sleep(0.08) # bezpecnostni prodleva pro preladeni a ustaleni data = sdr.read_samples(pocet_vzorku) sdr.center_freq = sdr.center_freq + 1e6
class Receiver: def __init__(self, frequency, sample_rate, ppm, resolution, num_FFT): self.sdr = RtlSdr() # configure SDR self.sdr.sample_rate = sample_rate self.sdr.center_freq = frequency # For some reason the SDR doesn't want to set the offset PPM to 0 so we avoid that if ppm != 0: self.sdr.freq_correction = ppm self.sdr.gain = 'auto' self.resolution = 2**resolution self.num_FFT = num_FFT # Reads data from SDR, processes and writes it def receive(self): print(f'Receiving {self.num_FFT} samples...') data_PSD = self.sample() # Observed frequency range start_freq = self.sdr.center_freq - self.sdr.sample_rate / 2 stop_freq = self.sdr.center_freq + self.sdr.sample_rate / 2 freqs = np.linspace(start=start_freq, stop=stop_freq, num=self.resolution) # Samples a blank spectrum if the hydrogen line is within the observed frequency range. # This will be used for calculating the SNR if start_freq < 1420405000 and stop_freq > 1420405000: self.sdr.center_freq = self.sdr.center_freq + 3000000 blank_PSD = self.sample() SNR_spectrum, SNR = self.estimate_SNR(data=data_PSD, blank=blank_PSD) return freqs, SNR_spectrum, SNR else: return freqs, data_PSD # Close the SDR self.sdr.close() # Returns numpy array with PSD values averaged from "num_FFT" datasets def sample(self): counter = 0.0 PSD_summed = (0, ) * self.resolution while (counter < self.num_FFT): samples = self.sdr.read_samples(self.resolution) # Perform FFT and PSD-analysis PSD = np.abs(np.fft.fft(samples) / self.sdr.sample_rate)**2 PSD_log = 10 * np.log10(PSD) PSD_summed = tuple( map(operator.add, PSD_summed, np.fft.fftshift(PSD_log))) counter += 1.0 averaged_PSD = tuple(sample / counter for sample in PSD_summed) return averaged_PSD # Calculates SNR from spectrum and H-line SNR def estimate_SNR(self, data, blank): SNR = np.array(data) - np.array(blank) noise_floor = np.mean(SNR[0]) shifted_SNR = SNR - noise_floor H_SNR = max(shifted_SNR) return shifted_SNR, round(H_SNR, 5)
if hopCount == 0: hopCount = 1 sampleCount = options.dwell_time*options.samp_rate p = int(math.log(sampleCount,2) + 1) sampleCount = pow(2,p) print "SampleCount ", sampleCount sdr = RtlSdr() sdr.sample_rate = options.samp_rate sdr.gain = 4 sdr.freq_correction = 60 while True: for i in range(0,int(hopCount) - 1): sdr.center_freq = startHz + i*options.samp_rate + offset samples = sdr.read_samples(sampleCount) energy = numpy.linalg.norm(samples)/sampleCount print "Center Freq ", (startHz + i*options.samp_rate + offset)/1e6 , " Mhz", " Energy ", energy
def main(argv): if (not len(argv)): sys.exit("Usage:\n1420_psd.py -i <integration time(s)>") try: opts, args = getopt.getopt(argv, "hi:", [ "integrate=", "background", "do_fsw", "doplot", "verbose", "device_index=", "progressbar", "freqcorr=", "obs_lat=", "obs_lon=", "altitude=", "azimuth=", "suffix=", ]) except getopt.GetoptError: print('Usage:\n1420_psd.py -i <integration time (s)> (--background)') sys.exit(2) for opt, arg in opts: if opt == '-h': print('Usage:\n1420_psd.py -i <integration time (s)>') sys.exit() elif opt in ("-i", "--integrate"): if arg.isdigit(): int_time = int(arg) if (int_time <= 0): sys.exit( "Integration time must be a positive integer number of seconds" ) else: sys.exit( "Error: argument must be an integer number of seconds") opts = dict(opts) if '--background' in opts: filesuffix = '_background' else: filesuffix = "" if '--suffix' in opts: suffix = str(opts['--suffix']) else: suffix = "" if "--doplot" in opts: doplot = True else: doplot = False if "--verbose" in opts: verbose = True else: verbose = False if "--progressbar" in opts: progressbar = tqdm.tqdm else: progressbar = lambda x: x if "--do_fsw" in opts: do_fsw = True try: velthrow = int(opts['--do_fsw']) * u.km / u.s except: velthrow = 50 * u.km / u.s else: do_fsw = False if '--device_index' in opts: device_index = int(opts['--device_index']) if verbose: print(f"Using device index {device_index}") else: device_index = 0 if '--freqcorr' in opts: freqcorr = int(opts['--freqcorr']) else: freqcorr = None if verbose: print(opts) import time t0 = time.time() # initialize SDR sdr = RtlSdr(device_index=device_index) if do_fsw: freqthrow = ((velthrow / constants.c) * hi_restfreq).to(u.Hz).value if verbose: print(f"velthrow={velthrow}, freqthrow={freqthrow}") sdr.sample_rate = 2.4e6 # center frequency in Hertz sdr.center_freq = hi_restfreq.to(u.Hz).value # max gain is ~50? sdr.gain = 50 if freqcorr is not None: if verbose: print(f"setting freqcorr={freqcorr}") sdr.set_freq_correction(freqcorr) numsamples = 2048 passes = int(int_time * sdr.rs / numsamples) if do_fsw: nfsw = 4 #fsw_time = int_time / nfsw #chanwidth = sdr.rs / numsamples #chanwidth_kms = (chanwidth / sdr.center_freq) * constants.c.to(u.km/u.s).value if verbose: print( f"Center freq: {sdr.fc} readsize: {sdr.fc} numsamples: {numsamples} passes: {passes} do_fsw={do_fsw}" ) # collect data if do_fsw: power = {1: [], -1: []} frequency = {} sign = 1 else: power = [] if verbose: print('Warning: expect execution to take 4-5x your integration time') print('Collecting Data...') time.sleep( 0.05 ) # try to prevent 'pll not locked' errors by adding inter-operation delays if do_fsw: for fsw_id in progressbar(range(nfsw)): cfreq_target = hi_restfreq.to(u.Hz).value + freqthrow * sign if verbose: print(f"For fswd_id={fsw_id}, cfreq={cfreq_target}") sdr.center_freq = cfreq_target if verbose: print(f"Set center_freq={sdr.center_freq}") time.sleep( 0.01 ) # try to prevent 'pll not locked' errors by adding inter-operation delays sign = sign * -1 frq = np.fft.fftfreq(numsamples) idx = np.argsort(frq) frequency[sign] = sdr.fc + sdr.rs * frq[idx] for ii in range(passes // nfsw): samples = sdr.read_samples(numsamples) ps = np.abs(np.fft.fft(samples))**2 ps[0] = np.mean(ps) n = len(samples) power[sign].append(ps[idx] / n) else: frq = np.fft.fftfreq(numsamples) idx = np.argsort(frq) frequency = sdr.fc + sdr.rs * frq[idx] for ii in progressbar(range(passes)): samples = sdr.read_samples(numsamples) ps = np.abs(np.fft.fft(samples))**2 ps[0] = np.mean(ps) n = len(samples) power.append(ps[idx] / n) if verbose: print(f"sampling time = {time.time()-t0} for tint={int_time}") if do_fsw: avgpower = { key: np.array(pow).mean(axis=0) for key, pow in power.items() } # fsw = low-frequency minus high frequency fsw = avgpower[-1] - avgpower[1] # radio velocity = (nu_0 - nu) / nu_0 rvel1 = (constants.c * ( (hi_restfreq - u.Quantity(frequency[-1], u.Hz)) / hi_restfreq)).to( u.km / u.s).value rvel2 = (constants.c * ( (hi_restfreq - u.Quantity(frequency[1], u.Hz)) / hi_restfreq)).to( u.km / u.s).value rvel = rvel1 else: avgpower = np.array(power).mean(axis=0) rvel = (constants.c * ( (hi_restfreq - u.Quantity(frequency, u.Hz)) / hi_restfreq)).to( u.km / u.s).value now = str(datetime.datetime.now().strftime("%y%m%d_%H%M%S")) if doplot: fig, ax = plt.subplots(figsize=(14, 6)) if do_fsw: ax.plot( rvel, 10 * np.log10(fsw), ) else: ax.plot( rvel, 10 * np.log10(avgpower), ) ax.tick_params(labelsize=6) ax.get_xaxis().get_major_formatter().set_useOffset(False) ax.set_xlabel('Relative Velocity (km/s)') ax.set_ylabel('Measured Power (dB)') try: fig.savefig('psd_' + now + '.pdf') except: print("FAILED savefig") # write csv if do_fsw: filename = f"psd_{now}_tint{int_time}s_sdr{device_index}_fsw{filesuffix}{suffix}.fits" dat = { 'freq1': frequency[-1], 'freq2': frequency[1], 'power1': avgpower[-1], 'power2': avgpower[1], 'fsw_rvel1': rvel1, 'fsw_rvel2': rvel2, 'fsw_pow': fsw } else: filename = f"psd_{now}_tint{int_time}s_sdr{device_index}{filesuffix}{suffix}.fits" dat = {'freq': frequency, 'rvel': frequency, 'power': avgpower} tbl = Table(dat) if verbose: print(filename) for key in ('obs_lat', 'obs_lon', 'altitude', 'azimuth'): if f'--{key}' in opts: tbl.meta[f'--{key}'] = opts[f'--{key}'] tbl.meta['device'] = str(device_index) tbl.meta['tint'] = int_time tbl.meta['suffix'] = suffix tbl.meta['is_bg'] = filesuffix tbl.meta['date-obs'] = now tbl.write(filename) if verbose: print(f"total time = {time.time()-t0} for tint={int_time}") return filename
sat_name = sorted_sats[0][0] sat = sorted_sats[0][1] tles = active_orbcomm_satellites[sat_name]['tles'] print("Receiving from: {}".format(sat_name)) frequencies = active_orbcomm_satellites[sorted_sats[0][0]]['frequencies'] print("Satellite frequencies: {}".format(frequencies)) # Decode the lower of the two channels sat_center_frequency = frequencies[0] center_freq = sat_center_frequency # we will change this later. sdr.fc = center_freq print('Recording samples.') # Record samples twice just to fill up buffers (not sure if needed) samples = sdr.read_samples(num_samples_per_recording) samples = sdr.read_samples(num_samples_per_recording) context_dict = { 'sdr':sdr, 'observer':obs, 'sat':sat, 'sat_name':sat_name, 'tles':[tles], 'fs': sample_rate/decimation, 'fc': center_freq, } sdr.read_samples_async(rtlsdr_callback, num_samples_per_recording, context_dict) if should_finish: break
mag_file.write('%s]\n' % magnitude[i]) freq_file.write('%s]\n' % frequency[i]) return; sdr = RtlSdr() # np.set_printoptions(threshold=np.inf) # configure device sdr.sample_rate = 2.4e6 # Hz sdr.center_freq = 95.1e6 # Hz sdr.freq_correction = 60 # PPM sdr.gain = 4 # 'auto' # extract data data_points = 1024 data = sdr.read_samples(256*data_points) # initialize samples = sdr.read_samples(256*data_points) mag_file_path = '/home/pi/magtest.txt' freq_file_path = '/home/pi/freqtest.txt' sdr.close() # PSD plot psddata = psd(samples, NFFT=data_points, Fs=sdr.sample_rate/1e6, Fc=sdr.center_freq/1e6) #xlabel('Frequency (MHz)') #ylabel('Relative power (dB)') #show() magnitude = psddata[0]
class Single(threading.Thread): def __init__(self, opts, system_mods, settings): self.stoprequest = threading.Event() threading.Thread.__init__(self) self.connector = system_mods['connector'] devmod = system_mods['devices'] self.freq = opts['freq'] self.thresh = opts['thresh'] self.devid = opts['devid'] self.gain = devmod.get_rtlsdr_gain(self.devid) self.ppm = devmod.get_rtlsdr_ppm(self.devid) self.sysdevid = devmod.get_sysdevid(self.devid) self.settings = settings def run(self): try: self.sdr = RtlSdr(self.sysdevid) self.sdr.sample_rate = Fs self.sdr.center_freq = self.freq self.sdr.gain = self.gain self.sdr.ppm = self.ppm except: gammarf_util.console_message("error initializing device", MOD_NAME) devmod.freedev(self.devid) self.sdr.close() return data = {} data['module'] = MODULE_SINGLE data['protocol'] = PROTOCOL_VERSION self.lpf = signal.remez(LPF_TAPS, [0, F_BW, F_BW + (Fs / 2 - F_BW) / 4, Fs / 2], [1, 0], Hz=Fs) while not self.stoprequest.isSet(): x1 = self.sdr.read_samples(N) x3 = signal.lfilter(self.lpf, 1.0, x1) pwr = (10 * np.log10(np.mean(np.absolute(x3)))) if pwr > self.thresh: if self.settings['print_all']: gammarf_util.console_message( "hit on {}: {}".format(self.freq, pwr), MOD_NAME) data['freq'] = self.freq data['thresh'] = self.thresh data['pwr'] = pwr self.connector.senddat(data) try: self.sdr.close() except: gammarf_util.console_message("error closing device", MOD_NAME) self.devmod.removedev(self.devid) return def join(self, timeout=None): self.stoprequest.set() super(Single, self).join(timeout)
from matplotlib import pylab from pylab import psd, xlabel, ylabel, show from rtlsdr import RtlSdr sdr = RtlSdr() # configure device sdr.sample_rate = 2.4e6 sdr.center_freq = 1039e5 sdr.gain = 4 samples = sdr.read_samples(256 * 1024) # use matplotlib to estimate and plot the PSD psd(samples, NFFT=1024, Fs=sdr.sample_rate / 1e6, Fc=sdr.center_freq / 1e6) xlabel('Frequency (MHz)') ylabel('Relative power (dB)') show()
import numpy as np powe = np.ndarray(0) freq = np.ndarray(0) SAMPLERATE = 2.4e6 # Hz for i in np.arange(50, 1000, SAMPLERATE / 1e6): sdr = RtlSdr() # configure device sdr.sample_rate = SAMPLERATE sdr.center_freq = i * 1e6 # Hz sdr.freq_correction = 60 # PPM sdr.gain = 'auto' # 4 samples = sdr.read_samples(8 * 1024) sdr.close() sdr = None # use matplotlib to estimate and plot the PSD power, psd_freq = mlab.psd(samples, NFFT=1024, Fs=SAMPLERATE / 1e6) psd_freq = psd_freq + i powe = np.concatenate((powe, np.array(power))) freq = np.concatenate((freq, np.array(psd_freq))) print(f"{i}/1000") plt.semilogy(freq, powe) plt.xlabel('Frequency (MHz)') plt.ylabel('Relative power (dB)') plt.show()
def run_spectrum_int(num_samp, nbins, gain, rate, fc, t_int): ''' Inputs: num_samp: Number of elements to sample from the SDR IQ per call; use powers of 2 nbins: Number of frequency bins in the resulting power spectrum; powers of 2 are most efficient, and smaller numbers are faster on CPU. gain: Requested SDR gain (dB) rate: SDR sample rate, intrinsically tied to bandwidth in SDRs (Hz) fc: Base center frequency (Hz) t_int: Total effective integration time (s) Returns: freqs: Frequencies of the resulting spectrum, centered at fc (Hz), numpy array p_avg_db_hz: Power spectral density (dB/Hz) numpy array ''' # Force a choice of window to allow converting to PSD after averaging # power spectra WINDOW = 'hann' # Force a default nperseg for welch() because we need to get a window # of this size later. Use the scipy default 256, but enforce scipy # conditions on nbins vs. nperseg when nbins gets small. if nbins < 256: nperseg = nbins else: nperseg = 256 print('Initializing rtl-sdr with pyrtlsdr:') sdr = RtlSdr() try: sdr.rs = rate # Rate of Sampling (intrinsically tied to bandwidth with SDR dongles) sdr.fc = fc sdr.gain = gain print(' sample rate: %0.6f MHz' % (sdr.rs / 1e6)) print(' center frequency %0.6f MHz' % (sdr.fc / 1e6)) print(' gain: %d dB' % sdr.gain) print(' num samples per call: {}'.format(num_samp)) print(' PSD binning: {} bins'.format(nbins)) print(' requested integration time: {}s'.format(t_int)) N = int(sdr.rs * t_int) num_loops = int(N / num_samp) + 1 print(' => num samples to collect: {}'.format(N)) print(' => est. num of calls: {}'.format(num_loops - 1)) # Set up arrays to store power spectrum calculated from I-Q samples freqs = np.zeros(nbins) p_xx_tot = np.zeros(nbins) cnt = 0 # Set the baseline time start_time = time.time() print('Integration began at {}'.format( time.strftime('%a, %d %b %Y %H:%M:%S', time.localtime(start_time)))) # Estimate the power spectrum by Bartlett's method. # Following https://en.wikipedia.org/wiki/Bartlett%27s_method: # Use scipy.signal.welch to compute one spectrum for each timeseries # of samples from a call to the SDR. # The scipy.signal.welch() method with noverlap=0 is equivalent to # Bartlett's method, which estimates the spectral content of a time- # series by splitting our num_samp array into K segments of length # nperseg and averaging the K periodograms. # The idea here is to average many calls to welch() across the # requested integration time; this means we can call welch() on each # set of samples from the SDR, accumulate the binned power estimates, # and average later by the number of spectra taken to reduce the # noise while still following Barlett's method, and without keeping # huge arrays of iq samples around in RAM. # Time integration loop for cnt in range(num_loops): iq = sdr.read_samples(num_samp) freqs, p_xx = welch(iq, fs=rate, nperseg=nperseg, nfft=nbins, noverlap=0, scaling='spectrum', window=WINDOW, detrend=False, return_onesided=False) p_xx_tot += p_xx end_time = time.time() print('Integration ended at {} after {} seconds.'.format( time.strftime('%a, %d %b %Y %H:%M:%S'), end_time - start_time)) print('{} spectra were measured at {}.'.format(cnt, fc)) print('for an effective integration time of {:.2f}s'.format( num_samp * cnt / rate)) # Unfortunately, welch() with return_onesided=False does a sloppy job # of returning the arrays in what we'd consider the "right" order, # so we have to swap the first and last halves to avoid an artifact # in the plot. half_len = len(freqs) // 2 freqs = np.fft.fftshift(freqs) p_xx_tot = np.fft.fftshift(p_xx_tot) # Compute the average power spectrum based on the number of spectra read p_avg = p_xx_tot / cnt # Convert to power spectral density # A great resource that helped me understand the difference: # https://community.sw.siemens.com/s/article/what-is-a-power-spectral-density-psd # We could just divide by the bandwidth, but welch() applies a # windowing correction to the spectrum, and does it differently to # power spectra and PSDs. We multiply by the power spectrum correction # factor to remove it and divide by the PSD correction to apply it # instead. Then divide by the bandwidth to get the power per unit # frequency. # See the scipy docs for _spectral_helper(). win = get_window(WINDOW, nperseg) p_avg_hz = p_avg * ((win.sum()**2) / (win * win).sum()) / rate p_avg_db_hz = 10. * np.log10(p_avg_hz) # Shift frequency spectra back to the intended range freqs = freqs + fc # nice and tidy sdr.close() except OSError as err: print("OS error: {0}".format(err)) raise (err) except: print('Unexpected error:', sys.exc_info()[0]) raise finally: sdr.close() return freqs, p_avg_db_hz
class FMRadio(QtGui.QMainWindow,Ui_MainWindow): sample_buffer = Queue.Queue(maxsize=10) base_spectrum = np.ones(5780) plotOverall = True plotChannel = False plotPlaying = False plotWaveform = False useStereo = False stereoWidth = 10 useMedianFilt = True useLPFilt = False demodFiltSize = 11 useAudioFilter = True audioFilterSize = 16 toDraw = True demodMain = True demodSub1 = False demodSub2 = False toDrawWaterfalls = True toDrawPlots = False prevCutoff = 0 toPlot = (np.cumsum(np.ones(5780)),np.cumsum(np.ones(5780))) def __init__(self,freq,N_samples): QtGui.QMainWindow.__init__(self) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.createQtConnections() self.sample_rate = 2.4e5 ###1e6 #self.decim_r1 = 1e6/2e5 # for wideband fm self.decim_r2 = 2.4e5/48000 # for baseband recovery self.center_freq = freq #+250e3 self.gain = 38 self.N_samples = N_samples self.is_sampling = False self.spectrogram = np.zeros((328,200)) self.chspectrogram = np.zeros((328,200)) self.plspectrogram = np.zeros((164,200)) self.sdr = RtlSdr() #self.sdr.direct_sampling = 1 self.sdr.sample_rate = self.sample_rate self.sdr.center_freq = self.center_freq self.sdr.gain = self.gain self.pa = pyaudio.PyAudio() self.stream = self.pa.open( format = pyaudio.paFloat32, channels = 2, rate = 48000, output = True) adj = 0 hamming = np.kaiser(self.N_samples/4 + adj,1) lpf = np.append( np.zeros(self.N_samples*3/8),hamming) self.lpf = np.fft.fftshift(np.append(lpf,np.zeros(self.N_samples*3/8))) #,int(-.25*self.N_samples)) hamming = 10*signal.hamming(self.N_samples/16) lpf = np.append(np.zeros(self.N_samples*15/32),hamming) self.lpf_s1 = (np.append(lpf,np.zeros(int(self.N_samples*15/32)))) #self.lpf_s1 = np.roll(temp,int(.5*self.N_samples*67/120)) #self.lpf_s1 += np.roll(temp,int(-.5*self.N_samples*67/120)) self.lpf_s1 = np.fft.fftshift(self.lpf_s1) #self.lpf_s1 += np.fft.fftshift(self.lpf_s1) # fig = plt.figure() # ax = fig.add_subplot(111) # ax.plot(range(self.lpf_s1.size),self.lpf_s1) # fig.show() hamming = 10*signal.hamming(self.N_samples/32) lpf = np.append(np.zeros(self.N_samples*31/64),hamming) self.lpf_s2 = (np.append(lpf,np.zeros(int(self.N_samples*31/64)))) #self.lpf_s2 = np.roll(temp,int(.5*self.N_samples*92/120)) #self.lpf_s2 += np.roll(temp,int(-.5*self.N_samples*92/120)) self.lpf_s2 = np.fft.fftshift(self.lpf_s2) def createQtConnections(self): QtCore.QObject.connect(self.ui.freqSelect, QtCore.SIGNAL(_fromUtf8("valueChanged(int)")), self.setFreq) QtCore.QObject.connect(self.ui.checkBox, QtCore.SIGNAL(_fromUtf8("toggled(bool)")), self.setUseStereo) QtCore.QObject.connect(self.ui.mainchannel, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDemodMain) QtCore.QObject.connect(self.ui.subband1, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDemodSub1) QtCore.QObject.connect(self.ui.subband2, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDemodSub2) QtCore.QObject.connect(self.ui.stereoWidthSlider, QtCore.SIGNAL(_fromUtf8("sliderMoved(int)")), self.setStereoWidth) QtCore.QObject.connect(self.ui.spectrum_overall, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setSpectrumOverall) QtCore.QObject.connect(self.ui.spectrum_channel, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setSpectrumChannel) QtCore.QObject.connect(self.ui.spectrum_playing, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setSpectrumPlaying) QtCore.QObject.connect(self.ui.spectrum_waveform, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setSpectrumWaveform) QtCore.QObject.connect(self.ui.demodFiltMedian, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDemodFiltMedian) QtCore.QObject.connect(self.ui.demodFiltLP, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDemodFiltLP) QtCore.QObject.connect(self.ui.demodFilterSize, QtCore.SIGNAL(_fromUtf8("sliderMoved(int)")), self.setDemodFiltSize) QtCore.QObject.connect(self.ui.audioFilterActive, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setAudioFiltUse) QtCore.QObject.connect(self.ui.audioFilterSizeSlider, QtCore.SIGNAL(_fromUtf8("sliderMoved(int)")), self.setAudioFiltSize) QtCore.QObject.connect(self.ui.exitButton, QtCore.SIGNAL(_fromUtf8("clicked()")), self.terminate) QtCore.QObject.connect(self.ui.drawPlot, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDrawSpec) QtCore.QObject.connect(self.ui.waterfallButton, QtCore.SIGNAL(_fromUtf8('toggled(bool)')), self.setDrawWaterfalls) # QtCore.QObject.connect(self.ui.plotButton, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDrawPlot) self.bindPlot() def bindPlot(self): self.dpi = 100 self.fig = Figure((4.31,2.0), dpi=self.dpi) self.canvas = FigureCanvas(self.fig) self.canvas.setParent(self.ui.plotFrame) self.initplot() #self.anim = animation.FuncAnimation(self.fig,self.replot,interval=2000,blit=False) #self.canvas.mpl_connect('click_event',self.on_click_plot) # self.curve = QwtPlotCurve("Frequencies") # self.curve.setData(self.toPlot[0],self.toPlot[1]) #np.r_[-5e5:5e5:1e6/self.toPlot.size],np.abs(self.toPlot)) # self.curve.attach(self.ui.spectrumPlot) # self.ui.spectrumPlot.replot() # #threading.Timer(1,self.replot).start() def initplot(self): self.axes = self.fig.add_subplot(111, aspect=200/431) self.axes.xaxis.set_major_locator(ticker.NullLocator()) self.axes.yaxis.set_major_locator(ticker.NullLocator()) #self.axes.invert_yaxis() def replot(self): self.axes.clear() #self.axes.set_s self.axes.plot(self.toPlot[0],self.toPlot[1]) self.axes.set_aspect('auto',anchor='C') self.canvas.draw() def setDrawSpec(self,s): self.toDraw = s def drawSpectrum(self): self.axes.clear() self.axes.imshow(self.spectrogram, cmap='spectral') self.axes.xaxis.set_major_locator(ticker.NullLocator()) self.axes.yaxis.set_major_locator(ticker.NullLocator()) self.axes.set_aspect('auto',adjustable='box',anchor='NW') self.canvas.draw() def drawChspectrum(self): self.axes.clear() self.axes.imshow(self.chspectrogram, cmap='spectral') self.axes.xaxis.set_major_locator(ticker.NullLocator()) self.axes.yaxis.set_major_locator(ticker.NullLocator()) self.axes.set_aspect('auto',adjustable='box',anchor='NW') self.canvas.draw() def drawPlspectrum(self): self.axes.clear() self.axes.imshow(self.plspectrogram, cmap='spectral') self.axes.xaxis.set_major_locator(ticker.NullLocator()) self.axes.yaxis.set_major_locator(ticker.NullLocator()) self.axes.set_aspect('auto',adjustable='box',anchor='NW') self.canvas.draw() def setDrawPlots(self,s): self.toDrawPlots = s self.toDrawWaterfalls = not s def setDrawWaterfalls(self,s): self.toDrawWaterfalls = s self.toDrawPlots = not s def setFreq(self,freq): freq /= 10.0 text = "%.1f MHz" % freq self.ui.curFreq.setText(text) self.center_freq = freq*1e6 #+ 250e3 setf_t = threading.Thread(target=self.setF_th, args=[self.center_freq,]) setf_t.start() setf_t.join() def setF_th(self,f): while(self.is_sampling == True): pass self.sdr.center_freq = f def setUseStereo(self,u): self.useStereo = u def setStereoWidth(self,w): self.stereoWidth = np.sqrt(10*w) def setDemodMain(self,s): self.demodMain = s self.demodSub1 = not s self.demodSub2 = not s #self.useStereo = True def setDemodSub1(self,s): self.demodMain = not s self.demodSub1 = s self.demodSub2 = not s #self.useStereo = False def setDemodSub2(self,s): self.demodMain = not s self.demodSub1 = not s self.demodSub2 = s #self.useStereo = False def setSpectrumOverall(self,s): #self.initplot() self.plotOverall = s self.plotChannel = not s self.plotPlaying = not s self.plotWaveform = not s def setSpectrumChannel(self,s): #self.initplot() self.plotChannel = s self.plotOverall = not s self.plotPlaying = not s self.plotWaveform = not s def setSpectrumPlaying(self,s): #self.initplot() self.plotPlaying = s self.plotChannel = not s self.plotOverall= not s self.plotWaveform = not s def setSpectrumWaveform(self,s): self.plotWaveform = s self.plotPlaying = not s self.plotChannel = not s self.plotOverall= not s def setDemodFiltMedian(self,s): self.useMedianFilt = s self.useLPFilt = not s def setDemodFiltLP(self,s): self.useLPFilt = s self.useMedianFilt = not s def setDemodFiltSize(self,s): if(s % 2 == 0): s+=1 self.demodFiltSize = s def setAudioFiltUse(self,s): self.useAudioFilter = s def setAudioFiltSize(self,s): self.audioFilterSize = s def terminate(self): self.__del__() def __del__(self): #QtGui.QMainWindow.__del__() #Ui_MainWindow.__del__() #self.streamer.stop() #self.sampler_t.stop() print "sdr closed" self.sdr.close() print "pyaudio terminated" self.pa.terminate() sys.exit() def getSamples(self): #N_samples = self.N_samples # 1/24.4 seconds ~46336 #approximately a 2048/44100 amount's time return self.sdr.read_samples(self.N_samples) def getSamplesAsync(self): #Asynchronous call. Meant to be put in a loop w/ a calback fn #print 'gonna sample' self.is_sampling = True samples = self.sdr.read_samples_async(self.sampleCallback,self.N_samples,context=self) def sampleCallback(self,samples,sself): self.is_sampling = False self.sample_buffer.put(samples) #print 'put some samples in the jar' # recursive loop #sself.getSamplesAsync() def demodulate_th(self): while(1): try: samples = self.sample_buffer.get() #samples2 = self.sample_buffer.get() # print 'gottum' except: print "wtf idk no samples?" break out1 = self.demodulate(samples) self.sample_buffer.task_done() #out2 = self.demodulate(samples2) #self.sample_buffer.task_done() audio_out = out1 #np.append(out1,out2) self.play(audio_out) print 'gonna try to finish off the to-do list' sample_buffer.join() def demodulate(self,samples): # DEMODULATION CODE #samples = #self.sample_buffer.get() # LIMITER goes here # low pass & down sampling via fft spectrum = np.fft.fftshift(np.fft.fft(samples)) self.spectrogram = np.roll(self.spectrogram, 1,axis=1) self.spectrogram[:,0] = np.log(np.abs(spectrum[::100])) if(self.toDraw and self.plotOverall and self.count % 10 == 9): # self.toPlot = (np.linspace(-5e5,5e5,spectrum.size),np.abs(spectrum)) # self.replot() self.drawSpectrum() self.count += 1 #fig = plt.figure() #plt.plot(np.abs(spectrum)) #plt.show() # # spectrum *= self.lpf # # Decimate in two rounds. One to 200k, another to 44.1k # # DECIMATE HERE. Note that we're looking at 1MHz bandwidth. # n_s = spectrum.size # # channel_spectrum = spectrum #.25*spectrum[int(n_s*.75-.5*n_s/self.decim_r1):int(.75*n_s+.5*n_s/self.decim_r1)] #np.append(spectrum[0:int(n_s/self.decim_r1*.5)],spectrum[n_s-int(n_s/self.decim_r1*.5):n_s]) # # #radio_spectrum -= np.mean(radio_spectrum) #attempt to remove dc bias # #print channel_spectrum.size # # fig = plt.figure() # # plt.plot(np.abs(np.fft.ifftshift(channel_spectrum))) # # plt.show() # #self.fig.plot(np.fft.ifftshift(channel_spectrum)) # # # lp_samples = np.fft.ifft(np.fft.ifftshift(channel_spectrum)) # lp_samples = samples # lp_samples /= power # polar discriminator dphase = np.zeros(lp_samples.size, dtype='complex') A = lp_samples[1:lp_samples.size] B = lp_samples[0:lp_samples.size-1] dphase[1:] = ( A * np.conj(B) ) dphase[0] = lp_samples[0] * np.conj(self.prevCutoff) #dphase[dphase.size-2] self.prevCutoff = lp_samples[lp_samples.size-1] # if self.useMedianFilt: # rebuilt = signal.medfilt(np.angle(dphase)/np.pi,self.demodFiltSize) # np.cos(dphase) # else: # rebuilt = self.lowpass(np.angle(dphase),self.demodFiltSize) rebuilt = np.angle(dphase) / np.pi # toplot = False # if toplot: # fig = plt.figure() # ax = fig.add_subplot(111) # ax.plot(rebuilt) power = np.abs(self.mad(lp_samples)) self.ui.signalMeter.setValue(20*(np.log10(power))) demodMain = False demodSub1 = False demodSub2 = False if self.demodMain: demodMain = True # lp_samples = samples elif self.demodSub1: demodSub1 = True #lp_samples = samples * np.exp(-1j*2*np.pi*67650/2.4e5*np.r_[0:samples.size]) elif self.demodSub2: demodSub2 = True #lp_samples = samples * np.exp(-1j*2*np.pi*92000/2.4e5*np.r_[0:samples.size]) spectrum = np.fft.fft(rebuilt) #toplot = self.plotChannel self.chspectrogram = np.roll(self.chspectrogram, 1,axis=1) self.chspectrogram[:,0] = np.log(np.abs(spectrum[spectrum.size/2:spectrum.size:50])) if(self.toDraw and self.plotChannel and self.count % 10 == 9): self.drawChspectrum() #plotspectrum = np.abs(channel_spectrum[::100]) #self.toPlot = (np.linspace(-np.pi,np.pi,plotspectrum.size),plotspectrum) #self.replot() isStereo = False #demodSub1 = False #demodSub2 = False n_z = rebuilt.size if demodMain: #stereo_spectrum = spectrum if self.useStereo: isStereo = True #modulated = rebuilt * np.exp(-2j*np.pi*38000/2.4e5*np.r_[0:rebuilt.size]) #h = signal.firwin(128,22000,nyq=1.2e5) #lp_mod = signal.fftconvolve(modulated,h,mode='same') #decim = lp_mod[::self.decim_r2] #dphase = np.zeros(decim.size, dtype='complex') # # A = decim[1:decim.size] # B = decim[0:decim.size-1] # # dphase[1:] = np.angle( A * np.conj(B) ) #h = signal.firwin(128,22000,nyq=24000) #diff = dphase# [::self.decim_r2] mod_spectrum = np.roll(spectrum,int(.5*n_z*38000/120000)) mod_spectrum += np.roll(spectrum,int(-.5*n_z*38000/120000)) #np.fft.fft(modulated) mod_spectrum *= self.lpf #np.fft.ifftshift(np.hamming(stereo_spectrum.size)) stereo_spectrum = np.append(mod_spectrum[0:np.ceil(n_z/self.decim_r2*.5)],mod_spectrum[n_z-np.ceil(n_z/self.decim_r2*.5):n_z]) diff = np.fft.ifft(stereo_spectrum) #self.base_spectrum = np.append(spectrum[0:int(n_z/self.decim_r2*.5)],spectrum[n_z-int(n_z/self.decim_r2*.5):n_z]) #output = np.fft.ifft(self.base_spectrum) h = signal.firwin(128,16000,nyq=1.2e5) output = signal.fftconvolve(rebuilt,h,mode='same') output = rebuilt[::self.decim_r2] # h = signal.firwin(128,16000,nyq=2.4e4) # output = signal.fftconvolve(output,h,mode='same') elif demodSub1: demod = rebuilt * np.exp(-2j*np.pi*67650/2.4e5*np.r_[0:rebuilt.size]) # spectrum = np.fft.fft(demod)*self.lpf_s1 h = signal.firwin(128,7500,nyq=2.4e5/2) lp_demod = signal.fftconvolve(demod,h,mode='same') decim = lp_demod[::self.decim_r2] # base_spectrum = np.append(spectrum[0:int(.5*n_z*7500/2.4e5)],spectrum[n_z-int(.5*n_z*7500/2.4e5):n_z]) # decim = np.fft.ifft(base_spectrum) dphase = np.zeros(decim.size, dtype='complex') # A = decim[1:decim.size] B = decim[0:decim.size-1] # dphase[1:] = np.angle( A * np.conj(B) ) h = signal.firwin(128,7500,nyq=24000) output = signal.fftconvolve(dphase,h,mode='same') #retoutput) elif demodSub2: demod = rebuilt * np.exp(-2j*np.pi*92000/2.4e5*np.r_[0:rebuilt.size]) # spectrum = np.fft.fft(demod)*self.lpf_s2 h = signal.firwin(128,7500,nyq=2.4e5/2) lp_demod = signal.fftconvolve(demod,h,mode='same') decim = lp_demod[::self.decim_r2] # base_spectrum = np.append(spectrum[0:int(.5*n_z*7500/2.4e5)],spectrum[n_z-int(.5*n_z*7500/2.4e5):n_z]) # decim = np.fft.ifft(base_spectrum) dphase = np.zeros(decim.size, dtype='complex') # A = decim[1:decim.size] B = decim[0:decim.size-1] # dphase[1:] = np.angle( A * np.conj(B) ) h = signal.firwin(128,7500,nyq=24000) output = signal.fftconvolve(dphase,h,mode='same') #return np.real(output) output -= np.mean(output) stereo = np.zeros(output.size*2, dtype='complex') if (isStereo): #diff = np.fft.ifft(stereo_spectrum) w = self.stereoWidth # adjust to change stereo wideness #print w left = output + w/10 * diff right = output - w/10 * diff if(self.useAudioFilter): left = self.lowpass(left,self.audioFilterSize) right = self.lowpass(right,self.audioFilterSize) stereo[0:stereo.size:2] = left stereo[1:stereo.size:2] = right else: if self.useAudioFilter: output = self.lowpass(output,self.audioFilterSize) # just the tip (kills the 19k pilot) stereo[0:stereo.size:2] = output stereo[1:stereo.size:2] = output spectrum = np.fft.fft(stereo[::2]) self.plspectrogram = np.roll(self.plspectrogram, 1,axis=1) self.plspectrogram[:,0] = np.log(np.abs(spectrum[spectrum.size/2:spectrum.size:20])) if(self.toDraw and self.plotPlaying): # and self.count % 2 == 0): if self.toDrawWaterfalls: self.drawPlspectrum() else: sm = np.abs(np.fft.fftshift(spectrum[::20])) self.toPlot = (np.linspace(-2.4e4,2.4e4,sm.size),sm) self.replot() if(self.toDraw and self.plotWaveform): sm = np.real(stereo[::20]) self.toPlot = (np.linspace(0,output.size/48000,sm.size),sm) self.replot() return np.real(stereo) # def updateimg(self,base_spectrum): # spectralimg = np.zeros((base_spectrum.size/20,base_spectrum.size/10)) # for i in np.r_[0:base_spectrum.size/10]: # spectralimg[np.abs(np.fft.fftshift(base_spectrum)[i*10]/10),i] = 1 # cv2.imshow('spectrum',spectralimg) def demodulate2(self,samples): # DEMODULATION CODE # LIMITER goes here # low pass & down sampling lp_samples = signal.decimate(self.lowpass_filter(samples,16),int(self.decim_r1)) # polar discriminator A = lp_samples[1:lp_samples.size] B = lp_samples[0:lp_samples.size-1] dphase = ( A * np.conj(B) ) dphase.resize(dphase.size+1) dphase[dphase.size-1] = dphase[dphase.size-2] rebuilt = signal.medfilt(np.angle(dphase)/np.pi,15) # np.cos(dphase) output = signal.decimate(rebuilt,int(self.decim_r2)) return np.real(.5*output) # utility functions # def lowpass(self,x,width): #wndw = np.sinc(np.r_[-15:16]/np.pi)/np.pi #wndw = np.kaiser(width,6) wndw = signal.firwin(16,width*990,nyq=24000) #wndw /= np.sum(wndw) new_array = signal.fftconvolve(x, wndw, mode='same') return new_array # calculate mean average deviation # def mad(self,samples): ave = np.mean(samples) return np.mean(np.abs(samples-ave)) # calculate rms for power # def rms(self,samples): meansq = np.mean(np.square(samples)) return np.sqrt(meansq) def play(self,samples): self.stream.write( samples.astype(np.float32).tostring() ) def start(self): self.streamer = MakeDaemon(self.demodulate_th) # run demodulation in the 'background' self.streamer.start() self.count = 0 self.sampler_t = threading.Thread(target=self.getSamplesAsync) # sampler loop self.sampler_t.start()
#echos rtlsdr read_samples output (without lines starting with hyphen) to console and to ~/finaldata.txt import os from rtlsdr import RtlSdr os.chdir(os.path.expanduser("~/")) sdr = RtlSdr() sdr.sample_rate = 2.048e6 #Hz sdr.center_freq = 70e6 # Hz sdr.freq_correction = 60 # PPM sdr.gain = 'auto' sdroutput = str(sdr.read_samples(512)) savefile = open('finaldata.txt', 'w') sdr1 = sdroutput.translate(None, '[]').split() sdr2 = sdr1 finaldata = '' for line in sdr2: if not "-" in line: finaldata+=line+"\n" print finaldata savefile.write(finaldata) savefile.close()
sdr = RtlSdr() #config sdr.samle_rate = 2.048e6 sdr.center_freq = 433888000 #sdr.freq_correction = 60 sdr.gain = 'auto' #print(sdr.read_samples(512)) burst = 0 burst_time = 0 overall_avg = 20 while True: samples = sdr.read_samples(512*2); #run an FFT and take absolute value to get freq magnitudes freqs = np.absolute(np.fft.fft(samples)) #ignore the mean/DC values at ends freqs = freqs[1:-1] #Shift FFT result positions to put center frequency in center freqs = np.fft.fftshift(freqs) #convert to decibels freqs = 20.0*np.log10(freqs) mean = np.mean(freqs) min = np.min(freqs) max = np.max(freqs) diff = max - mean percent_diff = overall_avg/max
def saveSignal(freq, file_path): # Define function for writing signal data into file def write_data(data_points, magnitudeData, frequencyData, mag_file, freq_file): i = 0 mag_file.write('[') freq_file.write('[') while i < data_points - 1: mag_file.write("%s, " % magnitudeData[i]) freq_file.write("%s, " % frequencyData[i]) i += 1 mag_file.write('%s]\n' % magnitudeData[i]) freq_file.write('%s]\n' % frequencyData[i]) sdr = RtlSdr() # Configure SDR sdr.sample_rate = 2.4e6 # Hz sdr.center_freq = freq # Hz sdr.freq_correction = 60 # PPM sdr.gain = 4 # 'auto' # Initialize data_points = 1024 samples = sdr.read_samples(256 * data_points) mag_file_path = file_path + "/magdata.txt" freq_file_path = file_path + "/freqdata.txt" ### *** IMPORTANT *** (for later, when optimizing) ### I'm not sure if we should leave this outside of the function ### and move it to the end of the main code, after the flight path ### ends. Idk the impact of leaving the SDR open/on for an extended ### period of time. If we move sdr.close() outside, we have to ### remember to also move the above code outside as well. ### Leaving this line within this function should be fine for now. sdr.close() # PSD plot data psddata = psd(samples, NFFT=data_points, Fs=sdr.sample_rate / 1e6, Fc=sdr.center_freq / 1e6) # Extracting pertinent information from the PSD plot calculation magnitudeData = psddata[0] frequencyData = psddata[1] # Check for .txt file and write data # For Ron: Magnitude has not been converted to dB yet. To convert, 10*log(magnitude). if Path(mag_file_path).is_file() and Path(freq_file_path).is_file(): with open(mag_file_path, 'a') as mag_file, open(freq_file_path, 'a') as freq_file: write_data(data_points, magnitudeData, frequencyData, mag_file, freq_file) else: with open(mag_file_path, 'w') as mag_file, open(freq_file_path, 'w') as freq_file: write_data(data_points, magnitudeData, frequencyData, mag_file, freq_file) print("Data saved successfully.")
sdr2 = RtlSdr(device_index1) sdr2.sample_rate = 1e6 sdr2.center_freq = 434 * 1e6 sdr2.gain = 1 #--------------------------- use github N = 1 # times of sample PSD values #raw_data=zeros((N,1024)) while 1: for ii in range(0, N): #start = time.time() samples1 = sdr1.read_samples(56 * 1024) #256 #sensingtime1 = (time.time() - start) #print('time for read_sample:',sensingtime1) # use matplotlib to estimate and plot the PSD plt.figure(1) #start = time.time() plt.cla() #p_density, fre = plt.psd(samples1, NFFT=1024, Fs=sdr1.sample_rate, Fc=sdr1.center_freq) # get psd using github package #print(np.max(20*np.log(p_density))) p_density, fre = selfpsd( samples1, NFFT=1024, Fs=sdr1.sample_rate, Fc=sdr1.center_freq) # get psd using own function re_pow1, new_psd1, f_new1 = received_power2(p_density, fre, 1, 128)
class RTLSdr: def __init__(self, **args): self.logcl = LogCL() self.import_rtlsdr() self.import_pylab() self.set_static_dir() self.set_args(args) self.dev = None self.dev_open = False self.sensivity = 3 self.stop_func = None def set_static_dir(self): full_path = os.path.realpath(__file__) self.static_dir = os.path.split(full_path)[0] + '/static/' def set_args(self, args): try: self.dev_id = int(args['dev']) self.sample_rate = int(args['samprate']) self.gain = args['gain'] self.center_freq = args['freq'] self.num_read = int(args['n']) self.interval = int(args['i']) self.args = args except Exception as e: self.logcl.log("Invalid argument detected.\n" + str(e), 'error') sys.exit() def import_rtlsdr(self): try: self.logcl.log("Importing rtlsdr module...") global RtlSdr from rtlsdr import RtlSdr except: self.logcl.log("rtlsdr module not found.", "error") def import_pylab(self): try: global plt, np, peakutils import pylab as plt import numpy as np import peakutils except Exception as e: if 'peak' in str(e): self.logcl.log("peakutils module not found.\n" + str(e), 'error') else: self.logcl.log("matplotlib module not found.\n" + str(e), 'error') sys.exit() def init_device(self, init_dev=True, show_log=True): try: if show_log: self.logcl.log("Trying to open & initialize device #" + str(self.dev_id)) self.dev = RtlSdr(self.dev_id) self.dev_open = True if init_dev: self.dev.center_freq = self.center_freq self.dev.sample_rate = self.sample_rate self.dev.gain = self.gain except IOError as e: self.dev_open = False if init_dev: self.logcl.log("Failed to open RTL-SDR device!\n" + str(e), 'error') except Exception as e: self.logcl.log("Failed to initialize RTL-SDR device.\n" + str(e), 'fatal') return self.dev_open def read_samples(self, n_read=512*512): try: if not self.dev.device_opened: if not self.stop_func == None: self.dev_open = False self.stop_func() else: return self.dev.read_samples(n_read) except Exception as e: self.logcl.log("Failed to read samples from RTL-SDR.\n" + str(e), 'error') def close(self, show_log=False): try: if show_log: self.logcl.log("Closing RTL-SDR device #" + str(self.dev_id)) if self.dev != None: self.dev.close() self.dev_open = False except Exception as e: self.logcl.log("Failed to close RTL-SDR device.\n" + str(e), 'error') def find_peaks(self, plt, Y, F, n): try: freqs = [] dbs = [] indexes = peakutils.indexes(Y, thres=abs(11-(n))/10, min_dist=20) for index in indexes: freq = F[index] db = 10 * math.log10(Y[index]) freqs.append(freq) dbs.append(db) plt.plot(freq, db, color='k', marker='x', markersize=6, linestyle='None') return [freqs, dbs] except: self.logcl.log("Failed to find peaks on graph.\n" + str(e), 'error') def get_fft_data(self, scan=False): try: [Y, F] = plt.psd(self.read_samples(), NFFT=1024, Fs=int(self.sample_rate)/1e6, \ Fc=int(self.center_freq)/1e6, color='k') if scan: max_freqs = self.find_peaks(plt, Y, F, n=self.sensivity) plt.xlabel('Frequency (MHz)') plt.ylabel('Relative power (dB)') plt.savefig(self.static_dir + '/img/fft.png', bbox_inches='tight', pad_inches = 0) plt.clf() encoded = base64.b64encode(open(self.static_dir + '/img/fft.png', "rb"). \ read()).decode("utf-8") return encoded if not scan else [encoded, max_freqs] except Exception as e: self.logcl.log("Failed to get graph data.\n" + str(e), 'error')
from azure.servicebus import ServiceBusService from rtlsdr import RtlSdr sdr = RtlSdr() # sdr sdr.sample_rate = 2.4e6 sdr.center_freq = 105e6 #sdr.freq_correction = 60 #sdr.gain = 'auto' sdr.gain = 4 # Azure key_name = 'RootManageSharedAccessKey' key_value = 'QIru9DStoatRrRFmQ6Sq6RfyBpe88TQyJUAemsrQzgk=' service_namespace = 'joksdr' fft = 1024 s = 10 i = 0 samples = sdr.read_samples(s * fft) sdr.close() del (sdr) sbs = ServiceBusService(service_namespace, shared_access_key_name=key_name, shared_access_key_value=key_value) while (i < (s * fft)): sbs.send_event('sdr', '{"signalval": "' + str(samples[i]) + '"}') i = i + 1
def run(self): logging.debug("PulseDetector.run") try: sdr = RtlSdr() sdr.rs = 2.4e6 sdr.fc = 146e6 sdr.gain = 10 except Exception as e: logging.exception("SDR init failed") return last_max_mag = 0 leadingEdge = False rgPulse = [] lastPulseTime = time.time() #timeoutCount = 0 pulseCount = 0 while True: # Handle change in frequency try: newFrequency = self.setFreqQueue.get_nowait() except Exception as e: pass else: logging.debug("Changing frequency %d", newFrequency) sdr.fc = newFrequency # Handle change in gain try: newGain = self.setGainQueue.get_nowait() except Exception as e: pass else: sdr.gain = newGain logging.debug("Changing gain %d:%f", newGain, sdr.gain) # Adjust noise threshold sdrReopen = False #noiseThreshold = self.calcNoiseThreshold(self.amp, sdr.gain) #logging.debug("Noise threshold %f", noiseThreshold) # Read samples try: samples = sdr.read_samples(NUM_SAMPLES_PER_SCAN) except Exception as e: logging.exception("SDR read failed") sdrReopen = True if sdrReopen: logging.debug("Attempting reopen") try: sdr.open() except Exception as e: logging.exception("SDR reopen failed") return try: samples = sdr.read_samples(NUM_SAMPLES_PER_SCAN) except Exception as e: logging.exception("SDR read failed") return # Process samples mag, freqs = magnitude_spectrum(samples, Fs=sdr.rs) if not leadingEdge: # Detect leading edge strength = self.detectedPulseStrength(mag) if strength: leadingEdge = True #logging.debug("leading edge strength:background %d %d", strength, self.backgroundNoise) rgPulse = [strength] else: # Detect trailing edge falling below background noise strength = self.detectedPulseStrength(mag) if strength: rgPulse.append(strength) else: leadingEdge = False pulseCaptureCount = len(rgPulse) self.adjustBackgroundNoise(strength) if pulseCaptureCount >= self.minPulseCaptureCount: pulseStrength = max(rgPulse) pulseCount += 1 logging.debug( "***** %d %d %d pulseStrength:len(rgPulse):background", pulseStrength, pulseCaptureCount, self.backgroundNoise) if self.pulseQueue: self.pulseQueue.put(pulseStrength) lastPulseTime = time.time() else: logging.debug("pulse too short %d", pulseCaptureCount) for skippedStrength in rgPulse: self.adjustBackgroundNoise(skippedStrength) rgPulse = [] # Check for no pulse if time.time() - lastPulseTime > 3: #timeoutCount += 1 if leadingEdge: leadingEdge = False logging.error( "failed to detect trailing edge - len(rgPulse):background %d %d", len(rgPulse), self.backgroundNoise) else: logging.debug("no pulse for two seconds - background %d", self.backgroundNoise) if self.pulseQueue: self.pulseQueue.put(0) rgPulse = [] lastPulseTime = time.time() sdr.close()
class Input(DataSource.DataSource): def __init__(self, source: str, data_type: str, sample_rate: float, centre_frequency: float, input_bw: float): """ The rtlsdr input source :param source: The device number, normally zero :param data_type: The data type the rtlsdr is providing, we will convert this :param sample_rate: The sample rate we will set the source to, note true sps is set from the device :param centre_frequency: The centre frequency the source will be set to :param input_bw: The filtering of the input, may not be configurable """ # Driver converts to floating point for us, underlying is 8o? self._constant_data_type = "16tle" super().__init__(source, self._constant_data_type, sample_rate, centre_frequency, input_bw) self._connected = False self._sdr = None self._tuner_type = 0 self._device_index = 0 self._gain_modes = ["auto", "manual"] # would ask, but can't super().set_gain_mode(self._gain_modes[0]) super().set_help(help_string) super().set_web_help(web_help_string) def open(self) -> bool: global import_error_msg if import_error_msg != "": msgs = f"No {module_type} support available, ", import_error_msg self._error = msgs logger.error(msgs) raise ValueError(msgs) if self._source == "?": self._error = self.find_devices() return False try: self._device_index = int(self._source) except ValueError as err: msgs = f"port number from {self._source}, {err}" self._error = str(err) logger.error(msgs) raise ValueError(err) try: self._sdr = RtlSdr(device_index=self._device_index) except Exception as err: self._error = f"Failed to connect {str(err)}" logger.error(self._error) raise ValueError(self._error) self._tuner_type = self._sdr.get_tuner_type() logger.debug(f"Connected to {module_type}") try: self.set_sample_rate_sps(self._sample_rate_sps) self.set_centre_frequency_hz(self._centre_frequency_hz) # self._sdr.freq_correction = 0 # ppm self.set_gain_mode('auto') self.set_gain(0) except ValueError: pass except Exception as err: self._error = str(err) raise ValueError(err) # recover the true values from the device self._sample_rate_sps = float(self._sdr.get_sample_rate()) self._centre_frequency_hz = float(self._sdr.get_center_freq()) logger.debug( f"{allowed_tuner_types[self._tuner_type]} {self._centre_frequency_hz / 1e6:.6}MHz @ " f"{self._sample_rate_sps:.3f}sps") self._connected = True return self._connected def close(self) -> None: if self._sdr: self._sdr.close() self._sdr = None self._connected = False @staticmethod def find_devices() -> str: devices = "" # could do with a call that returns the valid device_index's max_device = 10 for device in range(max_device): try: sdr = RtlSdr(device_index=device) type_of_tuner = sdr.get_tuner_type() # index = sdr.get_device_index_by_serial('0000001') # permissions required # addresses = sdr.get_device_serial_addresses() # permissions required sdr.close() devices += f"device {device}, type {type_of_tuner} {allowed_tuner_types[type_of_tuner]}\n" except Exception: pass if devices == "": devices = f"No rtlsdr devices found, scanned 0 to {max_device-1}" print(devices) return devices def get_sample_rate_sps(self) -> float: if self._sdr: self._sample_rate_sps = float(self._sdr.get_sample_rate()) return self._sample_rate_sps def get_centre_frequency_hz(self) -> float: if self._sdr: if self._hw_ppm_compensation: self._centre_frequency_hz = float(self._sdr.get_center_freq()) return self._centre_frequency_hz def set_sample_type(self, data_type: str) -> None: # we can't set a different sample type on this source super().set_sample_type(self._constant_data_type) def set_sample_rate_sps(self, sample_rate: float) -> None: # rtlsdr has limits on allowed sample rates # from librtlsdr.c data_source.get_bytes_per_sample() # /* check if the rate is supported by the resampler */ # if ((samp_rate <= 225000) || (samp_rate > 3200000) || # ((samp_rate > 300000) && (samp_rate <= 900000))) { # fprintf(stderr, "Invalid sample rate: %u Hz\n", samp_rate); # return -EINVAL; # } # logger.info(f"set sr rtlsdr tuner type {self._tuner_type}, {allowed_tuner_types[self._tuner_type]}") if (sample_rate <= 225000) or (sample_rate > 3200000) or ( (sample_rate > 300000) and (sample_rate <= 900000)): err = f"{module_type} invalid sample rate, {sample_rate}sps, 225000-3000000 and not 300000-900000" self._error = err logger.error(err) sample_rate = 1e6 # something safe self._sample_rate_sps = sample_rate if self._sdr: try: self._sdr.sample_rate = sample_rate self._sample_rate_sps = float(self._sdr.get_sample_rate()) except Exception as err: self._error = str(err) logger.debug( f"bad sr {sample_rate} now {self._sample_rate_sps}") logger.info(f"Set sample rate {sample_rate}sps") def set_centre_frequency_hz(self, frequency: float) -> None: # limits depend on tuner type: from https://wiki.radioreference.com/index.php/RTL-SDR # Tuner Frequency Range # ======================================= # Elonics E4000 52 – 1100 MHz / 1250 - 2200 MHz # Rafael Micro R820T(2) 24 – 1766 MHz # Fitipower FC0013 22 – 1100 MHz # Fitipower FC0012 22 - 948.6 MHz # FCI FC2580 146 – 308 MHz / 438 – 924 MHz freq_ok = True ok = True # logger.info(f"set cf rtlsdr tuner type {self._tuner_type}, {allowed_tuner_types[self._tuner_type]}") # what type of tuner do we have ? freq_range = "" if self._tuner_type == 1: # E4000 if (frequency < 52e6) or (frequency > 2200e6): freq_ok = False freq_range = "52 – 1100 MHz and 1250 - 2200 MHz" elif (frequency > 1100e6) and (frequency < 1250e6): freq_ok = False freq_range = "52 – 1100 MHz and 1250 - 2200 MHz" elif self._tuner_type == 2: # FC0012 if (frequency < 22e6) or (frequency > 948.6e6): freq_ok = False freq_range = "22 - 948.6 MHz" elif self._tuner_type == 3: # FC0013 if (frequency < 22e6) or (frequency > 1100e6): freq_ok = False freq_range = "22 – 1100 MHz" elif self._tuner_type == 4: # FC2580 if (frequency < 146e6) or (frequency > 924e6): freq_ok = False freq_range = "146 – 308 MHz and 438 – 924 MHz" elif (frequency > 308e6) and (frequency < 438e6): freq_ok = False freq_range = "146 – 308 MHz and 438 – 924 MHz" elif self._tuner_type == 5 or self._tuner_type == 6: # R820T or R828D if (frequency < 24e6) or (frequency > 1.766e9): freq_ok = False freq_range = "24 – 1766 MHz" else: self._error = f"Unknown tuner type {self._tuner_type}, frequency range checking impossible" logger.error(self._error) ok = False if not freq_ok: self._error = f"{allowed_tuner_types[self._tuner_type]} invalid frequency {frequency}Hz, " \ f"outside range {freq_range}" logger.error(self._error) ok = False if self._sdr and ok: try: if self._hw_ppm_compensation: self._sdr.center_freq = frequency self._centre_frequency_hz = float( self._sdr.get_center_freq()) else: self._centre_frequency_hz = frequency self._sdr.center_freq = self.get_ppm_corrected(frequency) # print(f"freq {frequency} ppm {self._ppm} -> {frequency + (self._ppm * frequency / 1e6)}") logger.info(f"Set frequency {frequency / 1e6:0.6f}MHz") except Exception as err: self._error = str(err) def set_ppm(self, ppm: float) -> None: """ +ve reduces tuned frequency -ve increases the tuned frequency :param ppm: Parts per million error, :return: """ self._ppm = ppm self.set_centre_frequency_hz(self._centre_frequency_hz) def get_gain(self) -> float: if self._sdr: self._gain = self._sdr.get_gain() return self._gain def set_gain(self, gain: float) -> None: self._gain = gain if self._sdr: try: # horrible _sdr.set_gain() - either a number or string if self._gain_mode == 'auto': self._sdr.set_gain('auto') else: self._sdr.set_gain(float(gain)) except Exception as err: self._error = f"failed to set gain of '{gain}', {err}" def set_gain_mode(self, mode: str) -> None: if mode in self._gain_modes: self._gain_mode = mode if self._sdr: # because the 'best' way to set the mode is to set the gain, apparently self.set_gain(self._gain) return def set_bandwidth_hz(self, bw: float) -> None: if self._sdr: try: self._sdr.set_bandwidth(int(bw)) except Exception as err: self._error += str(err) self._bandwidth_hz = self._sdr.get_bandwidth() def get_bandwidth_hz(self) -> float: if self._sdr: self._bandwidth_hz = self._sdr.get_bandwidth() return self._bandwidth_hz def read_cplx_samples(self, number_samples: int) -> Tuple[np.array, float]: """ Get complex float samples from the device Note that we don't use unpack() for this device :return: A tuple of a numpy array of complex samples and time in nsec """ complex_data = None rx_time = 0 if self._sdr and self._connected: try: complex_data = self._sdr.read_samples( number_samples) # will return np.complex128 rx_time = self.get_time_ns() complex_data = np.array( complex_data, dtype=np.complex64 ) # (?) we need all values to be 32bit floats except Exception as err: self._connected = False self._error = str(err) logger.error(self._error) raise ValueError(err) return complex_data, rx_time
from scipy.io.wavfile import write import matplotlib.pyplot as plt F_station = int(88.7e6) # Rutgers Radio F_offset = 250000 # Offset to capture at # We capture at an offset to avoid DC spike Fc = F_station - F_offset # Capture center frequency Fs = int(1140000) # Sample rate N = int(4 * 8192000) # Samples to capture sdr = RtlSdr() sdr.sample_rate = Fs # Hz sdr.center_freq = Fc # Hz s sdr.freq_correction = 60 # PPM (Parts Per Million) sdr.gain = 'auto' #pick gain value samples = sdr.read_samples(N) print(samples) sdr.close() # Read in the samples: IQ = np.array(samples, dtype=np.complex) print("IQ (Saad): ", IQ) multiplied = IQ[:-1] * np.conj(IQ[1:]) demodulated = np.angle(multiplied) print("Demodulted (IQ Mert): ", demodulated) plt.specgram(IQ, NFFT=2048, Fs=Fs) plt.title("x1") plt.ylim(-Fs / 2, Fs / 2) plt.savefig("x1_spec.pdf", bbox_inches='tight', pad_inches=0.5) plt.close()
#Esperamos 1 segundo time.sleep(1) arduino.flushInput() arduino.setDTR(True) with arduino: while True: cantidad = input("Ingrese cantidad de mediciones entre 1 y 9: ") arduino.write(cantidad.encode()) #Leo lineas del arduino (posicion) hasta la palabra Fin for rawString in iter(lambda: arduino.readline(), b'Fin\r\n'): #Leo las muestras iq = sdr.read_samples(n * nfft) #Calculo la potencia de la señal potencia = get_potencia(iq) - sdr.gain #Imprimo los resultados print('Medicion ' + str(rawString.decode("utf-8")) + ': {:2.2f} dB'.format(potencia)) #Le mando al arduino que ya termine la medicion y "mueva los motores" arduino.write(bytes(b'r')) # #Cierro los dispositivos # arduino.close() sdr.close()
elif (arg == "-c"): config.center_freq = int(sys.argv[i+1]) elif (arg == "-r"): config.sample_rate = int(sys.argv[i+1]) #init RTLSDR and if no then go out try: sdr = RtlSdr() except IOError: print "Probably RTLSDR device not attached" sys.exit(0) # configure device sdr.sample_rate = config.sample_rate # Hz sdr.center_freq = config.center_freq # Hz sdr.freq_correction = 60 # PPM sdr.gain = 'auto' samples = sdr.read_samples( config.sample_num ) if config.matlab_flag == False: print( samples ) else: print "samples = [", for s in samples: if s.imag < 0.0: print "%s%si "%(str(s.real), str(s.imag)), else: print "%s+%s "%(str(s.real), str(s.imag)), print "];"
class FMRadio(QtGui.QMainWindow,Ui_MainWindow): sample_buffer = Queue.Queue(maxsize=10) base_spectrum = np.ones(5780) plotOverall = True plotChannel = False plotPlaying = False plotWaveform = False useStereo = False stereoWidth = 10 useMedianFilt = True useLPFilt = True demodFiltSize = 100000 useAudioFilter = True audioFilterSize = 16 toDraw = True demodMain = True demodSub1 = False demodSub2 = False toDrawWaterfalls = True toDrawPlots = False prevCutoff = 0 prevSpec1 = np.zeros(128) prevSpec2 = np.zeros(128) prevSpec3 = np.zeros(128) prevConvo1 = np.zeros(128) prevConvo2 = np.zeros(128,dtype='complex') limiterMax = np.zeros(32) toPlot = (np.cumsum(np.ones(5780)),np.cumsum(np.ones(5780))) def __init__(self,freq,N_samples): self.spectrogram = np.zeros((512,400)) self.chspectrogram = np.zeros((512,400)) self.plspectrogram = np.zeros((256,400)) self.cur_spectrogram = self.spectrogram QtGui.QMainWindow.__init__(self) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.createQtConnections() ftxt = "%.1f MHz" % (freq/1e6) self.ui.curFreq.setText(ftxt) self.sample_rate = 2.4e5 # tried 1.024e6 - not so great self.decim_r1 = 1 # 1.024e6/2.4e5 # for wideband fm down from sample_rate self.decim_r2 = 2.4e5/48000 # for baseband recovery self.center_freq = freq #+250e3 self.gain = 16 self.N_samples = N_samples self.is_sampling = False self.sdr = RtlSdr() #self.sdr.direct_sampling = 1 self.sdr.sample_rate = self.sample_rate self.sdr.center_freq = self.center_freq self.sdr.gain = self.gain self.pa = pyaudio.PyAudio() self.stream = self.pa.open( format = pyaudio.paFloat32, channels = 2, rate = 48000, output = True) self.PLL = PhaseLockedLoop(self.N_samples,19000,self.sample_rate) self.initOpenCV() self.noisefilt = np.ones(6554) b,a = signal.butter(1, 2122/48000*2*np.pi, btype='low') self.demph_zf = signal.lfilter_zi(b, a) adj = 0 hamming = np.kaiser(self.N_samples/4 + adj,1) lpf = np.append( np.zeros(self.N_samples*3/8),hamming) self.lpf = np.fft.fftshift(np.append(lpf,np.zeros(self.N_samples*3/8))) #,int(-.25*self.N_samples)) hamming = 10*signal.hamming(self.N_samples/16) lpf = np.append(np.zeros(self.N_samples*15/32),hamming) self.lpf_s1 = (np.append(lpf,np.zeros(int(self.N_samples*15/32)))) #self.lpf_s1 = np.roll(temp,int(.5*self.N_samples*67/120)) #self.lpf_s1 += np.roll(temp,int(-.5*self.N_samples*67/120)) self.lpf_s1 = np.fft.fftshift(self.lpf_s1) #self.lpf_s1 += np.fft.fftshift(self.lpf_s1) # fig = plt.figure() # ax = fig.add_subplot(111) # ax.plot(range(self.lpf_s1.size),self.lpf_s1) # fig.show() hamming = 10*signal.hamming(self.N_samples/32) lpf = np.append(np.zeros(self.N_samples*31/64),hamming) self.lpf_s2 = (np.append(lpf,np.zeros(int(self.N_samples*31/64)))) #self.lpf_s2 = np.roll(temp,int(.5*self.N_samples*92/120)) #self.lpf_s2 += np.roll(temp,int(-.5*self.N_samples*92/120)) self.lpf_s2 = np.fft.fftshift(self.lpf_s2) # Not currently used def getSamples(self): return self.sdr.read_samples(self.N_samples); def getSamplesAsync(self): #Asynchronous call. Initiates a continuous loop with the callback fn self.is_sampling = True samples = self.sdr.read_samples_async(self.sampleCallback,self.N_samples,context=self) def sampleCallback(self,samples,sself): self.is_sampling = False self.sample_buffer.put(samples) #print 'put some samples in the jar' # recursive loop #sself.getSamplesAsync() def demodulate_th(self): # Initiates a loop to process all the incoming blocks of samples from the Queue # This should be run in its own thread, or the program will become unresponsive while(1): try: samples = self.sample_buffer.get() #samples2 = self.sample_buffer.get() except: #print "wtf idk no samples?" # even though this can't happen... (although I'm not sure why not) #print 'gonna try to finish off the to-do list' #self.sample_buffer.join() break out1 = self.demodulate(samples) self.sample_buffer.task_done() #out2 = self.demodulate(samples2) #self.sample_buffer.task_done() audio_out = out1 #np.append(out1,out2) self.play(audio_out) def gen_spectrogram(self,x,m,prevSpec): itsreal = np.isreal(x[0]) m = int(m) lx = x.size nt = (lx) // m #NT = (lx +m -1)//m #padsize = NT*m -lx cutsize = lx -nt*m padsize = int(cutsize + m/2) if not prevSpec.size == padsize: prevSpec = np.zeros(padsize) xp = np.append(x[cutsize:],prevSpec) prevSpec = x[:(padsize)] xh = np.zeros((m,nt*2), dtype='complex') for n in range(int(nt*2)): block = xp[m*n//2:m*(n+2)//2] xh[:,n] = block*np.hanning(block.size) #if self.prevSpec.size == padsize: # xb = np.append(self.prevSpec[:prevSpec.size-m/2],x) # xc = np.append(self.prevSpec,x[:lx-m/2]) # self.prevSpec = x[lx-m/2:] #else: # xb = np.append(x,np.zeros(-lx+nt*m)) # xc = np.append(x[m/2:],np.zeros(nt*m - lx + m/2)) #xr = np.reshape(xb, (m,nt), order='F') * np.outer(np.hanning(m),np.ones(nt)) #xs = np.reshape(xc, (m,nt), order='F') * np.outer(np.hanning(m),np.ones(nt)) #xm = np.zeros((m,2*nt),dtype='complex') #xm[:,::2] = xr #xm[:,1::2] = xs if itsreal: spec = np.fft.fft(xh,m,axis=0) spec = spec[:m//2,:] else: spec = np.fft.fftshift(np.fft.fft(xh,m,axis=0)) #mx = np.max(spec) pwr = np.log(np.abs(spec) + 1e-6) return (np.real(pwr),prevSpec) def initOpenCV(self): cv2.namedWindow("Spectrogram") def demodulate(self,samples): # DEMODULATION CODE - And the core function # samples must be passed in by the caller self.count += 1 #spectral_window = signal.hanning #spectrum = np.fft.fftshift(np.fft.fft(samples*spectral_window(samples.size))) self.spectrogram = np.roll(self.spectrogram, 16,axis=1) stft,self.prevSpec1 = self.gen_spectrogram(samples,samples.size//8,self.prevSpec1) self.spectrogram[:,:16] = stft[::8,:] # np.log(np.abs(spectrum[::100])) if(self.plotOverall): # and self.count % 10 == 9): #self.drawSpectrum() self.cur_spectrogram = self.spectrogram self.drawCurSpectrum() # cutoff = self.demodFiltSize # h = signal.firwin(128, cutoff,nyq=self.sample_rate/2) # lp = signal.fftconvolve(samples[::self.decim_r1],h,mode='full') # lps = lp.size # hs = h.size # prev = lp[lps-hs:] # lp[:hs/2] += self.prevConvo2[hs/2:] # lp = np.append(self.prevConvo2[:hs/2],lp) # self.prevConvo2 = prev # lp_samples = lp[:lps-hs+1] lp_samples = samples power = np.abs(self.mad(lp_samples)) self.ui.signalMeter.setValue(20*(np.log10(power))) # polar discriminator dphase = np.zeros(lp_samples.size, dtype='complex') A = lp_samples[1:lp_samples.size] B = lp_samples[0:lp_samples.size-1] dphase[1:] = ( A * np.conj(B) ) dphase[0] = lp_samples[0] * np.conj(self.prevCutoff) #dphase[dphase.size-2] self.prevCutoff = lp_samples[lp_samples.size-1] # limiting dphase /= np.abs(dphase) # if self.useMedianFilt: # rebuilt = signal.medfilt(np.angle(dphase)/np.pi,self.demodFiltSize) # np.cos(dphase) # else: # rebuilt = self.lowpass(np.angle(dphase),self.demodFiltSize) rebuilt = np.real(np.angle(dphase) / np.pi) demodMain = False demodSub1 = False demodSub2 = False isStereo = False if self.demodMain: demodMain = True if self.useStereo: isStereo = True elif self.demodSub1: demodSub1 = True elif self.demodSub2: demodSub2 = True #spectrum = np.fft.fft(rebuilt* spectral_window(rebuilt.size)) #print rebuilt.size/8 self.chspectrogram = np.roll(self.chspectrogram, 16,axis=1) stft,self.prevSpec2 = self.gen_spectrogram(rebuilt,rebuilt.size/8,self.prevSpec2) self.chspectrogram[:,:16] = stft[::-4,:] # np.log(np.abs(spectrum[spectrum.size/2:spectrum.size:50])) if(self.plotChannel):# and self.count % 10 == 9): self.cur_spectrogram = self.chspectrogram self.drawCurSpectrum() #plotspectrum = np.abs(channel_spectrum[::100]) #self.toPlot = (np.linspace(-np.pi,np.pi,plotspectrum.size),plotspectrum) #self.replot() n_z = rebuilt.size if demodMain: h = signal.firwin(128,16000,nyq=1.2e5) output = signal.fftconvolve(rebuilt,h,mode='full') outputa = output # could be done in place but I'm not concerned with memory outputa[:h.size/2] += self.prevConvo1[h.size/2:] #add the latter half of tail end of the previous convolution outputa = np.append(self.prevConvo1[:h.size/2], outputa) # also delayed by half size of h so append the first half self.prevConvo1 = output[output.size-h.size:] # set the tail for next iteration output = outputa[:output.size-h.size:self.decim_r2] # chop off the tail and decimate #stereo_spectrum = spectrum if isStereo: #pilot = rebuilt * np.cos(2*np.pi*19/240*(np.r_[0:rebuilt.size])) h = signal.firwin(512,[18000,20000],pass_zero=False,nyq=1.2e5) pilot_actual = signal.fftconvolve(rebuilt,h,mode='same') self.PLL.adjust(pilot_actual) moddif = rebuilt * np.real(np.square(self.PLL.pll)) #np.cos(2*np.pi*38/240*(np.r_[0:ss] - phase_shift)) h = signal.firwin(128,16000,nyq=1.2e5) moddif = signal.fftconvolve(moddif,h,mode='same') h = signal.firwin(64,16000,nyq=48000/2) diff = signal.fftconvolve(moddif[::self.decim_r2],h,mode='same') diff = np.real(diff) # rdbs = rebuilt * np.power(self.PLL.pll,3) # h = signal.hanning(1024) # rdbs = signal.fftconvolve(rdbs,h) # if np.mean(rdbs) > 0: # # bit ONE # else: # # bit ZERO elif demodSub1: demod = rebuilt * np.exp(-2j*np.pi*67650/2.4e5*np.r_[0:rebuilt.size]) h = signal.firwin(128,7500,nyq=2.4e5/2) lp_demod = signal.fftconvolve(demod,h,mode='same') decim = lp_demod[::self.decim_r2] dphase = np.zeros(decim.size, dtype='complex') # A = decim[1:decim.size] B = decim[0:decim.size-1] # dphase[1:] = np.real(np.angle( A * np.conj(B) )) h = signal.firwin(128,7500,nyq=24000) output = signal.fftconvolve(dphase,h,mode='same') elif demodSub2: demod = rebuilt * np.exp(-2j*np.pi*92000/2.4e5*np.r_[0:rebuilt.size]) h = signal.firwin(128,7500,nyq=2.4e5/2) lp_demod = signal.fftconvolve(demod,h,mode='same') decim = lp_demod[::self.decim_r2] dphase = np.zeros(decim.size, dtype='complex') # A = decim[1:decim.size] B = decim[0:decim.size-1] # dphase[1:] = np.real(np.angle( A * np.conj(B) )) h = signal.firwin(128,7500,nyq=24000) output = signal.fftconvolve(dphase,h,mode='same') # DC block filter, lol, srsly output = np.real(output) - np.mean(np.real(output)) if np.isnan(output[0]): #print "error" # for some reason, output is NaN for the first 2 loops return np.zeros(6554) # deemphasis - # 2122/samplerate*2 *pi - butterworth filter b,a = signal.butter(1, 2122/48000*2*np.pi, btype='low') output, zf = signal.lfilter(b, a, output,zi=self.demph_zf) self.demph_zf = zf stereo = np.zeros(output.size*2) if (isStereo): diff = signal.lfilter(b,a,diff) w = self.stereoWidth # adjust to change stereo wideness left = output + w/10 * diff right = output - w/10 * diff if(self.useAudioFilter): left = self.lowpass(left,self.audioFilterSize) right = self.lowpass(right,self.audioFilterSize) stereo[0:stereo.size:2] = left stereo[1:stereo.size:2] = right else: if self.useAudioFilter: output = self.lowpass(output,self.audioFilterSize) # just the tip (kills the 19k pilot) stereo[0:stereo.size:2] = output stereo[1:stereo.size:2] = output #normalize to avoid any possible clipping when playing stereo /= 2*np.max(stereo) #spectrum = np.fft.fft(stereo[::2]) output = .5*(stereo[::2]+stereo[1::2]) #spectrum = np.fft.fft(.5*(stereo[::2]+stereo[1::2])*spectral_window(output.size)) self.plspectrogram = np.roll(self.plspectrogram, 24,axis=1) stft,self.prevSpec3 = self.gen_spectrogram(output,512,self.prevSpec3) self.plspectrogram[:,:24] = stft[::-1,:] # np.log(np.abs(spectrum[spectrum.size/2:spectrum.size:20])) if(self.plotPlaying): # and self.count % 2 == 0): #if self.toDrawWaterfalls: self.cur_spectrogram = self.plspectrogram self.drawCurSpectrum(invert=True) #self.drawPlspectrum() #else: # sm = np.abs(np.fft.fftshift(spectrum[::20])) # toPlot = (np.linspace(-2.4e4,2.4e4,sm.size),sm) # self.replot(toPlot) #if(self.toDraw and self.plotWaveform): # if self.toDrawWaterfalls: # sm = np.real(output[::20]) # toPlot = (np.linspace(0,output.size/48000,sm.size),sm) # self.replot(toPlot) # else: # sm = np.real(self.PLL.pll[::200]) # toPlot = (np.linspace(0,output.size/48000,sm.size),sm) # self.replot(toPlot) return np.real(stereo) # Alternate demodulator. Not used, but extremely simple def demodulate2(self,samples): # DEMODULATION CODE # LIMITER goes here # low pass & down sampling h = signal.firwin(128,80000,nyq=1.2e5) lp_samples = signal.fftconvolve(samples, h) # polar discriminator A = lp_samples[1:lp_samples.size] B = lp_samples[0:lp_samples.size-1] dphase = ( A * np.conj(B) ) / np.pi dphase.resize(dphase.size+1) dphase[dphase.size-1] = dphase[dphase.size-2] h = signal.firwin(128,16000,nyq=1.2e5) rebuilt = signal.fftconvolve(dphase,h) output = rebuilt[::self.decim_r2] output = self.lowpass(output, self.audioFilterSize) return np.real(output) # utility functions # def lowpass(self,x,width): #wndw = np.sinc(np.r_[-15:16]/np.pi)/np.pi #wndw = np.kaiser(width,6) wndw = signal.firwin(16,width*999,nyq=24000) #wndw /= np.sum(wndw) new_array = signal.fftconvolve(x, wndw, mode='same') return new_array # calculate mean average deviation # def mad(self,samples): ave = np.mean(samples) return np.mean(np.abs(samples-ave)) # calculate rms for power # def rms(self,samples): meansq = np.mean(np.square(samples)) return np.sqrt(meansq) def play(self,samples): self.stream.write( samples.astype(np.float32).tostring() ) # starting point def start(self): # Initiates running things self.streamer = MakeDaemon(self.demodulate_th) # run demodulation in the 'background' self.streamer.start() self.count = 0 self.sampler_t = threading.Thread(target=self.getSamplesAsync) # sampler loop self.sampler_t.start() def createQtConnections(self): QtCore.QObject.connect(self.ui.freqSelect, QtCore.SIGNAL(_fromUtf8("valueChanged(int)")), self.setFreq) QtCore.QObject.connect(self.ui.checkBox, QtCore.SIGNAL(_fromUtf8("toggled(bool)")), self.setUseStereo) QtCore.QObject.connect(self.ui.mainchannel, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDemodMain) QtCore.QObject.connect(self.ui.subband1, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDemodSub1) QtCore.QObject.connect(self.ui.subband2, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDemodSub2) QtCore.QObject.connect(self.ui.stereoWidthSlider, QtCore.SIGNAL(_fromUtf8("sliderMoved(int)")), self.setStereoWidth) QtCore.QObject.connect(self.ui.spectrum_overall, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setSpectrumOverall) QtCore.QObject.connect(self.ui.spectrum_channel, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setSpectrumChannel) QtCore.QObject.connect(self.ui.spectrum_playing, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setSpectrumPlaying) QtCore.QObject.connect(self.ui.spectrum_waveform, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setSpectrumWaveform) QtCore.QObject.connect(self.ui.demodFiltMedian, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDemodFiltMedian) QtCore.QObject.connect(self.ui.demodFiltLP, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDemodFiltLP) QtCore.QObject.connect(self.ui.demodFilterSize, QtCore.SIGNAL(_fromUtf8("sliderMoved(int)")), self.setDemodFiltSize) QtCore.QObject.connect(self.ui.audioFilterActive, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setAudioFiltUse) QtCore.QObject.connect(self.ui.audioFilterSizeSlider, QtCore.SIGNAL(_fromUtf8("sliderMoved(int)")), self.setAudioFiltSize) QtCore.QObject.connect(self.ui.exitButton, QtCore.SIGNAL(_fromUtf8("clicked()")), self.terminate) QtCore.QObject.connect(self.ui.drawPlot, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDrawSpec) QtCore.QObject.connect(self.ui.waterfallButton, QtCore.SIGNAL(_fromUtf8('toggled(bool)')), self.setDrawWaterfalls) # QtCore.QObject.connect(self.ui.plotButton, QtCore.SIGNAL(_fromUtf8("clicked(bool)")), self.setDrawPlot) self.bindPlot() def bindPlot(self): self.dpi = 100 self.fig = Figure((4.31,2.0), dpi=self.dpi) self.canvas = FigureCanvas(self.fig) self.canvas.setParent(self.ui.plotFrame) self.initplot() def initplot(self): self.axes = self.fig.add_subplot(111, aspect=200/431) self.axes.xaxis.set_major_locator(ticker.NullLocator()) self.axes.yaxis.set_major_locator(ticker.NullLocator()) self.fig.tight_layout() #self.axes.invert_yaxis() #self.anim = animation.FuncAnimation(self.fig,self.drawCurSpectrum,interval=750) def replot(self,toPlot): self.axes.clear() self.axes.plot(toPlot[0],toPlot[1]) self.axes.set_aspect('auto',anchor='C') self.canvas.draw() def setDrawSpec(self,s): self.toDraw = s def drawCurSpectrum(self,invert=False): #self.axes.clear() #self.axes.imshow(self.cur_spectrogram, cmap='spectral') #self.axes.xaxis.set_major_locator(ticker.NullLocator()) #self.axes.yaxis.set_major_locator(ticker.NullLocator()) #self.axes.set_aspect('auto',adjustable='box',anchor='NW') #self.canvas.draw() mx = np.max(self.cur_spectrogram) mn = np.min(self.cur_spectrogram) if invert: self.cur_spectrogram = -cv2.convertScaleAbs(self.cur_spectrogram,alpha=255 / (mx)) else: self.cur_spectrogram = cv2.convertScaleAbs(self.cur_spectrogram,alpha=255 / (mn)) self.cur_spectrogram = cv2.GaussianBlur(self.cur_spectrogram,(5,5),.6) cmapped =cv2.applyColorMap(self.cur_spectrogram,cv2.COLORMAP_JET) cv2.imshow('Spectrogram',cmapped) cv2.waitKey(1); def drawSpectrum(self): self.axes.clear() self.axes.imshow(self.spectrogram, cmap='spectral') self.axes.xaxis.set_major_locator(ticker.NullLocator()) self.axes.yaxis.set_major_locator(ticker.NullLocator()) self.axes.set_aspect('auto',adjustable='box',anchor='NW') self.canvas.draw() def drawChspectrum(self): self.axes.clear() self.axes.imshow(self.chspectrogram, cmap='spectral') self.axes.xaxis.set_major_locator(ticker.NullLocator()) self.axes.yaxis.set_major_locator(ticker.NullLocator()) self.axes.set_aspect('auto',adjustable='box',anchor='NW') self.canvas.draw() def drawPlspectrum(self): self.axes.clear() self.axes.imshow(self.plspectrogram, cmap='spectral') self.axes.xaxis.set_major_locator(ticker.NullLocator()) self.axes.yaxis.set_major_locator(ticker.NullLocator()) self.axes.set_aspect('auto',adjustable='box',anchor='NW') self.canvas.draw() def setDrawPlots(self,s): self.toDrawPlots = s self.toDrawWaterfalls = not s def setDrawWaterfalls(self,s): self.toDrawWaterfalls = s self.toDrawPlots = not s def setFreq(self,freq): if freq % 2 == 0: freq += 1 freq /= 10.0 text = "%.1f MHz" % freq self.ui.curFreq.setText(text) self.center_freq = freq*1e6 #+ 250e3 setf_t = threading.Thread(target=self.setF_th, args=[self.center_freq,]) setf_t.start() setf_t.join() # This function is what is used to adjust the tuner on the RTL # Currently, it causes the program to crash if used after an unspecified period of inactivity # commented lines are attempts that didn't work def setF_th(self,f): while(self.is_sampling == True): pass #self.sdr.cancel_read_async() time.sleep(.1) self.sdr.center_freq = f #self.getSamplesAsync() def setUseStereo(self,u): self.useStereo = u def setStereoWidth(self,w): self.stereoWidth = w/5 def setDemodMain(self,s): self.demodMain = s self.demodSub1 = not s self.demodSub2 = not s #self.useStereo = True def setDemodSub1(self,s): self.demodMain = not s self.demodSub1 = s self.demodSub2 = not s #self.useStereo = False def setDemodSub2(self,s): self.demodMain = not s self.demodSub1 = not s self.demodSub2 = s #self.useStereo = False def setSpectrumOverall(self,s): #self.initplot() #self.cur_spectrogram = self.spectrogram self.plotOverall = s self.plotChannel = not s self.plotPlaying = not s self.plotWaveform = not s def setSpectrumChannel(self,s): #self.initplot() self.plotChannel = s self.plotOverall = not s self.plotPlaying = not s self.plotWaveform = not s def setSpectrumPlaying(self,s): #self.initplot() self.plotPlaying = s self.plotChannel = not s self.plotOverall= not s self.plotWaveform = not s def setSpectrumWaveform(self,s): self.plotWaveform = s self.plotPlaying = not s self.plotChannel = not s self.plotOverall= not s def setDemodFiltMedian(self,s): self.useMedianFilt = s self.useLPFilt = not s def setDemodFiltLP(self,s): self.useLPFilt = s self.useMedianFilt = not s def setDemodFiltSize(self,s): #if(s % 2 == 0): # s+=1 self.demodFiltSize = s def setAudioFiltUse(self,s): self.useAudioFilter = s def setAudioFiltSize(self,s): self.audioFilterSize = s def terminate(self): self.__del__() # Destructor - also used to exit the program when user clicks "Quit" def __del__(self): # Program will continue running in the background unless the RTL is told to stop sampling self.sdr.cancel_read_async() print "sdr closed" self.sdr.close() print "pyaudio terminated" self.pa.terminate() cv2.destroyAllWindows()
parser.add_argument('-n', action='store', dest='N',help='numero de muestras ej:1024e4',type=float,default=1024e4) parser.add_argument('-f', action='store', dest='Fo',help='frecuencia centro en MHz ej:91.3',type=float,default=91.3) parser.add_argument('--plot', action='store_true', default=False,dest='plot',help='Mostrar graficos de DEP y FFT') args = parser.parse_args() sdr = RtlSdr() sdr.sample_rate = Fs # Hz sdr.center_freq = (args.Fo*1e6) # Hz sdr.freq_correction = 60 # PPM sdr.gain = 'auto' timer = Temporizador() plotter = Plotter(Fs,(args.Fo*1e6)) if args.plot else None fm = Demodulador(timer,plotter = plotter) sFs = fm.outputFs() timer.tag('inicio toma de muestras') samples = sdr.read_samples(args.N) timer.tag('fin toma de muestras') audio = fm.demodular(samples) timer.tag('reproduciendo audio') sd.play(audio,sFs,blocking=True) timer.tag('fin reproduccion') timer.print() plotter and plotter.show()
from rtlsdr import RtlSdr sdr = RtlSdr() # configure device sdr.sample_rate = 2.048e6 # Hz sdr.center_freq = 70e6 # Hz sdr.freq_correction = 60 # PPM sdr.gain = 'auto' print(sdr.read_samples(512))
class Rtl_threading(threading.Thread): def __init__(self, addr, fc, fs, size, times, corr): threading.Thread.__init__(self) self.sdr = RtlSdr(addr) # configure device self.sdr.sample_rate = fs; # Hz self.sdr.center_freq = fc; # Hz # self.freq_correction = corr; # PPM if addr==1: self.sdr.gain = 15.7; else: #0 self.sdr.gain = 32.8; #15.7 0.725 # init param self.alive = True self.addr = addr; self.size = size self.times = times self.counter = 0; self.timestamp = int(time.time()); #0.0 0self.9 1.4 2.7 3.7 7.7 8.7 12.5 14.4 15.7 16.6 19.7 20.7 22.9 25.4 28.0 29.7 32.8 33.8 36.4 37.2 38.6 40.2 42.1 43.4 43.9 44.5 48.0 49.6 def run(self): global event, samples0, samples1; #init the synchronization # start lock to avoid reading the same data if event.isSet(): event.clear() event.wait() else: self.timestamp = int(time.time()); event.set() for x in range(0, self.times): #read output = self.sdr.read_samples(self.size); if self.addr == 0: #ref samples0 = np.array(output, dtype = np.complex128); else: samples1 = np.array(output, dtype = np.complex128); if event.isSet(): event.clear() if not self.alive: break; event.wait() else: self.save2mat(x) self.timestamp = int(time.time()); print '*'*3+' '+str(x)+' done: '+time.asctime( time.localtime(time.time()) ); if not self.alive: break; event.set() def save2mat(self, i): global samples0, samples1; std0 = np.around(np.std(samples0), 5); std1 = np.around(np.std(samples1), 5); print 'std0:', std0, 'std1', std1; scipy.io.savemat('./data/'+folder_name+'/'+filename+'_'+str(i)+'.mat', mdict={'s0':samples0, 's1':samples1, 'timestamp': self.timestamp, 'fs':self.sdr.sample_rate, 'ref_addr':ref_addr});
class Sampler(QtCore.QObject): samplerError = QtCore.pyqtSignal(object) dataAcquired = QtCore.pyqtSignal(object) def __init__(self, gain, sampRate, freqs, numSamples, parent=None): super(Sampler, self).__init__(parent) self.gain = gain self.sampRate = sampRate self.freqs = freqs self.numSamples = numSamples self.offset = 0 self.sdr = None self.errorMsg = None self.WORKING = True self.BREAK = False self.MEASURE = False try: self.sdr = RtlSdr() self.sdr.set_manual_gain_enabled(1) self.sdr.gain = self.gain self.sdr.sample_rate = self.sampRate except IOError: self.WORKING = False print "Failed to initiate device. Please reconnect." self.errorMsg = "Failed to initiate device. Please reconnect." self.samplerError.emit(self.errorMsg) def sampling(self): print 'Starting sampler...' while self.WORKING: prev = 0 counter = 0 gain = self.gain numSamples = self.numSamples self.BREAK = False self.sdr.gain = gain start = time.time() #print self.sdr.get_gain() for i in range(len(self.freqs)): if self.BREAK: break else: centerFreq = self.freqs[i] #print "frequency: " + str(center_freq/1e6) + "MHz" if centerFreq != prev: try: self.sdr.set_center_freq(centerFreq) except: self.WORKING = False print "Device failure while setting center frequency" self.errorMsg = "Device failure while setting center frequency" self.samplerError.emit(self.errorMsg) break prev = centerFreq else: pass #time.sleep(0.01) try: x = self.sdr.read_samples(2048) data = self.sdr.read_samples(numSamples) except: self.WORKING = False print "Device failure while getting samples" self.errorMsg = "Device failure while getting samples" self.samplerError.emit(self.errorMsg) break if self.MEASURE: self.offset = np.mean(data) counter += 1 self.dataAcquired.emit([i, centerFreq, data]) if self.errorMsg is not None: self.samplerError.emit(self.errorMsg) if self.sdr is not None: self.sdr.close()
#from scipy import signal sdr = RtlSdr() # sdr sdr.sample_rate = 2.048e6 sdr.center_freq = 105e6 sdr.freq_correction = 60 sdr.gain = 'auto' # Azure key_name = 'RootManageSharedAccessKey' key_value = 'uoDYiA/o3Jjtp2Wb4f3HZnclv73VneyPigcZ0jwGMEU=' service_namespace = 'joksdrpsd' evhub = 'sdr1' sbs=ServiceBusService(service_namespace,shared_access_key_name=key_name,shared_access_key_value=key_value) x = 1024 # FFT bins i = 256 # Passes while(True): samples = sdr.read_samples(i*x) sdr.close() power,freq = psd(samples, NFFT=x, Fs=sdr.sample_rate/1e6) for i in range(len(freq)): msg = '{"psd": "' + str(freq[i]) + ',' + str(power[i]) + '"}' sbs.send_event(evhub,msg)
class FMRadio: # multiple of 256 def __init__(self,freq,N_samples): self.sample_rate = 1e6 self.decim_r1 = 1e6/2e5 # for wideband fm self.decim_r2 = 2e5/44100 # for baseband recovery self.center_freq = freq self.gain = 36 self.N_samples = N_samples self.sdr = RtlSdr() self.sdr.direct_sampling = 1 self.sdr.sample_rate = self.sample_rate self.sdr.center_freq = self.center_freq self.sdr.gain = self.gain self.pa = pyaudio.PyAudio() self.stream = self.pa.open( format = pyaudio.paFloat32, channels = 1, rate = 44100, output = True) hamming = 10*signal.hamming(self.N_samples*.10 ) lpf = np.append( np.zeros(self.N_samples*.45),hamming) self.lpf = np.fft.fftshift(np.append(lpf,np.zeros(self.N_samples*.45))) def __del__(self): print "sdr closed" self.sdr.close() print "pyaudio terminated" self.pa.terminate() def getSamples(self): #N_samples = self.N_samples # 1/24.4 seconds ~46336 #approximately a blocksize amount's time return self.sdr.read_samples(self.N_samples) # def demodulate_threaded(self,samples): # async_demodulation = self.pool.apply_async(self.demodulate, samples, callback=self.play) def demodulate(self,samples): # DEMODULATION CODE #samples = #self.sample_buffer.get() # LIMITER goes here # low pass & down sampling via fft spectrum = np.fft.fft(samples) * (self.lpf) # toplot = False # if(toplot): # fig = plt.figure() # plt.plot(np.abs(spectrum)) # plt.show() # Decimate in two rounds. One to 200k, another to 44.1k # DECIMATE HERE. Note that we're looking at 1MHz bandwidth. n_s = spectrum.size channel_spectrum = np.append(spectrum[0:n_s/self.decim_r1*.5],spectrum[n_s-n_s/self.decim_r1*.5:n_s]) #radio_spectrum -= np.mean(radio_spectrum) #attempt to remove dc bias # toplot = False # if(toplot): # fig = plt.figure() # plt.plot(np.abs(channel_spectrum)) # plt.show() lp_samples = np.fft.ifft(channel_spectrum) #lp_samples = self.lowpass_filter(lp_samples,4) # polar discriminator A = lp_samples[1:lp_samples.size] B = lp_samples[0:lp_samples.size-1] dphase = ( A * np.conj(B) ) #dpm = np.mean(np.abs(dphase)) # normalize # dphase /= dpm dphase.resize(dphase.size+1) dphase[dphase.size-1] = dphase[dphase.size-2] rebuilt = signal.medfilt(np.angle(dphase)/np.pi,15) # np.cos(dphase) #phase = np.sin(rebuilt) #phase = self.lowpass_filter(phase,8) #rebuilt= self.lowpass_filter(rebuilt,8) # toplot = False # if toplot: # fig = plt.figure() # ax = fig.add_subplot(111) # ax.plot(rebuilt) # ax.plot(phase) # plt.show() spectrum = np.fft.fft(rebuilt) #* self.lpf2 n_s = spectrum.size base_spectrum = np.append(spectrum[0:n_s/self.decim_r2*.5],spectrum[n_s-n_s/self.decim_r2*.5:n_s]) output = np.fft.ifft(base_spectrum) #check: should be 1807 or very close to it. it is!! # output = self.lowpass_filter(np.real(output),16) #[12:8204] # toplot = False # if(toplot): # fig = plt.figure() # plt.plot(np.real(output)) # plt.show() return np.real(output) def demodulate2(self,samples): # DEMODULATION CODE # LIMITER goes here # low pass & down sampling lp_samples = signal.decimate(self.lowpass_filter(samples,16),int(self.decim_r1)) # polar discriminator A = lp_samples[1:lp_samples.size] B = lp_samples[0:lp_samples.size-1] dphase = ( A * np.conj(B) ) dphase.resize(dphase.size+1) dphase[dphase.size-1] = dphase[dphase.size-2] rebuilt = signal.medfilt(np.angle(dphase)/np.pi,15) # np.cos(dphase) output = signal.decimate(rebuilt,int(self.decim_r2)) return np.real(output) def lowpass_filter(self,x,width): #wndw = np.sinc(np.r_[-15:16]/np.pi)/np.pi wndw = np.kaiser(width,6) wndw /= np.sum(wndw) new_array = signal.fftconvolve(x, wndw) return new_array[int(width/2):x.size+int(width/2)] def play(self,samples): self.stream.write( samples.astype(np.float32).tostring() ) def start(self): while True: self.play(self.demodulate(self.getSamples()))