fm_radio.py 11 KB

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