fm_radio.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. #
  4. # SPDX-License-Identifier: GPL-3.0
  5. #
  6. # GNU Radio Python Flow Graph
  7. # Title: FM Radio Receiver
  8. # GNU Radio version: 3.10.5.1
  9. from packaging.version import Version as StrictVersion
  10. if __name__ == '__main__':
  11. import ctypes
  12. import sys
  13. if sys.platform.startswith('linux'):
  14. try:
  15. x11 = ctypes.cdll.LoadLibrary('libX11.so')
  16. x11.XInitThreads()
  17. except:
  18. print("Warning: failed to XInitThreads()")
  19. from PyQt5 import Qt
  20. from gnuradio import qtgui
  21. from gnuradio.filter import firdes
  22. import sip
  23. from gnuradio import analog
  24. from gnuradio import audio
  25. from gnuradio import blocks
  26. from gnuradio import filter
  27. from gnuradio import gr
  28. from gnuradio.fft import window
  29. import sys
  30. import signal
  31. from argparse import ArgumentParser
  32. from gnuradio.eng_arg import eng_float, intx
  33. from gnuradio import eng_notation
  34. from gnuradio.qtgui import Range, RangeWidget
  35. from PyQt5 import QtCore
  36. import osmosdr
  37. import time
  38. from gnuradio import qtgui
  39. class fm_radio(gr.top_block, Qt.QWidget):
  40. def __init__(self):
  41. gr.top_block.__init__(self, "FM Radio Receiver", catch_exceptions=True)
  42. Qt.QWidget.__init__(self)
  43. self.setWindowTitle("FM Radio Receiver")
  44. qtgui.util.check_set_qss()
  45. try:
  46. self.setWindowIcon(Qt.QIcon.fromTheme('gnuradio-grc'))
  47. except:
  48. pass
  49. self.top_scroll_layout = Qt.QVBoxLayout()
  50. self.setLayout(self.top_scroll_layout)
  51. self.top_scroll = Qt.QScrollArea()
  52. self.top_scroll.setFrameStyle(Qt.QFrame.NoFrame)
  53. self.top_scroll_layout.addWidget(self.top_scroll)
  54. self.top_scroll.setWidgetResizable(True)
  55. self.top_widget = Qt.QWidget()
  56. self.top_scroll.setWidget(self.top_widget)
  57. self.top_layout = Qt.QVBoxLayout(self.top_widget)
  58. self.top_grid_layout = Qt.QGridLayout()
  59. self.top_layout.addLayout(self.top_grid_layout)
  60. self.settings = Qt.QSettings("GNU Radio", "fm_radio")
  61. try:
  62. if StrictVersion(Qt.qVersion()) < StrictVersion("5.0.0"):
  63. self.restoreGeometry(self.settings.value("geometry").toByteArray())
  64. else:
  65. self.restoreGeometry(self.settings.value("geometry"))
  66. except:
  67. pass
  68. ##################################################
  69. # Variables
  70. ##################################################
  71. self.volume = volume = 0.5
  72. self.samp_rate = samp_rate = 2560000
  73. self.frequency_mhz = frequency_mhz = 98.3
  74. self.channel_width_hertz = channel_width_hertz = 250000
  75. self.audio_sample_rate_hertz = audio_sample_rate_hertz = 48000
  76. ##################################################
  77. # Blocks
  78. ##################################################
  79. self._volume_range = Range(0, 1, 0.05, 0.5, 200)
  80. self._volume_win = RangeWidget(self._volume_range, self.set_volume, "Volume", "counter_slider", float, QtCore.Qt.Horizontal)
  81. self.top_layout.addWidget(self._volume_win)
  82. self._frequency_mhz_range = Range(87.5, 108, 0.1, 98.3, 200)
  83. self._frequency_mhz_win = RangeWidget(self._frequency_mhz_range, self.set_frequency_mhz, "Frequency MHz", "counter_slider", float, QtCore.Qt.Horizontal)
  84. self.top_layout.addWidget(self._frequency_mhz_win)
  85. self.rtlsdr_source_0 = osmosdr.source(
  86. args="numchan=" + str(1) + " " + ""
  87. )
  88. self.rtlsdr_source_0.set_time_unknown_pps(osmosdr.time_spec_t())
  89. self.rtlsdr_source_0.set_sample_rate(samp_rate)
  90. self.rtlsdr_source_0.set_center_freq((frequency_mhz*1e6), 0)
  91. self.rtlsdr_source_0.set_freq_corr(0, 0)
  92. self.rtlsdr_source_0.set_dc_offset_mode(0, 0)
  93. self.rtlsdr_source_0.set_iq_balance_mode(0, 0)
  94. self.rtlsdr_source_0.set_gain_mode(False, 0)
  95. self.rtlsdr_source_0.set_gain(20, 0)
  96. self.rtlsdr_source_0.set_if_gain(20, 0)
  97. self.rtlsdr_source_0.set_bb_gain(20, 0)
  98. self.rtlsdr_source_0.set_antenna('', 0)
  99. self.rtlsdr_source_0.set_bandwidth(0, 0)
  100. self.rational_resampler_xxx_0 = filter.rational_resampler_fff(
  101. interpolation=audio_sample_rate_hertz,
  102. decimation=channel_width_hertz,
  103. taps=[],
  104. fractional_bw=0)
  105. self.qtgui_waterfall_sink_x_0 = qtgui.waterfall_sink_c(
  106. 1024, #size
  107. window.WIN_BLACKMAN_hARRIS, #wintype
  108. (frequency_mhz*1e6), #fc
  109. samp_rate, #bw
  110. "", #name
  111. 1, #number of inputs
  112. None # parent
  113. )
  114. self.qtgui_waterfall_sink_x_0.set_update_time(0.10)
  115. self.qtgui_waterfall_sink_x_0.enable_grid(False)
  116. self.qtgui_waterfall_sink_x_0.enable_axis_labels(True)
  117. labels = ['', '', '', '', '',
  118. '', '', '', '', '']
  119. colors = [0, 0, 0, 0, 0,
  120. 0, 0, 0, 0, 0]
  121. alphas = [1.0, 1.0, 1.0, 1.0, 1.0,
  122. 1.0, 1.0, 1.0, 1.0, 1.0]
  123. for i in range(1):
  124. if len(labels[i]) == 0:
  125. self.qtgui_waterfall_sink_x_0.set_line_label(i, "Data {0}".format(i))
  126. else:
  127. self.qtgui_waterfall_sink_x_0.set_line_label(i, labels[i])
  128. self.qtgui_waterfall_sink_x_0.set_color_map(i, colors[i])
  129. self.qtgui_waterfall_sink_x_0.set_line_alpha(i, alphas[i])
  130. self.qtgui_waterfall_sink_x_0.set_intensity_range(-140, 10)
  131. self._qtgui_waterfall_sink_x_0_win = sip.wrapinstance(self.qtgui_waterfall_sink_x_0.qwidget(), Qt.QWidget)
  132. self.top_layout.addWidget(self._qtgui_waterfall_sink_x_0_win)
  133. self.qtgui_freq_sink_x_0 = qtgui.freq_sink_f(
  134. 1024, #size
  135. window.WIN_BLACKMAN_hARRIS, #wintype
  136. 0, #fc
  137. channel_width_hertz, #bw
  138. "Demod Out", #name
  139. 1,
  140. None # parent
  141. )
  142. self.qtgui_freq_sink_x_0.set_update_time(0.10)
  143. self.qtgui_freq_sink_x_0.set_y_axis((-140), 10)
  144. self.qtgui_freq_sink_x_0.set_y_label('Relative Gain', 'dB')
  145. self.qtgui_freq_sink_x_0.set_trigger_mode(qtgui.TRIG_MODE_FREE, 0.0, 0, "")
  146. self.qtgui_freq_sink_x_0.enable_autoscale(False)
  147. self.qtgui_freq_sink_x_0.enable_grid(False)
  148. self.qtgui_freq_sink_x_0.set_fft_average(1.0)
  149. self.qtgui_freq_sink_x_0.enable_axis_labels(True)
  150. self.qtgui_freq_sink_x_0.enable_control_panel(False)
  151. self.qtgui_freq_sink_x_0.set_fft_window_normalized(False)
  152. self.qtgui_freq_sink_x_0.disable_legend()
  153. self.qtgui_freq_sink_x_0.set_plot_pos_half(not True)
  154. labels = ['', '', '', '', '',
  155. '', '', '', '', '']
  156. widths = [1, 1, 1, 1, 1,
  157. 1, 1, 1, 1, 1]
  158. colors = ["blue", "red", "green", "black", "cyan",
  159. "magenta", "yellow", "dark red", "dark green", "dark blue"]
  160. alphas = [1.0, 1.0, 1.0, 1.0, 1.0,
  161. 1.0, 1.0, 1.0, 1.0, 1.0]
  162. for i in range(1):
  163. if len(labels[i]) == 0:
  164. self.qtgui_freq_sink_x_0.set_line_label(i, "Data {0}".format(i))
  165. else:
  166. self.qtgui_freq_sink_x_0.set_line_label(i, labels[i])
  167. self.qtgui_freq_sink_x_0.set_line_width(i, widths[i])
  168. self.qtgui_freq_sink_x_0.set_line_color(i, colors[i])
  169. self.qtgui_freq_sink_x_0.set_line_alpha(i, alphas[i])
  170. self._qtgui_freq_sink_x_0_win = sip.wrapinstance(self.qtgui_freq_sink_x_0.qwidget(), Qt.QWidget)
  171. self.top_layout.addWidget(self._qtgui_freq_sink_x_0_win)
  172. self.low_pass_filter_0 = filter.fir_filter_ccf(
  173. (int(samp_rate/channel_width_hertz)),
  174. firdes.low_pass(
  175. 2,
  176. samp_rate,
  177. 100000,
  178. 10000,
  179. window.WIN_KAISER,
  180. 6.76))
  181. self.blocks_multiply_const_vxx_0 = blocks.multiply_const_ff(volume)
  182. self.audio_sink_0 = audio.sink(audio_sample_rate_hertz, '', True)
  183. self.analog_wfm_rcv_0 = analog.wfm_rcv(
  184. quad_rate=channel_width_hertz,
  185. audio_decimation=1,
  186. )
  187. ##################################################
  188. # Connections
  189. ##################################################
  190. self.connect((self.analog_wfm_rcv_0, 0), (self.qtgui_freq_sink_x_0, 0))
  191. self.connect((self.analog_wfm_rcv_0, 0), (self.rational_resampler_xxx_0, 0))
  192. self.connect((self.blocks_multiply_const_vxx_0, 0), (self.audio_sink_0, 0))
  193. self.connect((self.low_pass_filter_0, 0), (self.analog_wfm_rcv_0, 0))
  194. self.connect((self.rational_resampler_xxx_0, 0), (self.blocks_multiply_const_vxx_0, 0))
  195. self.connect((self.rtlsdr_source_0, 0), (self.low_pass_filter_0, 0))
  196. self.connect((self.rtlsdr_source_0, 0), (self.qtgui_waterfall_sink_x_0, 0))
  197. def closeEvent(self, event):
  198. self.settings = Qt.QSettings("GNU Radio", "fm_radio")
  199. self.settings.setValue("geometry", self.saveGeometry())
  200. self.stop()
  201. self.wait()
  202. event.accept()
  203. def get_volume(self):
  204. return self.volume
  205. def set_volume(self, volume):
  206. self.volume = volume
  207. self.blocks_multiply_const_vxx_0.set_k(self.volume)
  208. def get_samp_rate(self):
  209. return self.samp_rate
  210. def set_samp_rate(self, samp_rate):
  211. self.samp_rate = samp_rate
  212. self.low_pass_filter_0.set_taps(firdes.low_pass(2, self.samp_rate, 100000, 10000, window.WIN_KAISER, 6.76))
  213. self.qtgui_waterfall_sink_x_0.set_frequency_range((self.frequency_mhz*1e6), self.samp_rate)
  214. self.rtlsdr_source_0.set_sample_rate(self.samp_rate)
  215. def get_frequency_mhz(self):
  216. return self.frequency_mhz
  217. def set_frequency_mhz(self, frequency_mhz):
  218. self.frequency_mhz = frequency_mhz
  219. self.qtgui_waterfall_sink_x_0.set_frequency_range((self.frequency_mhz*1e6), self.samp_rate)
  220. self.rtlsdr_source_0.set_center_freq((self.frequency_mhz*1e6), 0)
  221. def get_channel_width_hertz(self):
  222. return self.channel_width_hertz
  223. def set_channel_width_hertz(self, channel_width_hertz):
  224. self.channel_width_hertz = channel_width_hertz
  225. self.qtgui_freq_sink_x_0.set_frequency_range(0, self.channel_width_hertz)
  226. def get_audio_sample_rate_hertz(self):
  227. return self.audio_sample_rate_hertz
  228. def set_audio_sample_rate_hertz(self, audio_sample_rate_hertz):
  229. self.audio_sample_rate_hertz = audio_sample_rate_hertz
  230. def main(top_block_cls=fm_radio, options=None):
  231. if StrictVersion("4.5.0") <= StrictVersion(Qt.qVersion()) < StrictVersion("5.0.0"):
  232. style = gr.prefs().get_string('qtgui', 'style', 'raster')
  233. Qt.QApplication.setGraphicsSystem(style)
  234. qapp = Qt.QApplication(sys.argv)
  235. tb = top_block_cls()
  236. tb.start()
  237. tb.show()
  238. def sig_handler(sig=None, frame=None):
  239. tb.stop()
  240. tb.wait()
  241. Qt.QApplication.quit()
  242. signal.signal(signal.SIGINT, sig_handler)
  243. signal.signal(signal.SIGTERM, sig_handler)
  244. timer = Qt.QTimer()
  245. timer.start(500)
  246. timer.timeout.connect(lambda: None)
  247. qapp.exec_()
  248. if __name__ == '__main__':
  249. main()