summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntoine Blais2024-01-25 15:30:38 +0100
committerAntoine Blais2024-01-25 15:30:38 +0100
commitc56ae1cc47ec271c1335ece5dd409a4c66a14715 (patch)
treeecd8d2b5b130246bae08303a0facd59e48e4492f
parent6fd43eec4663657997dc59411cdb89b38cdff8b2 (diff)
downloadspectrum_analyser-c56ae1cc47ec271c1335ece5dd409a4c66a14715.zip
spectrum_analyser-c56ae1cc47ec271c1335ece5dd409a4c66a14715.tar.gz
spectrum_analyser-c56ae1cc47ec271c1335ece5dd409a4c66a14715.tar.bz2
spectrum_analyser-c56ae1cc47ec271c1335ece5dd409a4c66a14715.tar.xz
Commit initial.
-rw-r--r--analyseur_de_spectre_a_balayage.grc817
-rw-r--r--simple_spectrum_analyser_scope.py220
2 files changed, 1037 insertions, 0 deletions
diff --git a/analyseur_de_spectre_a_balayage.grc b/analyseur_de_spectre_a_balayage.grc
new file mode 100644
index 0000000..3bf45a7
--- /dev/null
+++ b/analyseur_de_spectre_a_balayage.grc
@@ -0,0 +1,817 @@
+options:
+ parameters:
+ author: Antoine Blais
+ catch_exceptions: 'True'
+ category: Custom
+ cmake_opt: ''
+ comment: ''
+ copyright: Antoine Blais 2023
+ description: "Analyseur de spectre \xE0 balayage"
+ gen_cmake: 'On'
+ gen_linking: dynamic
+ generate_options: qt_gui
+ hier_block_src_path: '.:'
+ id: analyseur_de_spectre_a_balayage
+ max_nouts: '0'
+ output_language: python
+ placement: (0,0)
+ qt_qss_theme: ''
+ realtime_scheduling: ''
+ run: 'True'
+ run_command: '{python} -u {filename}'
+ run_options: prompt
+ sizing_mode: fixed
+ thread_safe_setters: ''
+ title: "Analyseur de spectre \xE0 balayage"
+ window_size: 1600,600
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [16, 16.0]
+ rotation: 0
+ state: enabled
+
+blocks:
+- name: decim_RF_2_BF
+ id: variable
+ parameters:
+ comment: ''
+ value: int(samp_rate/rbw)
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [816, 16.0]
+ rotation: 0
+ state: enabled
+- name: freq_val
+ id: variable_function_probe
+ parameters:
+ block_id: freq
+ comment: ''
+ function_args: ''
+ function_name: level
+ poll_rate: poll_rate
+ value: '0'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [1032, 616.0]
+ rotation: 0
+ state: enabled
+- name: gain_rf
+ id: variable_qtgui_range
+ parameters:
+ comment: ''
+ gui_hint: ''
+ label: Gain RF
+ min_len: '200'
+ orient: QtCore.Qt.Horizontal
+ rangeType: float
+ start: '0'
+ step: '1'
+ stop: '49.6'
+ value: '49.6'
+ widget: counter_slider
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [960, 16.0]
+ rotation: 0
+ state: enabled
+- name: label_freq
+ id: variable_qtgui_label
+ parameters:
+ comment: ''
+ formatter: 'lambda x: f''{x/1e6:.3f} MHz'''
+ gui_hint: ''
+ label: "\"Fr\xE9quence : \""
+ type: real
+ value: freq_val
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [1096, 16.0]
+ rotation: 0
+ state: enabled
+- name: poll_rate
+ id: variable
+ parameters:
+ comment: ''
+ value: '25'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [520, 96.0]
+ rotation: 0
+ state: enabled
+- name: rbw
+ id: variable
+ parameters:
+ comment: ''
+ value: 10e3
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [648, 16.0]
+ rotation: 0
+ state: enabled
+- name: samp_rate
+ id: variable
+ parameters:
+ comment: ''
+ value: 250e3
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [520, 16.0]
+ rotation: 0
+ state: enabled
+- name: samp_rate_BF
+ id: variable
+ parameters:
+ comment: ''
+ value: samp_rate/decim_RF_2_BF
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [816, 96.0]
+ rotation: 0
+ state: enabled
+- name: span
+ id: variable
+ parameters:
+ comment: ''
+ value: 20.5e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [312, 16.0]
+ rotation: 0
+ state: enabled
+- name: start_freq
+ id: variable
+ parameters:
+ comment: ''
+ value: 87.5e6
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [216, 16.0]
+ rotation: 0
+ state: enabled
+- name: sweep
+ id: variable
+ parameters:
+ comment: ''
+ value: 20.5*3
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [408, 16.0]
+ rotation: 0
+ state: enabled
+- name: vbw
+ id: variable
+ parameters:
+ comment: ''
+ value: 2.5e3
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [728, 16.0]
+ rotation: 0
+ state: enabled
+- name: analog_const_source_x_0
+ id: analog_const_source_x
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ const: start_freq
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ type: float
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [792, 208.0]
+ rotation: 0
+ state: enabled
+- name: analog_const_source_x_0_0
+ id: analog_const_source_x
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ const: span
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ type: float
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [792, 272.0]
+ rotation: 0
+ state: enabled
+- name: analog_sig_source_x_0_0
+ id: analog_sig_source_x
+ parameters:
+ affinity: ''
+ alias: ''
+ amp: span
+ comment: ''
+ freq: 1.0/sweep
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ offset: start_freq
+ phase: '0'
+ samp_rate: samp_rate
+ showports: 'False'
+ type: float
+ waveform: analog.GR_SAW_WAVE
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [64, 600.0]
+ rotation: 0
+ state: enabled
+- name: blocks_complex_to_mag_squared_0
+ id: blocks_complex_to_mag_squared
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [584, 416.0]
+ rotation: 0
+ state: enabled
+- name: blocks_keep_one_in_n_0_1
+ id: blocks_keep_one_in_n
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ n: int(samp_rate_BF/poll_rate)
+ type: float
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [1008, 416.0]
+ rotation: 0
+ state: enabled
+- name: blocks_keep_one_in_n_0_1_0
+ id: blocks_keep_one_in_n
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ n: int(samp_rate/poll_rate)
+ type: float
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [584, 648.0]
+ rotation: 0
+ state: enabled
+- name: blocks_streams_to_vector_0
+ id: blocks_streams_to_vector
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ num_streams: '4'
+ type: float
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [1192, 352.0]
+ rotation: 0
+ state: enabled
+- name: blocks_throttle2_0
+ id: blocks_throttle2
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ ignoretag: 'True'
+ limit: auto
+ maximum: '0.1'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ samples_per_second: samp_rate
+ type: float
+ vlen: '1'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [368, 632.0]
+ rotation: 0
+ state: true
+- name: freq
+ id: blocks_probe_signal_x
+ parameters:
+ affinity: ''
+ alias: ''
+ comment: ''
+ type: float
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [864, 640.0]
+ rotation: 0
+ state: enabled
+- name: low_pass_filter_0
+ id: low_pass_filter
+ parameters:
+ affinity: ''
+ alias: ''
+ beta: '6.76'
+ comment: ''
+ cutoff_freq: rbw/2
+ decim: decim_RF_2_BF
+ gain: '1'
+ interp: '1'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ samp_rate: samp_rate
+ type: fir_filter_ccf
+ width: rbw/20
+ win: window.WIN_HAMMING
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [368, 356.0]
+ rotation: 0
+ state: enabled
+- name: low_pass_filter_0_0
+ id: low_pass_filter
+ parameters:
+ affinity: ''
+ alias: ''
+ beta: '6.76'
+ comment: ''
+ cutoff_freq: vbw/2
+ decim: '1'
+ gain: 1/rbw
+ interp: '1'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ samp_rate: samp_rate_BF
+ type: fir_filter_fff
+ width: vbw/20
+ win: window.WIN_HAMMING
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [792, 356.0]
+ rotation: 0
+ state: enabled
+- name: note_0
+ id: note
+ parameters:
+ alias: ''
+ comment: ''
+ note: 'SPDX-FileCopyrightText: Copyright (C) 2023 Antoine Blais; SPDX-License-Identifier:
+ GPL-3.0-or-later'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [1256, 16.0]
+ rotation: 0
+ state: enabled
+- name: rtlsdr_source_0
+ id: rtlsdr_source
+ parameters:
+ affinity: ''
+ alias: ''
+ ant0: ''
+ ant1: ''
+ ant10: ''
+ ant11: ''
+ ant12: ''
+ ant13: ''
+ ant14: ''
+ ant15: ''
+ ant16: ''
+ ant17: ''
+ ant18: ''
+ ant19: ''
+ ant2: ''
+ ant20: ''
+ ant21: ''
+ ant22: ''
+ ant23: ''
+ ant24: ''
+ ant25: ''
+ ant26: ''
+ ant27: ''
+ ant28: ''
+ ant29: ''
+ ant3: ''
+ ant30: ''
+ ant31: ''
+ ant4: ''
+ ant5: ''
+ ant6: ''
+ ant7: ''
+ ant8: ''
+ ant9: ''
+ args: '"rtl=0"'
+ bb_gain0: '0'
+ bb_gain1: '20'
+ bb_gain10: '20'
+ bb_gain11: '20'
+ bb_gain12: '20'
+ bb_gain13: '20'
+ bb_gain14: '20'
+ bb_gain15: '20'
+ bb_gain16: '20'
+ bb_gain17: '20'
+ bb_gain18: '20'
+ bb_gain19: '20'
+ bb_gain2: '20'
+ bb_gain20: '20'
+ bb_gain21: '20'
+ bb_gain22: '20'
+ bb_gain23: '20'
+ bb_gain24: '20'
+ bb_gain25: '20'
+ bb_gain26: '20'
+ bb_gain27: '20'
+ bb_gain28: '20'
+ bb_gain29: '20'
+ bb_gain3: '20'
+ bb_gain30: '20'
+ bb_gain31: '20'
+ bb_gain4: '20'
+ bb_gain5: '20'
+ bb_gain6: '20'
+ bb_gain7: '20'
+ bb_gain8: '20'
+ bb_gain9: '20'
+ bw0: '0'
+ bw1: '0'
+ bw10: '0'
+ bw11: '0'
+ bw12: '0'
+ bw13: '0'
+ bw14: '0'
+ bw15: '0'
+ bw16: '0'
+ bw17: '0'
+ bw18: '0'
+ bw19: '0'
+ bw2: '0'
+ bw20: '0'
+ bw21: '0'
+ bw22: '0'
+ bw23: '0'
+ bw24: '0'
+ bw25: '0'
+ bw26: '0'
+ bw27: '0'
+ bw28: '0'
+ bw29: '0'
+ bw3: '0'
+ bw30: '0'
+ bw31: '0'
+ bw4: '0'
+ bw5: '0'
+ bw6: '0'
+ bw7: '0'
+ bw8: '0'
+ bw9: '0'
+ clock_source0: ''
+ clock_source1: ''
+ clock_source2: ''
+ clock_source3: ''
+ clock_source4: ''
+ clock_source5: ''
+ clock_source6: ''
+ clock_source7: ''
+ comment: ''
+ corr0: '0'
+ corr1: '0'
+ corr10: '0'
+ corr11: '0'
+ corr12: '0'
+ corr13: '0'
+ corr14: '0'
+ corr15: '0'
+ corr16: '0'
+ corr17: '0'
+ corr18: '0'
+ corr19: '0'
+ corr2: '0'
+ corr20: '0'
+ corr21: '0'
+ corr22: '0'
+ corr23: '0'
+ corr24: '0'
+ corr25: '0'
+ corr26: '0'
+ corr27: '0'
+ corr28: '0'
+ corr29: '0'
+ corr3: '0'
+ corr30: '0'
+ corr31: '0'
+ corr4: '0'
+ corr5: '0'
+ corr6: '0'
+ corr7: '0'
+ corr8: '0'
+ corr9: '0'
+ dc_offset_mode0: '0'
+ dc_offset_mode1: '0'
+ dc_offset_mode10: '0'
+ dc_offset_mode11: '0'
+ dc_offset_mode12: '0'
+ dc_offset_mode13: '0'
+ dc_offset_mode14: '0'
+ dc_offset_mode15: '0'
+ dc_offset_mode16: '0'
+ dc_offset_mode17: '0'
+ dc_offset_mode18: '0'
+ dc_offset_mode19: '0'
+ dc_offset_mode2: '0'
+ dc_offset_mode20: '0'
+ dc_offset_mode21: '0'
+ dc_offset_mode22: '0'
+ dc_offset_mode23: '0'
+ dc_offset_mode24: '0'
+ dc_offset_mode25: '0'
+ dc_offset_mode26: '0'
+ dc_offset_mode27: '0'
+ dc_offset_mode28: '0'
+ dc_offset_mode29: '0'
+ dc_offset_mode3: '0'
+ dc_offset_mode30: '0'
+ dc_offset_mode31: '0'
+ dc_offset_mode4: '0'
+ dc_offset_mode5: '0'
+ dc_offset_mode6: '0'
+ dc_offset_mode7: '0'
+ dc_offset_mode8: '0'
+ dc_offset_mode9: '0'
+ freq0: freq_val
+ freq1: 100e6
+ freq10: 100e6
+ freq11: 100e6
+ freq12: 100e6
+ freq13: 100e6
+ freq14: 100e6
+ freq15: 100e6
+ freq16: 100e6
+ freq17: 100e6
+ freq18: 100e6
+ freq19: 100e6
+ freq2: 100e6
+ freq20: 100e6
+ freq21: 100e6
+ freq22: 100e6
+ freq23: 100e6
+ freq24: 100e6
+ freq25: 100e6
+ freq26: 100e6
+ freq27: 100e6
+ freq28: 100e6
+ freq29: 100e6
+ freq3: 100e6
+ freq30: 100e6
+ freq31: 100e6
+ freq4: 100e6
+ freq5: 100e6
+ freq6: 100e6
+ freq7: 100e6
+ freq8: 100e6
+ freq9: 100e6
+ gain0: gain_rf
+ gain1: '10'
+ gain10: '10'
+ gain11: '10'
+ gain12: '10'
+ gain13: '10'
+ gain14: '10'
+ gain15: '10'
+ gain16: '10'
+ gain17: '10'
+ gain18: '10'
+ gain19: '10'
+ gain2: '10'
+ gain20: '10'
+ gain21: '10'
+ gain22: '10'
+ gain23: '10'
+ gain24: '10'
+ gain25: '10'
+ gain26: '10'
+ gain27: '10'
+ gain28: '10'
+ gain29: '10'
+ gain3: '10'
+ gain30: '10'
+ gain31: '10'
+ gain4: '10'
+ gain5: '10'
+ gain6: '10'
+ gain7: '10'
+ gain8: '10'
+ gain9: '10'
+ gain_mode0: 'False'
+ gain_mode1: 'False'
+ gain_mode10: 'False'
+ gain_mode11: 'False'
+ gain_mode12: 'False'
+ gain_mode13: 'False'
+ gain_mode14: 'False'
+ gain_mode15: 'False'
+ gain_mode16: 'False'
+ gain_mode17: 'False'
+ gain_mode18: 'False'
+ gain_mode19: 'False'
+ gain_mode2: 'False'
+ gain_mode20: 'False'
+ gain_mode21: 'False'
+ gain_mode22: 'False'
+ gain_mode23: 'False'
+ gain_mode24: 'False'
+ gain_mode25: 'False'
+ gain_mode26: 'False'
+ gain_mode27: 'False'
+ gain_mode28: 'False'
+ gain_mode29: 'False'
+ gain_mode3: 'False'
+ gain_mode30: 'False'
+ gain_mode31: 'False'
+ gain_mode4: 'False'
+ gain_mode5: 'False'
+ gain_mode6: 'False'
+ gain_mode7: 'False'
+ gain_mode8: 'False'
+ gain_mode9: 'False'
+ if_gain0: '0'
+ if_gain1: '20'
+ if_gain10: '20'
+ if_gain11: '20'
+ if_gain12: '20'
+ if_gain13: '20'
+ if_gain14: '20'
+ if_gain15: '20'
+ if_gain16: '20'
+ if_gain17: '20'
+ if_gain18: '20'
+ if_gain19: '20'
+ if_gain2: '20'
+ if_gain20: '20'
+ if_gain21: '20'
+ if_gain22: '20'
+ if_gain23: '20'
+ if_gain24: '20'
+ if_gain25: '20'
+ if_gain26: '20'
+ if_gain27: '20'
+ if_gain28: '20'
+ if_gain29: '20'
+ if_gain3: '20'
+ if_gain30: '20'
+ if_gain31: '20'
+ if_gain4: '20'
+ if_gain5: '20'
+ if_gain6: '20'
+ if_gain7: '20'
+ if_gain8: '20'
+ if_gain9: '20'
+ iq_balance_mode0: '0'
+ iq_balance_mode1: '0'
+ iq_balance_mode10: '0'
+ iq_balance_mode11: '0'
+ iq_balance_mode12: '0'
+ iq_balance_mode13: '0'
+ iq_balance_mode14: '0'
+ iq_balance_mode15: '0'
+ iq_balance_mode16: '0'
+ iq_balance_mode17: '0'
+ iq_balance_mode18: '0'
+ iq_balance_mode19: '0'
+ iq_balance_mode2: '0'
+ iq_balance_mode20: '0'
+ iq_balance_mode21: '0'
+ iq_balance_mode22: '0'
+ iq_balance_mode23: '0'
+ iq_balance_mode24: '0'
+ iq_balance_mode25: '0'
+ iq_balance_mode26: '0'
+ iq_balance_mode27: '0'
+ iq_balance_mode28: '0'
+ iq_balance_mode29: '0'
+ iq_balance_mode3: '0'
+ iq_balance_mode30: '0'
+ iq_balance_mode31: '0'
+ iq_balance_mode4: '0'
+ iq_balance_mode5: '0'
+ iq_balance_mode6: '0'
+ iq_balance_mode7: '0'
+ iq_balance_mode8: '0'
+ iq_balance_mode9: '0'
+ maxoutbuf: '0'
+ minoutbuf: '0'
+ nchan: '1'
+ num_mboards: '1'
+ sample_rate: samp_rate
+ sync: sync
+ time_source0: ''
+ time_source1: ''
+ time_source2: ''
+ time_source3: ''
+ time_source4: ''
+ time_source5: ''
+ time_source6: ''
+ time_source7: ''
+ type: fc32
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [64, 316.0]
+ rotation: 0
+ state: enabled
+- name: zeromq_pub_sink_0
+ id: zeromq_pub_sink
+ parameters:
+ address: tcp://127.0.0.1:5555
+ affinity: ''
+ alias: ''
+ bind: 'True'
+ comment: ''
+ drop_on_hwm: 'True'
+ hwm: '-1'
+ key: ''
+ pass_tags: 'False'
+ timeout: '100'
+ type: float
+ vlen: '4'
+ states:
+ bus_sink: false
+ bus_source: false
+ bus_structure: null
+ coordinate: [1400, 352.0]
+ rotation: 0
+ state: enabled
+
+connections:
+- [analog_const_source_x_0, '0', blocks_streams_to_vector_0, '0']
+- [analog_const_source_x_0_0, '0', blocks_streams_to_vector_0, '1']
+- [analog_sig_source_x_0_0, '0', blocks_throttle2_0, '0']
+- [blocks_complex_to_mag_squared_0, '0', low_pass_filter_0_0, '0']
+- [blocks_keep_one_in_n_0_1, '0', blocks_streams_to_vector_0, '2']
+- [blocks_keep_one_in_n_0_1_0, '0', blocks_streams_to_vector_0, '3']
+- [blocks_keep_one_in_n_0_1_0, '0', freq, '0']
+- [blocks_streams_to_vector_0, '0', zeromq_pub_sink_0, '0']
+- [blocks_throttle2_0, '0', blocks_keep_one_in_n_0_1_0, '0']
+- [low_pass_filter_0, '0', blocks_complex_to_mag_squared_0, '0']
+- [low_pass_filter_0_0, '0', blocks_keep_one_in_n_0_1, '0']
+- [rtlsdr_source_0, '0', low_pass_filter_0, '0']
+
+metadata:
+ file_format: 1
+ grc_version: v3.11.0.0git-615-g6404f371
diff --git a/simple_spectrum_analyser_scope.py b/simple_spectrum_analyser_scope.py
new file mode 100644
index 0000000..1368dee
--- /dev/null
+++ b/simple_spectrum_analyser_scope.py
@@ -0,0 +1,220 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+
+# This program displays a simple spectrum analyser scope.
+
+'''
+SPDX-FileCopyrightText: Copyright (C) 2023 Antoine Blais
+SPDX-License-Identifier: GPL-3.0-or-later
+
+This file is part of analyseur_de_spectre_grc.
+
+analyseur_de_spectre_grc is free software: you can redistribute it and/or
+modify it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or (at your
+option) any later version.
+analyseur_de_spectre_grc is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+more details.
+You should have received a copy of the GNU General Public License along with
+analyseur_de_spectre_grc. If not, see <https://www.gnu.org/licenses/>. 
+'''
+
+# For the exit function
+import sys
+import pygame
+from pygame.locals import *
+import numpy as np
+import zmq
+
+import matplotlib
+import matplotlib.pyplot as plt
+import matplotlib.backends.backend_agg as agg
+
+# In order to integrate Matplotlib with Pygame, we need to use a
+# non-interactive backend, otherwise Matplotlib will present us with a GUI
+# window by default.
+matplotlib.use("Agg")
+
+pygame.init()
+
+# Plot the spectrum in dB rather than in linear scale
+in_dB = True
+
+
+def plot_spectrum(x_1, x_2, data_1, data_2, i, i_last, ax, canvas):
+ x_lim, y_lim = ax.get_xlim(), ax.get_ylim()
+ ax.clear()
+ ax.set_xlim(x_lim), ax.set_ylim(y_lim)
+ ax.xaxis.set_major_formatter('{x:.3f}')
+ ax.set_xlabel('MHz')
+
+ ax.plot(x_1[0:i], data_1[0:i], 'r')
+ j = np.searchsorted(x_2, x_1[i - 1])
+ ax.plot(x_2[j:i_last], data_2[j:i_last], 'r')
+ # ax.plot(x_2[0:i_last], data_2[0:i_last], 'b')
+
+ canvas.draw()
+ renderer = canvas.get_renderer()
+
+ # raw_data = renderer.tostring_rgb()
+ raw_data = renderer.buffer_rgba()
+ size = canvas.get_width_height()
+
+ # return pygame.image.fromstring(raw_data, size, "RGB")
+ return pygame.image.frombuffer (raw_data, size, "RGBA")
+
+
+if __name__ == "__main__":
+
+ # ZeroMQ Context
+ context = zmq.Context()
+
+ # Define the socket using the "context"
+ sock = context.socket(zmq.SUB)
+ # No filter, accept all messages
+ sock.setsockopt(zmq.SUBSCRIBE, b"")
+ sock.connect("tcp://127.0.0.1:5555")
+
+ POLL_SOCKET = USEREVENT + 1
+ # The higher the transmission rate in GRC the higher the socket polling rate
+ pygame.time.set_timer(POLL_SOCKET, 1)
+
+ # figsize=[w, h] in inches, the resulting buffer is (w*dpi)x(h*dpi) pixels
+ fig = plt.figure(figsize=[10, 5], dpi=100)
+ ax = fig.gca()
+ canvas = agg.FigureCanvasAgg(fig)
+
+ pygame.init()
+ screen = pygame.display.set_mode((1000, 500))
+ pygame.display.set_caption('Spectrum analyzer scope')
+
+ # Erase screen
+ screen.fill((255, 255, 255))
+
+ freq_l, freq_h = None, None
+ range_set = False
+ update = False
+
+ freq_val, pow_val = None, None
+ freq_old = None
+
+ i, i_last = 0, 0
+
+ n_ping, n_pong = 0, 0
+ f_ping, f_pong = np.array([]), np.array([])
+ power_ping, power_pong = np.array([]), np.array([])
+
+ n = [0, 0]
+ f = [np.array([]), np.array([])]
+ power = [np.array([]), np.array([])]
+
+ ping_or_pong = 0
+
+ pow_min, pow_max = 0, 0
+
+ dt = np.dtype(np.float32)
+
+ # old_freq, old_pow, old_t = 0, 0, time.time()
+
+ while True:
+
+ for event in pygame.event.get():
+ if event.type == pygame.QUIT or \
+ (event.type == KEYDOWN and event.key == K_q):
+ pygame.quit()
+ sys.exit()
+
+ if event.type == POLL_SOCKET:
+ try:
+ data = sock.recv(zmq.NOBLOCK)
+
+ # ld = len(data)
+ # print(u"Longueur des data = {:} : {:}".format(ld, data), file=sys.stderr)
+ # data_hex = ''.join('\\x{:02x}'.format(x) for x in data)
+ # print(data_hex, file=sys.stderr)
+
+ start_freq, span, pow_val, freq_val = np.frombuffer(data,
+ dtype=dt, count=4)
+
+ # print(u"Message : {:} {:} {:} {:}".format(start_freq, span,
+ # freq_val, pow_val), end='', file=sys.stderr)
+ # t_now = time.time()
+ # print(u" dt = {:.3f} delta f = {:} delta P = {:}".
+ # format(t_now - old_t, freq_val - old_freq,
+ # pow_val - old_pow), file=sys.stderr)
+ # old_freq, old_pow, old_t = freq_val, pow_val, t_now
+
+ if pow_val > 0:
+ if in_dB is True:
+ pow_val = 10*np.log10(pow_val)
+ else:
+ pass
+ else:
+ continue
+
+ if range_set is False:
+ freq_l, freq_h = start_freq, start_freq + span
+ freq_old = freq_val
+ print(u"Range initialization", file=sys.stderr)
+ elif (freq_l != start_freq) or (freq_h != start_freq + span):
+ range_set = False
+ freq_l, freq_h = start_freq, start_freq + span
+ freq_old = freq_val
+ pow_min, pow_max = 0, 0
+ i, i_last, n = 0, 0, 0
+ f = np.array([])
+ power = np.array([])
+ # Erase screen
+ screen.fill((255, 255, 255))
+ print(u"Range re-initialization", file=sys.stderr)
+
+ if freq_val < freq_old:
+ # print(u"loop back i = {:}, i_last = {:}, n = {:}".
+ # format(i, i_last, n), file=sys.stderr)
+ ping_or_pong = (ping_or_pong + 1)%2
+ i_last = i
+ i = 0
+
+ if (i < n[ping_or_pong]):
+ f[ping_or_pong][i] = freq_val
+ power[ping_or_pong][i] = pow_val
+ else:
+ f[ping_or_pong] = np.append(f[ping_or_pong], freq_val)
+ power[ping_or_pong] = np.append(power[ping_or_pong], pow_val)
+ n[ping_or_pong] += 1
+
+ i += 1
+ update = True
+ freq_old = freq_val
+ # print(u"i = {:}, i_last = {:}, n = {:}".
+ # format(i, i_last, n), file=sys.stderr)
+
+ except zmq.ZMQError:
+ continue
+
+ if update is True:
+
+ if range_set is False:
+ pow_min, pow_max = pow_val, pow_val
+ ax.set_xlim([freq_l/1e6, freq_h/1e6])
+ if in_dB is True:
+ ax.set_ylim([pow_max - 10, pow_max + 10])
+ else:
+ ax.set_ylim([pow_max/10, pow_max*10])
+ range_set = True
+ elif (pow_val < pow_min):
+ pow_min = pow_val
+ ax.set_ylim([pow_min, pow_max])
+ elif (pow_val > pow_max):
+ pow_max = pow_val
+ ax.set_ylim([pow_min, pow_max])
+
+ pong_or_ping = (ping_or_pong + 1)%2
+ surf = plot_spectrum(f[ping_or_pong]/1e6, f[pong_or_ping]/1e6,
+ power[ping_or_pong], power[pong_or_ping], i, i_last, ax, canvas)
+ screen.blit(surf, (0, 0))
+ pygame.display.update()
+ update = False
+