fm_radio.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  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. ##################################################
  74. # Blocks
  75. ##################################################
  76. self._volume_range = Range(0, 1, 0.05, 0.5, 200)
  77. self._volume_win = RangeWidget(self._volume_range, self.set_volume, 'Volume', "counter_slider", float)
  78. self.top_grid_layout.addWidget(self._volume_win)
  79. self._frequency_mhz_range = Range(87.5, 108, 0.1, 98.3, 200)
  80. self._frequency_mhz_win = RangeWidget(self._frequency_mhz_range, self.set_frequency_mhz, 'Frequency MHz', "counter_slider", float)
  81. self.top_grid_layout.addWidget(self._frequency_mhz_win)
  82. self.rtlsdr_source_0 = osmosdr.source(
  83. args="numchan=" + str(1) + " " + ""
  84. )
  85. self.rtlsdr_source_0.set_time_unknown_pps(osmosdr.time_spec_t())
  86. self.rtlsdr_source_0.set_sample_rate(samp_rate)
  87. self.rtlsdr_source_0.set_center_freq(frequency_mhz*1e6, 0)
  88. self.rtlsdr_source_0.set_freq_corr(0, 0)
  89. self.rtlsdr_source_0.set_gain(20, 0)
  90. self.rtlsdr_source_0.set_if_gain(20, 0)
  91. self.rtlsdr_source_0.set_bb_gain(20, 0)
  92. self.rtlsdr_source_0.set_antenna('', 0)
  93. self.rtlsdr_source_0.set_bandwidth(0, 0)
  94. self.rational_resampler_xxx_0 = filter.rational_resampler_fff(
  95. interpolation=48000,
  96. decimation=channel_width_hertz,
  97. taps=None,
  98. fractional_bw=None)
  99. self.qtgui_waterfall_sink_x_0 = qtgui.waterfall_sink_c(
  100. 1048, #size
  101. firdes.WIN_BLACKMAN_hARRIS, #wintype
  102. frequency_mhz*1e6, #fc
  103. samp_rate, #bw
  104. "", #name
  105. 1 #number of inputs
  106. )
  107. self.qtgui_waterfall_sink_x_0.set_update_time(0.10)
  108. self.qtgui_waterfall_sink_x_0.enable_grid(False)
  109. self.qtgui_waterfall_sink_x_0.enable_axis_labels(True)
  110. labels = ['', '', '', '', '',
  111. '', '', '', '', '']
  112. colors = [0, 0, 0, 0, 0,
  113. 0, 0, 0, 0, 0]
  114. alphas = [1.0, 1.0, 1.0, 1.0, 1.0,
  115. 1.0, 1.0, 1.0, 1.0, 1.0]
  116. for i in range(1):
  117. if len(labels[i]) == 0:
  118. self.qtgui_waterfall_sink_x_0.set_line_label(i, "Data {0}".format(i))
  119. else:
  120. self.qtgui_waterfall_sink_x_0.set_line_label(i, labels[i])
  121. self.qtgui_waterfall_sink_x_0.set_color_map(i, colors[i])
  122. self.qtgui_waterfall_sink_x_0.set_line_alpha(i, alphas[i])
  123. self.qtgui_waterfall_sink_x_0.set_intensity_range(-140, 10)
  124. self._qtgui_waterfall_sink_x_0_win = sip.wrapinstance(self.qtgui_waterfall_sink_x_0.pyqwidget(), Qt.QWidget)
  125. self.top_grid_layout.addWidget(self._qtgui_waterfall_sink_x_0_win)
  126. self.qtgui_freq_sink_x_0 = qtgui.freq_sink_f(
  127. 1024, #size
  128. firdes.WIN_BLACKMAN_hARRIS, #wintype
  129. 0, #fc
  130. channel_width_hertz, #bw
  131. "Demod Out", #name
  132. 1
  133. )
  134. self.qtgui_freq_sink_x_0.set_update_time(0.10)
  135. self.qtgui_freq_sink_x_0.set_y_axis(-140, 10)
  136. self.qtgui_freq_sink_x_0.set_y_label('Relative Gain', 'dB')
  137. self.qtgui_freq_sink_x_0.set_trigger_mode(qtgui.TRIG_MODE_FREE, 0.0, 0, "")
  138. self.qtgui_freq_sink_x_0.enable_autoscale(False)
  139. self.qtgui_freq_sink_x_0.enable_grid(False)
  140. self.qtgui_freq_sink_x_0.set_fft_average(1.0)
  141. self.qtgui_freq_sink_x_0.enable_axis_labels(True)
  142. self.qtgui_freq_sink_x_0.enable_control_panel(False)
  143. self.qtgui_freq_sink_x_0.disable_legend()
  144. self.qtgui_freq_sink_x_0.set_plot_pos_half(not True)
  145. labels = ['', '', '', '', '',
  146. '', '', '', '', '']
  147. widths = [1, 1, 1, 1, 1,
  148. 1, 1, 1, 1, 1]
  149. colors = ["blue", "red", "green", "black", "cyan",
  150. "magenta", "yellow", "dark red", "dark green", "dark blue"]
  151. alphas = [1.0, 1.0, 1.0, 1.0, 1.0,
  152. 1.0, 1.0, 1.0, 1.0, 1.0]
  153. for i in range(1):
  154. if len(labels[i]) == 0:
  155. self.qtgui_freq_sink_x_0.set_line_label(i, "Data {0}".format(i))
  156. else:
  157. self.qtgui_freq_sink_x_0.set_line_label(i, labels[i])
  158. self.qtgui_freq_sink_x_0.set_line_width(i, widths[i])
  159. self.qtgui_freq_sink_x_0.set_line_color(i, colors[i])
  160. self.qtgui_freq_sink_x_0.set_line_alpha(i, alphas[i])
  161. self._qtgui_freq_sink_x_0_win = sip.wrapinstance(self.qtgui_freq_sink_x_0.pyqwidget(), Qt.QWidget)
  162. self.top_grid_layout.addWidget(self._qtgui_freq_sink_x_0_win)
  163. self.low_pass_filter_0 = filter.fir_filter_ccf(
  164. int(samp_rate/channel_width_hertz),
  165. firdes.low_pass(
  166. 2,
  167. samp_rate,
  168. 100000,
  169. 10000,
  170. firdes.WIN_KAISER,
  171. 6.76))
  172. self.blocks_multiply_const_vxx_0 = blocks.multiply_const_ff(volume)
  173. self.audio_sink_0 = audio.sink(48000, '', True)
  174. self.analog_wfm_rcv_0 = analog.wfm_rcv(
  175. quad_rate=channel_width_hertz,
  176. audio_decimation=1,
  177. )
  178. ##################################################
  179. # Connections
  180. ##################################################
  181. self.connect((self.analog_wfm_rcv_0, 0), (self.qtgui_freq_sink_x_0, 0))
  182. self.connect((self.analog_wfm_rcv_0, 0), (self.rational_resampler_xxx_0, 0))
  183. self.connect((self.blocks_multiply_const_vxx_0, 0), (self.audio_sink_0, 0))
  184. self.connect((self.low_pass_filter_0, 0), (self.analog_wfm_rcv_0, 0))
  185. self.connect((self.rational_resampler_xxx_0, 0), (self.blocks_multiply_const_vxx_0, 0))
  186. self.connect((self.rtlsdr_source_0, 0), (self.low_pass_filter_0, 0))
  187. self.connect((self.rtlsdr_source_0, 0), (self.qtgui_waterfall_sink_x_0, 0))
  188. def closeEvent(self, event):
  189. self.settings = Qt.QSettings("GNU Radio", "fm_radio")
  190. self.settings.setValue("geometry", self.saveGeometry())
  191. event.accept()
  192. def get_volume(self):
  193. return self.volume
  194. def set_volume(self, volume):
  195. self.volume = volume
  196. self.blocks_multiply_const_vxx_0.set_k(self.volume)
  197. def get_samp_rate(self):
  198. return self.samp_rate
  199. def set_samp_rate(self, samp_rate):
  200. self.samp_rate = samp_rate
  201. self.low_pass_filter_0.set_taps(firdes.low_pass(2, self.samp_rate, 100000, 10000, firdes.WIN_KAISER, 6.76))
  202. self.qtgui_waterfall_sink_x_0.set_frequency_range(self.frequency_mhz*1e6, self.samp_rate)
  203. self.rtlsdr_source_0.set_sample_rate(self.samp_rate)
  204. def get_frequency_mhz(self):
  205. return self.frequency_mhz
  206. def set_frequency_mhz(self, frequency_mhz):
  207. self.frequency_mhz = frequency_mhz
  208. self.qtgui_waterfall_sink_x_0.set_frequency_range(self.frequency_mhz*1e6, self.samp_rate)
  209. self.rtlsdr_source_0.set_center_freq(self.frequency_mhz*1e6, 0)
  210. def get_channel_width_hertz(self):
  211. return self.channel_width_hertz
  212. def set_channel_width_hertz(self, channel_width_hertz):
  213. self.channel_width_hertz = channel_width_hertz
  214. self.qtgui_freq_sink_x_0.set_frequency_range(0, self.channel_width_hertz)
  215. def main(top_block_cls=fm_radio, options=None):
  216. if StrictVersion("4.5.0") <= StrictVersion(Qt.qVersion()) < StrictVersion("5.0.0"):
  217. style = gr.prefs().get_string('qtgui', 'style', 'raster')
  218. Qt.QApplication.setGraphicsSystem(style)
  219. qapp = Qt.QApplication(sys.argv)
  220. tb = top_block_cls()
  221. tb.start()
  222. tb.show()
  223. def sig_handler(sig=None, frame=None):
  224. Qt.QApplication.quit()
  225. signal.signal(signal.SIGINT, sig_handler)
  226. signal.signal(signal.SIGTERM, sig_handler)
  227. timer = Qt.QTimer()
  228. timer.start(500)
  229. timer.timeout.connect(lambda: None)
  230. def quitting():
  231. tb.stop()
  232. tb.wait()
  233. qapp.aboutToQuit.connect(quitting)
  234. qapp.exec_()
  235. if __name__ == '__main__':
  236. main()