summaryrefslogtreecommitdiffstats
path: root/util/_UI/_web_interface
diff options
context:
space:
mode:
Diffstat (limited to 'util/_UI/_web_interface')
-rwxr-xr-xutil/_UI/_web_interface/assets/style.css215
-rwxr-xr-xutil/_UI/_web_interface/kraken_web_interface.py1916
-rw-r--r--util/_UI/_web_interface/tooltips.py210
3 files changed, 0 insertions, 2341 deletions
diff --git a/util/_UI/_web_interface/assets/style.css b/util/_UI/_web_interface/assets/style.css
deleted file mode 100755
index 1e39de9..0000000
--- a/util/_UI/_web_interface/assets/style.css
+++ /dev/null
@@ -1,215 +0,0 @@
-/*Globlal Properties*/
-/*Tags*/
-body {
- background-color: #000000;
- color:#ffffff;
- margin: 0px;
- padding: 0px;
-}
-*{
- font-size:18px;
- font-family: 'Montserrat', sans-serif;
-}
-h1{
- font-size:22px;
-}
-a{
- font-size: 22px;
-}
-input[type="checkbox"]{
- width:20px;
- height:20px;
- background:white;
- border-radius:5px;
- border:2px solid #555;
- vertical-align: text-bottom;
-}
-.Select-control {
- background-color:#000000;
-}
-.Select-value {
- background-color: rgb(255, 102, 0);
- color:#000000;
-}
-.Select-menu-outer {
- background-color: rgb(0, 0, 0);
-}
-
-input, select{
- width: 100%;
-}
-iframe{
- background-color: transparent;
- border: 0px none transparent;
- padding: 0px;
- overflow: hidden;
-}
-/*Classes*/
-.header{
- background-color: #000000;
- width: 100%;
- text-align: center;
- padding: 10px;
-}
-.header a{
- color: white;
- text-transform: uppercase;
- text-decoration: none;
- padding: 5px;
- line-height: 40px;
- border: 0.1em solid #ffffff;
- border-radius:0.05em;
- margin: 5px;
-}
-.header_active, .header a:hover{
- background-color: #ff6600c0;
-}
-.ctr_toolbar{
- background-color: #000000;
- height: 50px;
- width: 100%;
- text-align: center;
-}
-.ctr_toolbar_item {
- text-align: center;
- display : inline-block;
- position : relative;
- margin : 0 auto;
- padding : 0px;
- float : center;
-}
-.doa_check{
- text-align: left;
-}
-.btn{
- height: 40px;
- cursor: pointer;
- background-color: #141414;
- border: 0.1em solid #000000;
- border-radius:0.12em;
- color: white;
- font-size:20px;
- text-decoration: none;
- text-align: center;
- width: 100%;
- transition: all 0.2s;
-}
-.btn:hover{
- color: rgb(0, 0, 0);
- background-color: #ff6600;
-}
-.btn a{
- color: white;
- text-decoration: none;
- position: relative;
- top: 15%;
-}
-.btn_start{
- height: 40px;
- cursor: pointer;
- background-color: #02c93d;
- border: 0.1em solid #000000;
- border-radius:0.12em;
- color: rgb(0, 0, 0);
- font-size:20px;
- text-decoration: none;
- text-align: center;
- width: 100%;
- transition: all 0.2s;
-}
-.btn_start:hover{
- color: rgb(0, 0, 0);
- background-color: #ff6600;
-}
-.btn_stop{
- height: 40px;
- cursor: pointer;
- background-color: #c40404;
- border: 0.1em solid #000000;
- border-radius:0.12em;
- color: rgb(0, 0, 0);
- font-size:20px;
- text-decoration: none;
- text-align: center;
- width: 100%;
-}
-.btn_stop:hover{
- color: rgb(0, 0, 0);
- background-color: #ff6600;
-}
-.btn_save_cfg{
- height: 40px;
- cursor: pointer;
- background-color: #b5aef5;
- border: 0.1em solid #000000;
- border-radius:0.12em;
- color: rgb(0, 0, 0);
- font-size:20px;
- text-decoration: none;
- text-align: center;
- width: 100%;
-}
-.btn_save_cfg:hover{
- color: rgb(154, 233, 102);
- background-color: #ff6600;
-}
-.tooltip{
- color: rgb(0, 0, 0);
- background-color: #ffffff;
- opacity: 0.95;
- border-radius:0.2em;
- width: 300px;
-}
-.card{
- background-color: #000000;
- border: 0.1em solid #ffffff;
- border-radius:0.2em;
- width: 400px;
- max-width: 500px;
- padding: 20px;
- box-shadow: 0 6px 18px rgba(0, 0, 0, 0.46);
- margin: 10px;
- float: left;
-}
-.monitor_card{
- background-color: #000000;
- border: 0.1em solid #ffffff;
- border-radius:0.2em;
- width: 95%;
- height: 800px;
- overflow:scroll;
- box-shadow: 0 6px 18px rgba(0, 0, 0, 0.46);
- margin: auto;
- }
-
-.field{
- width: 400px;
- display: block;
- margin: 10px auto;
- padding: 0px;
-}
-.field-label{
- width: 250px;
- display: inline-block;
- vertical-align: top;
-}
-.field-body{
- width: 144px;
- display: inline-block;
-}
-
-/*Mobile Properties*/
-@media screen and (max-width: 1072px) {
- .card{
- width: calc( 100% - 30px );
- padding: 5px;
- margin: 20px auto;
- float: none;
- }
-}
-
-@media screen and (max-width: 500px) {
- .field, .field-label, .field-body, input{
- width: calc( 100% - 15px );
- }
-}
diff --git a/util/_UI/_web_interface/kraken_web_interface.py b/util/_UI/_web_interface/kraken_web_interface.py
deleted file mode 100755
index 7c1c90a..0000000
--- a/util/_UI/_web_interface/kraken_web_interface.py
+++ /dev/null
@@ -1,1916 +0,0 @@
-# KrakenSDR Signal Processor
-#
-# Copyright (C) 2018-2021 Carl Laufer, Tamás Pető
-#
-# This program 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
-# any later version.
-#
-# This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
-#
-#
-# - coding: utf-8 -*-
-
-# Import built-in modules
-import logging
-import os
-import sys
-import queue
-import time
-import subprocess
-import orjson
-# Import third-party modules
-
-#Testing dash_devices
-
-#import dash
-#from dash.dependencies import Input, Output, State
-
-#import plotly.io as pio
-#pio.renderers.default = 'iframe'
-
-import dash_core_components as dcc
-import dash_html_components as html
-
-import dash_devices as dash
-from dash_devices.dependencies import Input, Output, State
-#from dash import html
-
-
-from dash.exceptions import PreventUpdate
-from dash.dash import no_update
-import plotly.graph_objects as go
-import plotly.express as px
-import numpy as np
-from configparser import ConfigParser
-from numba import njit, jit
-
-#from waitress import serve
-#from gevent.pywsgi import WSGIServer
-
-from threading import Timer
-
-# Import Kraken SDR modules
-current_path = os.path.dirname(os.path.realpath(__file__))
-root_path = os.path.dirname(os.path.dirname(current_path))
-receiver_path = os.path.join(root_path, "_receiver")
-signal_processor_path = os.path.join(root_path, "_signal_processing")
-ui_path = os.path.join(root_path, "_UI")
-
-sys.path.insert(0, receiver_path)
-sys.path.insert(0, signal_processor_path)
-sys.path.insert(0, ui_path)
-
-daq_subsystem_path = os.path.join(
- os.path.join(os.path.dirname(root_path),
- "heimdall_daq_fw"),
- "Firmware")
-daq_preconfigs_path = os.path.join(
- os.path.join(os.path.dirname(root_path),
- "heimdall_daq_fw"),
- "config_files")
-daq_config_filename = os.path.join(daq_subsystem_path, "daq_chain_config.ini")
-daq_stop_filename = "daq_stop.sh"
-daq_start_filename = "daq_start_sm.sh"
-#daq_start_filename = "daq_synthetic_start.sh"
-sys.path.insert(0, daq_subsystem_path)
-
-import ini_checker
-import save_settings as settings
-from krakenSDR_receiver import ReceiverRTLSDR
-from krakenSDR_signal_processor import SignalProcessor
-
-import tooltips
-
-class webInterface():
-
- def __init__(self):
- self.user_interface = None
-
- logging.basicConfig(level=settings.logging_level*10)
- self.logger = logging.getLogger(__name__)
- self.logger.setLevel(settings.logging_level*10)
- self.logger.info("Inititalizing web interface ")
- if not settings.settings_found:
- self.logger.warning("Web Interface settings file is not found!")
-
- #############################################
- # Initialize and Configure Kraken modules #
- #############################################
-
- # Web interface internal
- self.disable_tooltips = settings.disable_tooltips
- self.page_update_rate = 1
- self._avg_win_size = 10
- self._update_rate_arr = None
- #self._doa_method = settings.doa_method_dict[settings.doa_method]
- #self._doa_fig_type = settings.doa_fig_type_dict[settings.doa_fig_type]
-
- self.sp_data_que = queue.Queue(1) # Que to communicate with the signal processing module
- self.rx_data_que = queue.Queue(1) # Que to communicate with the receiver modules
-
- # Instantiate and configure Kraken SDR modules
- self.module_receiver = ReceiverRTLSDR(data_que=self.rx_data_que, data_interface=settings.data_interface, logging_level=settings.logging_level*10)
- self.module_receiver.daq_center_freq = settings.center_freq*10**6
- self.module_receiver.daq_rx_gain = settings.uniform_gain
- #self.module_receiver.daq_squelch_th_dB = settings.squelch_threshold_dB
- self.module_receiver.rec_ip_addr = settings.default_ip
-
- self.module_signal_processor = SignalProcessor(data_que=self.sp_data_que, module_receiver=self.module_receiver, logging_level=settings.logging_level*10)
- #self.module_signal_processor.DOA_ant_alignment = settings.ant_arrangement
- #self.module_signal_processor.DOA_inter_elem_space = settings.ant_spacing
- self.module_signal_processor.en_PR = settings.en_pr
- self.module_signal_processor.PR_clutter_cancellation = settings.clutter_cancel_algo
- self.module_signal_processor.max_bistatic_range = settings.max_bistatic_range
- self.module_signal_processor.max_doppler = settings.max_doppler
- self.en_persist = settings.en_pr_persist
- self.pr_persist_decay = settings.pr_persist_decay
- self.pr_dynamic_range_min = settings.pr_dynrange_min
- self.pr_dynamic_range_max = settings.pr_dynrange_max
-
- #self.module_signal_processor.en_DOA_FB_avg = settings.en_fbavg
- #self.module_signal_processor.en_squelch = settings.en_squelch
- #self.config_doa_in_signal_processor()
- self.module_signal_processor.start()
-
- #############################################
- # UI Status and Config variables #
- #############################################
-
- # DAQ Subsystem status parameters
- self.daq_conn_status = 0
- self.daq_cfg_iface_status = 0 # 0- ready, 1-busy
- self.daq_restart = 0 # 1-restarting
- self.daq_update_rate = 0
- self.daq_frame_sync = 1 # Active low
- self.daq_frame_index = 0
- self.daq_frame_type = "-"
- self.daq_power_level = 0
- self.daq_sample_delay_sync = 0
- self.daq_iq_sync = 0
- self.daq_noise_source_state= 0
- self.daq_center_freq = settings.center_freq
- self.daq_adc_fs = "-"
- self.daq_fs = "-"
- self.daq_cpi = "-"
- self.daq_if_gains ="[,,,,]"
- self.en_advanced_daq_cfg = False #settings.en_advanced_daq_cfg
- self.daq_ini_cfg_params = read_config_file()
- self.active_daq_ini_cfg = self.daq_ini_cfg_params[0] #"Default" # Holds the string identifier of the actively loaded DAQ ini configuration
- self.tmp_daq_ini_cfg = "Default"
- self.daq_cfg_ini_error = ""
-
- # DSP Processing Parameters and Results
- self.spectrum = None
- #self.doa_thetas = None
- #self.doa_results = []
- #self.doa_labels = []
- #self.doas = [] # Final measured DoAs [deg]
- #self.doa_confidences = []
- #self.compass_ofset = settings.compass_offset
- self.daq_dsp_latency = 0 # [ms]
- #self.max_amplitude = 0 # Used to help setting the threshold level of the squelch
- #self.avg_powers = []
- self.logger.info("Web interface object initialized")
-
- # Passive Radar Data
- self.RD_matrix = None
-
- self.dsp_timer = None
- self.update_time = 9999
-
- self.pathname = ""
- self.reset_doa_graph_flag = False
- self.reset_spectrum_graph_flag = False
-
- #self.CAFMatrixOld = 0
- #self.en_persist = True
- #self.pr_persist_decay = 0.99
- #self.pr_dynamic_range_min = -20
- #self.pr_dynamic_range_max = 100
- self.CAFMatrixPersist = None
-
- # Basic DAQ Config
- self.decimated_bandwidth = 12.5
-
- if self.daq_ini_cfg_params is not None:
- self.logger.info("Config file found and read succesfully")
- """
- Set the number of channels in the receiver module because it is required
- to produce the initial gain configuration message (Only needed in shared-memory mode)
- """
- self.module_receiver.M = self.daq_ini_cfg_params[1]
-
- # Set initial Squelch parameters based on the content of the active config file
- #if self.daq_ini_cfg_params[5]: # Squelch is enabled
- # self.module_signal_processor.en_squelch = True
- # self.module_receiver.daq_squelch_th_dB = -80 #round(20*np.log10(self.daq_ini_cfg_params[6]),1)
- #self.module_signal_processor.squelch_threshold = self.daq_ini_cfg_params[6]
- # Note: There is no need to set the thresold in the DAQ Subsystem as it is configured from the ini-file.
- #else: # Squelch is disabled
- # self.module_signal_processor.en_squelch = False
-
-
-
- def save_configuration(self):
- data = {}
-
- # DAQ Configuration
- data["center_freq"] = self.module_receiver.daq_center_freq/10**6
- data["uniform_gain"] = self.module_receiver.daq_rx_gain
- data["data_interface"] = settings.data_interface
- data["default_ip"] = settings.default_ip
-
- # DOA Estimation
- data["en_pr"] = self.module_signal_processor.en_PR
-
- data["clutter_cancel_algo"] = self.module_signal_processor.PR_clutter_cancellation
- data["max_bistatic_range"] = self.module_signal_processor.max_bistatic_range
- data["max_doppler"] = self.module_signal_processor.max_doppler
- data["en_pr_persist"] = self.en_persist
- data["pr_persist_decay"] = self.pr_persist_decay
- data["pr_dynrange_min"] = self.pr_dynamic_range_min
- data["pr_dynrange_max"] = self.pr_dynamic_range_max
-
-
- #data["ant_arrangement"] = self.module_signal_processor.DOA_ant_alignment
- #data["ant_spacing"] = self.module_signal_processor.DOA_inter_elem_space
- #doa_method = "MUSIC"
- #for key, val in (settings.doa_method_dict).items():
- # if val == self._doa_method:
- # doa_method = key
- #data["doa_method"] = doa_method
- #data["en_fbavg"] = self.module_signal_processor.en_DOA_FB_avg
- #data["compass_offset"] = self.compass_ofset
- #doa_fig_type = "Linear plot"
- #for key, val in (settings.doa_fig_type_dict).items():
- # if val == self._doa_fig_type:
- # doa_fig_type = key
-
- #data["doa_fig_type"] = doa_fig_type
-
- # DSP misc
- #data["en_squelch"] = self.module_signal_processor.en_squelch
- #data["squelch_threshold_dB"] = self.module_receiver.daq_squelch_th_dB
-
- # Web Interface
- data["en_hw_check"] = settings.en_hw_check
- data["en_advanced_daq_cfg"] = self.en_advanced_daq_cfg
- data["logging_level"] = settings.logging_level
- data["disable_tooltips"] = settings.disable_tooltips
-
- settings.write(data)
- def start_processing(self):
- """
- Starts data processing
-
- Parameters:
- -----------
- :param: ip_addr: Ip address of the DAQ Subsystem
-
- :type ip_addr : string e.g.:"127.0.0.1"
- """
- self.logger.info("Start processing request")
- self.first_frame = 1
- #self.module_receiver.rec_ip_addr = "0.0.0.0"
- self.module_signal_processor.run_processing=True
- def stop_processing(self):
- self.module_signal_processor.run_processing=False
- while self.module_signal_processor.is_running: time.sleep(0.01) # Block until signal processor run_processing while loop ends
- def close_data_interfaces(self):
- self.module_receiver.eth_close()
- def close(self):
- pass
- """
- def config_doa_in_signal_processor(self):
- if self._doa_method == 0:
- self.module_signal_processor.en_DOA_Bartlett = True
- self.module_signal_processor.en_DOA_Capon = False
- self.module_signal_processor.en_DOA_MEM = False
- self.module_signal_processor.en_DOA_MUSIC = False
- elif self._doa_method == 1:
- self.module_signal_processor.en_DOA_Bartlett = False
- self.module_signal_processor.en_DOA_Capon = True
- self.module_signal_processor.en_DOA_MEM = False
- self.module_signal_processor.en_DOA_MUSIC = False
- elif self._doa_method == 2:
- self.module_signal_processor.en_DOA_Bartlett = False
- self.module_signal_processor.en_DOA_Capon = False
- self.module_signal_processor.en_DOA_MEM = True
- self.module_signal_processor.en_DOA_MUSIC = False
- elif self._doa_method == 3:
- self.module_signal_processor.en_DOA_Bartlett = False
- self.module_signal_processor.en_DOA_Capon = False
- self.module_signal_processor.en_DOA_MEM = False
- self.module_signal_processor.en_DOA_MUSIC = True
- """
- def config_squelch_value(self, squelch_threshold_dB):
- """
- Configures the squelch thresold both on the DAQ side and
- on the local DoA DSP side.
- """
- #NOT USING THIS ANYMORE
- self.daq_cfg_iface_status = 1
- #self.module_signal_processor.squelch_threshold = 10**(squelch_threshold_dB/20)
- #self.module_receiver.set_squelch_threshold(squelch_threshold_dB)
- #webInterface_inst.logger.info("Updating receiver parameters")
- #webInterface_inst.logger.info("Squelch threshold : {:f} dB".format(squelch_threshold_dB))
- def config_daq_rf(self, f0, gain):
- """
- Configures the RF parameters in the DAQ module
- """
- self.daq_cfg_iface_status = 1
- self.module_receiver.set_center_freq(int(f0*10**6))
- self.module_receiver.set_if_gain(gain)
-
- webInterface_inst.logger.info("Updating receiver parameters")
- webInterface_inst.logger.info("Center frequency: {:f} MHz".format(f0))
- webInterface_inst.logger.info("Gain: {:f} dB".format(gain))
-
-
-
-
-def read_config_file(config_fname=daq_config_filename):
- parser = ConfigParser()
- found = parser.read([config_fname])
- param_list = []
- if not found:
- return None
- param_list.append(parser.get('meta', 'config_name'))
-
- param_list.append(parser.getint('hw', 'num_ch'))
-
- param_list.append(parser.getint('daq','daq_buffer_size'))
- param_list.append(parser.getint('daq','sample_rate'))
- param_list.append(parser.getint('daq','en_noise_source_ctr'))
-
- param_list.append(parser.getint('squelch','en_squelch'))
- param_list.append(parser.getfloat('squelch','amplitude_threshold'))
-
- param_list.append(parser.getint('pre_processing', 'cpi_size'))
- param_list.append(parser.getint('pre_processing', 'decimation_ratio'))
- param_list.append(parser.getfloat('pre_processing', 'fir_relative_bandwidth'))
- param_list.append(parser.getint('pre_processing', 'fir_tap_size'))
- param_list.append(parser.get('pre_processing','fir_window'))
- param_list.append(parser.getint('pre_processing','en_filter_reset'))
-
- param_list.append(parser.getint('calibration','corr_size'))
- param_list.append(parser.getint('calibration','std_ch_ind'))
- param_list.append(parser.getint('calibration','en_iq_cal'))
- param_list.append(parser.getint('calibration','gain_lock_interval'))
- param_list.append(parser.getint('calibration','require_track_lock_intervention'))
- param_list.append(parser.getint('calibration','cal_track_mode'))
- param_list.append(parser.get('calibration','amplitude_cal_mode'))
- param_list.append(parser.getint('calibration','cal_frame_interval'))
- param_list.append(parser.getint('calibration','cal_frame_burst_size'))
- param_list.append(parser.getint('calibration','amplitude_tolerance'))
- param_list.append(parser.getint('calibration','phase_tolerance'))
- param_list.append(parser.getint('calibration','maximum_sync_fails'))
-
- param_list.append(parser.get('data_interface','out_data_iface_type'))
-
- return param_list
-
-def write_config_file(param_list):
- webInterface_inst.logger.info("Write config file: {0}".format(param_list))
- parser = ConfigParser()
- found = parser.read([daq_config_filename])
- if not found:
- return -1
-
- parser['meta']['config_name']=str(param_list[0])
-
- parser['hw']['num_ch']=str(param_list[1])
-
- parser['daq']['daq_buffer_size']=str(param_list[2])
- parser['daq']['sample_rate']=str(param_list[3])
- parser['daq']['en_noise_source_ctr']=str(param_list[4])
-
- parser['squelch']['en_squelch']=str(param_list[5])
- parser['squelch']['amplitude_threshold']=str(param_list[6])
-
- parser['pre_processing']['cpi_size']=str(param_list[7])
- parser['pre_processing']['decimation_ratio']=str(param_list[8])
- parser['pre_processing']['fir_relative_bandwidth']=str(param_list[9])
- parser['pre_processing']['fir_tap_size']=str(param_list[10])
- parser['pre_processing']['fir_window']=str(param_list[11])
- parser['pre_processing']['en_filter_reset']=str(param_list[12])
-
- parser['calibration']['corr_size']=str(param_list[13])
- parser['calibration']['std_ch_ind']=str(param_list[14])
- parser['calibration']['en_iq_cal']=str(param_list[15])
- parser['calibration']['gain_lock_interval']=str(param_list[16])
- parser['calibration']['require_track_lock_intervention']=str(param_list[17])
- parser['calibration']['cal_track_mode']=str(param_list[18])
- parser['calibration']['amplitude_cal_mode']=str(param_list[19])
- parser['calibration']['cal_frame_interval']=str(param_list[20])
- parser['calibration']['cal_frame_burst_size']=str(param_list[21])
- parser['calibration']['amplitude_tolerance']=str(param_list[22])
- parser['calibration']['phase_tolerance']=str(param_list[23])
- parser['calibration']['maximum_sync_fails']=str(param_list[24])
-
- ini_parameters = parser._sections
- error_list = ini_checker.check_ini(ini_parameters, settings.en_hw_check)
- if len(error_list):
- for e in error_list:
- webInterface_inst.logger.error(e)
- return -1, error_list
- else:
- with open(daq_config_filename, 'w') as configfile:
- parser.write(configfile)
- return 0,[]
-
-def get_preconfigs(config_files_path):
- parser = ConfigParser()
- preconfigs = []
- preconfigs.append([daq_config_filename, "Current"])
- for root, dirs, files in os.walk(config_files_path):
- if len(files):
- config_file_path = os.path.join(root, files[0])
- parser.read([config_file_path])
- parameters = parser._sections
- preconfigs.append([config_file_path, parameters['meta']['config_name']])
- return preconfigs
-
-
-#############################################
-# Prepare Dash application #
-############################################
-webInterface_inst = webInterface()
-
-
-#############################################
-# Prepare component dependencies #
-#############################################
-
-trace_colors = px.colors.qualitative.Plotly
-trace_colors[3] = 'rgb(255,255,51)'
-valid_fir_windows = ['boxcar', 'triang', 'blackman', 'hamming', 'hann', 'bartlett', 'flattop', 'parzen' , 'bohman', 'blackmanharris', 'nuttall', 'barthann']
-valid_sample_rates = [0.25, 0.900001, 1.024, 1.4, 1.8, 1.92, 2.048, 2.4, 2.56, 3.2]
-valid_daq_buffer_sizes = (2**np.arange(10,21,1)).tolist()
-calibration_tack_modes = [['No tracking',0] , ['Periodic tracking',2]]
-doa_trace_colors = {
- "DoA Bartlett": "#00B5F7",
- "DoA Capon" : "rgb(226,26,28)",
- "DoA MEM" : "#1CA71C",
- "DoA MUSIC" : "rgb(257,233,111)"
-}
-figure_font_size = 20
-
-y=np.random.normal(0,1,2**3)
-x=np.arange(2**3)
-
-fig_layout = go.Layout(
- paper_bgcolor='rgba(0,0,0,0)',
- plot_bgcolor='rgba(0,0,0,0)',
- template='plotly_dark',
- showlegend=True,
- margin=go.layout.Margin(
- t=0 #top margin
- )
- )
-
-fig_dummy = go.Figure(layout=fig_layout)
-#fig_dummy.add_trace(go.Scatter(x=x, y=y, name = "Avg spectrum"))
-
-for m in range(0, webInterface_inst.module_receiver.M+1): #+1 for the auto decimation window selection
- fig_dummy.add_trace(go.Scatter(x=x,
- y=y,
- name="Channel {:d}".format(m),
- line = dict(color = trace_colors[m],
- width = 2)
- ))
-
-
-fig_dummy.update_xaxes(title_text="Frequency [MHz]")
-fig_dummy.update_yaxes(title_text="Amplitude [dB]")
-
-option = [{"label":"", "value": 1}]
-
-spectrum_fig = go.Figure(layout=fig_layout)
-
-for m in range(0, webInterface_inst.module_receiver.M+1): #+1 for the auto decimation window selection
- spectrum_fig.add_trace(go.Scattergl(x=x,
- y=y,
- name="Channel {:d}".format(m),
- line = dict(color = trace_colors[m],
- width = 2)
- ))
-
-
-#waterfall_fig = go.Figure(layout=fig_layout)
-#waterfall_fig.add_trace(go.Heatmapgl(
-# z=waterfall_init))
-# z=[[1,2,3,4,5]]))
-
-
-waterfall_init = [[-80] * webInterface_inst.module_signal_processor.spectrum_window_size] * 50
-waterfall_fig = go.Figure(layout=fig_layout)
-waterfall_fig.add_trace(go.Heatmapgl(
- z=waterfall_init,
- zsmooth=False,
- showscale=False,
- hoverinfo='skip',
- colorscale=[[0.0, '#000020'],
- [0.0714, '#000030'],
- [0.1428, '#000050'],
- [0.2142, '#000091'],
- [0.2856, '#1E90FF'],
- [0.357, '#FFFFFF'],
- [0.4284, '#FFFF00'],
- [0.4998, '#FE6D16'],
- [0.5712, '#FE6D16'],
- [0.6426, '#FF0000'],
- [0.714, '#FF0000'],
- [0.7854, '#C60000'],
- [0.8568, '#9F0000'],
- [0.9282, '#750000'],
- [1.0, '#4A0000']]))
-
-
-waterfall_fig.update_xaxes(tickfont_size=1)
-waterfall_fig.update_yaxes(tickfont_size=1)
-waterfall_fig.update_layout(margin=go.layout.Margin(t=5))
-
-
-
-pr_init = [[-80] * 128] * 128
-pr_fig = go.Figure(layout=fig_layout)
-pr_fig.add_trace(go.Heatmap(
- z=pr_init,
- zsmooth='best', #False,
- #zsmooth=False, #False,
- showscale=False,
- #hoverinfo='skip',
- colorscale=[[0.0, '#000020'],
- [0.0714, '#000030'],
- [0.1428, '#000050'],
- [0.2142, '#000091'],
- [0.2856, '#1E90FF'],
- [0.357, '#FFFFFF'],
- [0.4284, '#FFFF00'],
- [0.4998, '#FE6D16'],
- [0.5712, '#FE6D16'],
- [0.6426, '#FF0000'],
- [0.714, '#FF0000'],
- [0.7854, '#C60000'],
- [0.8568, '#9F0000'],
- [0.9282, '#750000'],
- [1.0, '#4A0000']]))
-
-
-
-#app = dash.Dash(__name__, suppress_callback_exceptions=True, compress=True, update_title="") # cannot use update_title with dash_devices
-app = dash.Dash(__name__, suppress_callback_exceptions=True, compress=False)
-
-# app_log = logger.getLogger('werkzeug')
-# app_log.setLevel(settings.logging_level*10)
-# app_log.setLevel(30) # TODO: Only during dev time
-app.layout = html.Div([
- dcc.Location(id='url', children='/config',refresh=False),
-
- html.Div([html.H1('KrakenSDR - Passive Radar')], style={"text-align": "center"}, className="main_title"),
- html.Div([html.A("Configuration", className="header_active" , id="header_config" ,href="/config"),
- html.A("Spectrum" , className="header_inactive" , id="header_spectrum",href="/spectrum"),
- html.A("Passive Radar" , className="header_inactive" , id="header_doa" ,href="/pr"),
- ], className="header"),
- html.Div([html.Div([html.Button('Start Processing', id='btn-start_proc', className="btn_start", n_clicks=0)], className="ctr_toolbar_item"),
- html.Div([html.Button('Stop Processing', id='btn-stop_proc', className="btn_stop", n_clicks=0)], className="ctr_toolbar_item"),
- html.Div([html.Button('Save Configuration', id='btn-save_cfg', className="btn_save_cfg", n_clicks=0)], className="ctr_toolbar_item")
- ], className="ctr_toolbar"),
-
- dcc.Interval(
- id="mem_leak_refresh_interval",
- interval= 300 * 1000, # Every 5mins TEST
- ),
-
-
- #dcc.Interval(
- # id='interval-component',
- # interval=500, # in milliseconds
- # n_intervals=0
- #),
- html.Div(id="placeholder_start" , style={"display":"none"}),
- html.Div(id="placeholder_stop" , style={"display":"none"}),
- html.Div(id="placeholder_save" , style={"display":"none"}),
- html.Div(id="placeholder_update_rx" , style={"display":"none"}),
- html.Div(id="placeholder_recofnig_daq" , style={"display":"none"}),
- html.Div(id="placeholder_update_daq_ini_params", style={"display":"none"}),
- html.Div(id="placeholder_update_freq" , style={"display":"none"}),
- html.Div(id="placeholder_update_dsp" , style={"display":"none"}),
- html.Div(id="placeholder_update_squelch" , style={"display":"none"}),
- html.Div(id="placeholder_config_page_upd" , style={"display":"none"}),
- html.Div(id="placeholder_spectrum_page_upd" , style={"display":"none"}),
- html.Div(id="placeholder_doa_page_upd" , style={"display":"none"}),
- html.Div(id="dummy_output" , style={"display":"none"}),
-
- html.Div(id='page-content')
-])
-def generate_config_page_layout(webInterface_inst):
- # Read DAQ config file
- daq_cfg_params = webInterface_inst.daq_ini_cfg_params
-
- if daq_cfg_params is not None:
- en_noise_src_values =[1] if daq_cfg_params[4] else []
- en_squelch_values =[1] if daq_cfg_params[5] else []
- en_filter_rst_values =[1] if daq_cfg_params[12] else []
- en_iq_cal_values =[1] if daq_cfg_params[15] else []
- en_req_track_lock_values =[1] if daq_cfg_params[17] else []
-
- #daq_data_iface_type = daq_cfg_params[25]
-
- # Read available preconfig files
- preconfigs = get_preconfigs(daq_preconfigs_path)
-
- en_persist_values =[1] if webInterface_inst.en_persist else []
- en_pr_values =[1] if webInterface_inst.module_signal_processor.en_PR else []
- #en_fb_avg_values =[1] if webInterface_inst.module_signal_processor.en_DOA_FB_avg else []
- #en_dsp_squelch_values =[1] if webInterface_inst.module_signal_processor.en_squelch else []
-
- en_advanced_daq_cfg =[1] if webInterface_inst.en_advanced_daq_cfg else []
- # Calulcate spacings
- wavelength= 300 / webInterface_inst.daq_center_freq
-
- ant_spacing_wavelength = webInterface_inst.module_signal_processor.DOA_inter_elem_space
- ant_spacing_meter = round(wavelength * ant_spacing_wavelength, 3)
- ant_spacing_feet = ant_spacing_meter*3.2808399
- ant_spacing_inch = ant_spacing_meter*39.3700787
-
- cfg_decimated_bw = ((daq_cfg_params[3]) / daq_cfg_params[8]) / 10**3
- cfg_data_block_len = ( daq_cfg_params[7] / (cfg_decimated_bw) )
- cfg_recal_interval = (daq_cfg_params[20] * (cfg_data_block_len/10**3)) / 60
-
- if daq_cfg_params[18] == 0: #If set to no tracking
- cfg_recal_interval = 1
-
-
- #for preconfig in preconfigs:
- # print(preconfig[0])
-
- #-----------------------------
- # DAQ Configuration Card
- #-----------------------------
- # -- > Main Card Layout < --
- daq_config_card_list = \
- [
- html.H2("RF Receiver Configuration", id="init_title_c"),
- html.Div([
- html.Div("Center Frequency [MHz]", className="field-label"),
- dcc.Input(id='daq_center_freq', value=webInterface_inst.module_receiver.daq_center_freq/10**6, type='number', debounce=True, className="field-body")
- ], className="field"),
- html.Div([
- html.Div("Receiver gain", className="field-label"),
- dcc.Dropdown(id='daq_rx_gain',
- options=[
- {'label': '0 dB', 'value': 0},
- {'label': '0.9 dB', 'value': 0.9},
- {'label': '1.4 dB', 'value': 1.4},
- {'label': '2.7 dB', 'value': 2.7},
- {'label': '3.7 dB', 'value': 3.7},
- {'label': '7.7 dB', 'value': 7.7},
- {'label': '8.7 dB', 'value': 8.7},
- {'label': '12.5 dB', 'value': 12.5},
- {'label': '14.4 dB', 'value': 14.4},
- {'label': '15.7 dB', 'value': 15.7},
- {'label': '16.6 dB', 'value': 16.6},
- {'label': '19.7 dB', 'value': 19.7},
- {'label': '20.7 dB', 'value': 20.7},
- {'label': '22.9 dB', 'value': 22.9},
- {'label': '25.4 dB', 'value': 25.4},
- {'label': '28.0 dB', 'value': 28.0},
- {'label': '29.7 dB', 'value': 29.7},
- {'label': '32.8 dB', 'value': 32.8},
- {'label': '33.8 dB', 'value': 33.8},
- {'label': '36.4 dB', 'value': 36.4},
- {'label': '37.2 dB', 'value': 37.2},
- {'label': '38.6 dB', 'value': 38.6},
- {'label': '40.2 dB', 'value': 40.2},
- {'label': '42.1 dB', 'value': 42.1},
- {'label': '43.4 dB', 'value': 43.4},
- {'label': '43.9 dB', 'value': 43.9},
- {'label': '44.5 dB', 'value': 44.5},
- {'label': '48.0 dB', 'value': 48.0},
- {'label': '49.6 dB', 'value': 49.6},
- ],
- value=webInterface_inst.module_receiver.daq_rx_gain, clearable=False, className="field-body"),
- ], className="field"),
- html.Div([
- html.Button('Update Receiver Parameters', id='btn-update_rx_param', className="btn"),
- ], className="field"),
-
-
- html.Div([
- html.Div("Preconfigured DAQ Files", className="field-label"),
- dcc.Dropdown(id='daq_cfg_files',
- options=[
- {'label': str(i[1]), 'value': i[0]} for i in preconfigs
- ],
- clearable=False,
- value=preconfigs[0][0],
- placeholder="Select Configuration File",
- persistence=True,
- style={"display":"inline-block", "width": "400px"},
- className="field-body"),
- ], className="field"),
- html.Div([
- html.Div("Active Configuration: " + webInterface_inst.active_daq_ini_cfg, id="active_daq_ini_cfg", className="field-label"),
- ], className="field"),
- html.Div([
- html.Div(webInterface_inst.daq_cfg_ini_error , id="daq_ini_check", className="field-label", style={"color":"red"}),
- ], className="field"),
-
- html.Div([html.Div("Basic Custom DAQ Configuration", id="label_en_basic_daq_cfg" , className="field-label")]),
- html.Div([
- html.Div("Data Block Length (ms):", className="field-label"),
- dcc.Input(id='cfg_data_block_len', value=cfg_data_block_len, type='number', debounce=True, className="field-body")
- ], className="field"),
- html.Div([
- html.Div("Decimated Bandwidth (kHz):", className="field-label"),
- dcc.Input(id='cfg_decimated_bw', value=cfg_decimated_bw, type='number', debounce=True, className="field-body")
- ], className="field"),
- html.Div([
- html.Div("Recalibration Interval (mins):", className="field-label"),
- dcc.Input(id='cfg_recal_interval', value=cfg_recal_interval, type='number', debounce=True, className="field-body")
- ], className="field"),
-
- html.Div([html.Div("Advanced Custom DAQ Configuration", id="label_en_advanced_daq_cfg" , className="field-label"),
- dcc.Checklist(options=option , id="en_advanced_daq_cfg" , className="field-body", value=en_advanced_daq_cfg),
- ], className="field"),
- ]
-
- # --> Optional DAQ Subsystem reconfiguration fields <--
- #if len(en_advanced_daq_cfg):
- # if daq_cfg_params is not None:
- daq_subsystem_reconfiguration_options = [ \
- html.Div([
-
- html.H2("DAQ Subsystem Reconfiguration", id="init_title_reconfig"),
- html.H3("HW", id="cfg_group_hw"),
- html.Div([
- html.Div("# RX Channels:", className="field-label"),
- dcc.Input(id='cfg_rx_channels', value=daq_cfg_params[1], type='number', debounce=True, className="field-body")
- ], className="field"),
- html.H3("DAQ", id="cfg_group_daq"),
- html.Div([
- html.Div("DAQ Buffer Size:", className="field-label", id="label_daq_buffer_size"),
- dcc.Dropdown(id='cfg_daq_buffer_size',
- options=[
- {'label': i, 'value': i} for i in valid_daq_buffer_sizes
- ],
- value=daq_cfg_params[2], style={"display":"inline-block"},className="field-body"),
- ], className="field"),
- html.Div([
- html.Div("Sample Rate [MHz]:", className="field-label", id="label_sample_rate"),
- dcc.Dropdown(id='cfg_sample_rate',
- options=[
- {'label': i, 'value': i} for i in valid_sample_rates
- ],
- value=daq_cfg_params[3]/10**6, style={"display":"inline-block"},className="field-body")
- ], className="field"),
- html.Div([
- html.Div("Enable Noise Source Control:", className="field-label", id="label_en_noise_source_ctr"),
- dcc.Checklist(options=option , id="en_noise_source_ctr" , className="field-body", value=en_noise_src_values),
- ], className="field"),
- html.H3("Squelch"),
- html.Div([
- html.Div("Enable DAQ Squelch (NOT ACTIVE):", className="field-label", id="label_en_squelch"),
- dcc.Checklist(options=option , id="en_squelch_mode" , className="field-body", value=en_squelch_values),
- ], className="field"),
- html.Div([
- html.Div("Initial Threshold:", className="field-label", id="label_squelch_init_threshold"),
- dcc.Input(id='cfg_squelch_init_th', value=daq_cfg_params[6], type='number', debounce=True, className="field-body")
- ], className="field"),
- html.H3("Pre Processing"),
- html.Div([
- html.Div("CPI Size [sample]:", className="field-label", id="label_cpi_size"),
- dcc.Input(id='cfg_cpi_size', value=daq_cfg_params[7], type='number', debounce=True, className="field-body")
- ], className="field"),
- html.Div([
- html.Div("Decimation Ratio:", className="field-label", id="label_decimation_ratio"),
- dcc.Input(id='cfg_decimation_ratio', value=daq_cfg_params[8], type='number', debounce=True, className="field-body")
- ], className="field"),
- html.Div([
- html.Div("FIR Relative Bandwidth:", className="field-label", id="label_fir_relative_bw"),
- dcc.Input(id='cfg_fir_bw', value=daq_cfg_params[9], type='number', debounce=True, className="field-body")
- ], className="field"),
- html.Div([
- html.Div("FIR Tap Size:", className="field-label", id="label_fir_tap_size"),
- dcc.Input(id='cfg_fir_tap_size', value=daq_cfg_params[10], type='number', debounce=True, className="field-body")
- ], className="field"),
- html.Div([
- html.Div("FIR Window:", className="field-label", id="label_fir_window"),
- dcc.Dropdown(id='cfg_fir_window',
- options=[
- {'label': i, 'value': i} for i in valid_fir_windows
- ],
- value=daq_cfg_params[11], style={"display":"inline-block"},className="field-body")
- ], className="field"),
- html.Div([
- html.Div("Enable Filter Reset:", className="field-label", id="label_en_filter_reset"),
- dcc.Checklist(options=option , id="en_filter_reset" , className="field-body", value=en_filter_rst_values),
- ], className="field"),
- html.H3("Calibration"),
- html.Div([
- html.Div("Correlation Size [sample]:", className="field-label", id="label_correlation_size"),
- dcc.Input(id='cfg_corr_size', value=daq_cfg_params[13], type='number', debounce=True, className="field-body")
- ], className="field"),
- html.Div([
- html.Div("Standard Channel Index:", className="field-label", id="label_std_ch_index"),
- dcc.Input(id='cfg_std_ch_ind', value=daq_cfg_params[14], type='number', debounce=True, className="field-body")
- ], className="field"),
- html.Div([
- html.Div("Enable IQ Calibration:", className="field-label", id="label_en_iq_calibration"),
- dcc.Checklist(options=option , id="en_iq_cal" , className="field-body", value=en_iq_cal_values),
- ], className="field"),
- html.Div([
- html.Div("Gain Lock Interval [frame]:", className="field-label", id="label_gain_lock_interval"),
- dcc.Input(id='cfg_gain_lock', value=daq_cfg_params[16], type='number', debounce=True, className="field-body")
- ], className="field"),
- html.Div([
- html.Div("Require Track Lock Intervention (For Kerberos):", className="field-label", id="label_require_track_lock"),
- dcc.Checklist(options=option , id="en_req_track_lock_intervention" , className="field-body", value=en_req_track_lock_values),
- ], className="field"),
- html.Div([
- html.Div("Calibration Track Mode:", className="field-label", id="label_calibration_track_mode"),
- dcc.Dropdown(id='cfg_cal_track_mode',
- options=[
- {'label': i[0], 'value': i[1]} for i in calibration_tack_modes
- ],
- value=daq_cfg_params[18], style={"display":"inline-block"},className="field-body"),
- ], className="field"),
- html.Div([
- html.Div("Amplitude Calibration Mode :", className="field-label", id="label_amplitude_calibration_mode"),
- dcc.Dropdown(id='cfg_amplitude_cal_mode',
- options=[
- {'label': 'default', 'value': 'default'},
- {'label': 'disabled', 'value': 'disabled'},
- {'label': 'channel_power', 'value': 'channel_power'}
- ],
- value=daq_cfg_params[19], style={"display":"inline-block"},className="field-body"),
- ], className="field"),
- html.Div([
- html.Div("Calibration Frame Interval:", className="field-label", id="label_calibration_frame_interval"),
- dcc.Input(id='cfg_cal_frame_interval', value=daq_cfg_params[20], type='number', debounce=True, className="field-body")
- ], className="field"),
- html.Div([
- html.Div("Calibration Frame Burst Size:", className="field-label", id="label_calibration_frame_burst_size"),
- dcc.Input(id='cfg_cal_frame_burst_size', value=daq_cfg_params[21], type='number', debounce=True, className="field-body")
- ], className="field"),
- html.Div([
- html.Div("Amplitude Tolerance [dB]:", className="field-label", id="label_amplitude_tolerance"),
- dcc.Input(id='cfg_amplitude_tolerance', value=daq_cfg_params[22], type='number', debounce=True, className="field-body")
- ], className="field"),
- html.Div([
- html.Div("Phase Tolerance [deg]:", className="field-label", id="label_phase_tolerance"),
- dcc.Input(id='cfg_phase_tolerance', value=daq_cfg_params[23], type='number', debounce=True, className="field-body")
- ], className="field"),
- html.Div([
- html.Div("Maximum Sync Fails:", className="field-label", id="label_max_sync_fails"),
- dcc.Input(id='cfg_max_sync_fails', value=daq_cfg_params[24], type='number', debounce=True, className="field-body")
- ], className="field"),
- ], style={'width': '100%'}, id='adv-cfg-container'),
-
- # Reconfigure Button
- html.Div([
- html.Button('Reconfigure & Restart DAQ chain', id='btn_reconfig_daq_chain', className="btn"),
- ], className="field"),
- ]
- for i in range(len(daq_subsystem_reconfiguration_options)):
- daq_config_card_list.append(daq_subsystem_reconfiguration_options[i])
- #else:
- # daq_config_card_list.append(html.H2("DAQ Subsystem Reconfiguration", id="init_title_reconfig"))
- # daq_config_card_list.append(html.Div("Config file not found! Reconfiguration is not possible !", id="daq_reconfig_note", className="field", style={"color":"red"}))
-
- daq_config_card = html.Div(daq_config_card_list, className="card")
- #-----------------------------
- # DAQ Status Card
- #-----------------------------
- daq_status_card = \
- html.Div([
- html.H2("DAQ Subsystem Status", id="init_title_s"),
- html.Div([html.Div("Update rate:" , id="label_daq_update_rate" , className="field-label"), html.Div("- ms" , id="body_daq_update_rate" , className="field-body")], className="field"),
- html.Div([html.Div("Latency:" , id="label_daq_dsp_latency" , className="field-label"), html.Div("- ms" , id="body_daq_dsp_latency" , className="field-body")], className="field"),
- html.Div([html.Div("Frame index:" , id="label_daq_frame_index" , className="field-label"), html.Div("-" , id="body_daq_frame_index" , className="field-body")], className="field"),
- html.Div([html.Div("Frame type:" , id="label_daq_frame_type" , className="field-label"), html.Div("-" , id="body_daq_frame_type" , className="field-body")], className="field"),
- html.Div([html.Div("Frame sync:" , id="label_daq_frame_sync" , className="field-label"), html.Div("LOSS" , id="body_daq_frame_sync" , className="field-body", style={"color": "red"})], className="field"),
- html.Div([html.Div("Power level:" , id="label_daq_power_level" , className="field-label"), html.Div("-" , id="body_daq_power_level" , className="field-body")], className="field"),
- html.Div([html.Div("Connection status:" , id="label_daq_conn_status" , className="field-label"), html.Div("Disconnected", id="body_daq_conn_status" , className="field-body", style={"color": "red"})], className="field"),
- html.Div([html.Div("Sample delay snyc:" , id="label_daq_delay_sync" , className="field-label"), html.Div("LOSS" , id="body_daq_delay_sync" , className="field-body", style={"color": "red"})], className="field"),
- html.Div([html.Div("IQ snyc:" , id="label_daq_iq_sync" , className="field-label"), html.Div("LOSS" , id="body_daq_iq_sync" , className="field-body", style={"color": "red"})], className="field"),
- html.Div([html.Div("Noise source state:" , id="label_daq_noise_source" , className="field-label"), html.Div("Disabled" , id="body_daq_noise_source" , className="field-body", style={"color": "green"})], className="field"),
- html.Div([html.Div("RF center frequecy [MHz]:" , id="label_daq_rf_center_freq", className="field-label"), html.Div("- MHz" , id="body_daq_rf_center_freq", className="field-body")], className="field"),
- html.Div([html.Div("Sampling frequency [MHz]:" , id="label_daq_sampling_freq" , className="field-label"), html.Div("- MHz" , id="body_daq_sampling_freq" , className="field-body")], className="field"),
- html.Div([html.Div("Data block length [ms]:" , id="label_daq_cpi" , className="field-label"), html.Div("- ms" , id="body_daq_cpi" , className="field-body")], className="field"),
- html.Div([html.Div("IF gains [dB]:" , id="label_daq_if_gain" , className="field-label"), html.Div("[,] dB" , id="body_daq_if_gain" , className="field-body")], className="field"),
- #html.Div([html.Div("Avg. powers [dB]:" , id="label_avg_powers" , className="field-label"), html.Div("[,] dB" , id="body_avg_powers" , className="field-body")], className="field"),
- ], className="card")
-
- #-----------------------------
- # DSP Confugartion Card
- #-----------------------------
-
- dsp_config_card = \
- html.Div([
- html.H2("Passive Radar Configuration", id="init_title_d"),
- html.Div([html.Div("Enable Passive Radar", id="label_en_pr" , className="field-label"),
- dcc.Checklist(options=option , id="en_pr_check" , className="field-body", value=en_pr_values),
- ], className="field"),
-
- html.Div([html.Div("Clutter Cancellation:" , id="label_clutter_cancellation" , className="field-label"),
- dcc.Dropdown(id='clutter_cancel_algo',
- options=[
- {'label': 'OFF', 'value': "OFF"},
- {'label': 'Wiener MRE' , 'value': "Wiener MRE"},
- ],
- value=webInterface_inst.module_signal_processor.PR_clutter_cancellation, style={"display":"inline-block"},className="field-body")
- ], className="field"),
-
- html.Div([html.Div("Max Bistatic Range [km]:" , id="label_max_bistatic_range" , className="field-label"),
- dcc.Dropdown(id='max_bistatic_range',
- options=[
- {'label': '16', 'value': 16},
- {'label': '32' , 'value': 32},
- {'label': '64' , 'value': 64},
- {'label': '128' , 'value': 128},
- {'label': '256' , 'value': 256},
- {'label': '512' , 'value': 512},
- {'label': '1024' , 'value': 1024},
- ],
- value=webInterface_inst.module_signal_processor.max_bistatic_range, style={"display":"inline-block"},className="field-body")
- ], className="field"),
-
- html.Div([html.Div("Max Doppler [Hz]:" , id="label_max_doppler" ,style={"display":"inline-block"}, className="field-label"),
- dcc.Input(id="max_doppler", value=webInterface_inst.module_signal_processor.max_doppler, type='number', style={"display":"inline-block", "float":"right", "padding-left":0}, debounce=True, className="field-body")
- ], style={'display':'inline-block'}, className="field"),
-
- html.Div([html.Div("PR Persist", id="label_en_persist" , className="field-label"),
- dcc.Checklist(options=option , id="en_persist_check" , className="field-body", value=en_persist_values),
- ], className="field"),
-
- html.Div([html.Div("Persist Decay:" , id="label_persist_decay" ,style={"display":"inline-block"}, className="field-label"),
- dcc.Input(id="persist_decay", value=webInterface_inst.pr_persist_decay, type='number', style={"display":"inline-block", "float":"right", "padding-left":0}, debounce=True, className="field-body")
- ], style={'display':'inline-block'}, className="field"),
-
-
- html.Div([html.Div("Dynamic Range (Min):" , id="label_dynrange_min" ,style={"display":"inline-block"}, className="field-label"),
- dcc.Input(id="dynrange_min", value=webInterface_inst.pr_dynamic_range_min, type='number', style={"display":"inline-block", "float":"right", "padding-left":0}, debounce=True, className="field-body")
- ], style={'display':'inline-block'}, className="field"),
-
- html.Div([html.Div("Dynamic Range (Max):" , id="label_dynrange_max" ,style={"display":"inline-block"}, className="field-label"),
- dcc.Input(id="dynrange_max", value=webInterface_inst.pr_dynamic_range_max, type='number', style={"display":"inline-block", "float":"right", "padding-left":0}, debounce=True, className="field-body")
- ], style={'display':'inline-block'}, className="field"),
-
-
-
-
- ], className="card")
-
- #-----------------------------
- # Display Options Card
- #-----------------------------
- #config_page_component_list = [daq_config_card, daq_status_card, dsp_config_card, display_options_card,squelch_card]
- config_page_component_list = [daq_config_card, daq_status_card, dsp_config_card]
-
- if not webInterface_inst.disable_tooltips:
- config_page_component_list.append(tooltips.dsp_config_tooltips)
- #if len(en_advanced_daq_cfg):
- #if daq_cfg_params is not None:
- config_page_component_list.append(tooltips.daq_ini_config_tooltips)
-
- return html.Div(children=config_page_component_list)
-
-
-spectrum_page_layout = html.Div([
- html.Div([
- dcc.Store(id="spectrum-store"),
- dcc.Graph(
- id="spectrum-graph",
- style={'width': '100%', 'height': '45%'},
- figure=fig_dummy #spectrum_fig #fig_dummy #spectrum_fig #fig_dummy
- ),
- dcc.Graph(
- id="waterfall-graph",
- style={'width': '93.5%', 'height': '60%'},
- figure=waterfall_fig #waterfall fig remains unchanged always due to slow speed to update entire graph #fig_dummy #spectrum_fig #fig_dummy
- ),
-], className="monitor_card"),
-
-
- #html.Div([
- #dcc.Graph(
- # style={"height": "inherit"},
- # id="waterfall-graph",
- # figure=fig_dummy #spectrum_fig #fig_dummy
- #)], className="monitor_card"),
-
-
-
-])
-def generate_pr_page_layout(webInterface_inst):
- pr_page_layout = html.Div([
- html.Div([
- #dcc.Graph(id='doa-graph-test', figure=doa_fig),
- dcc.Store(id='pr-store', data=[]),
- dcc.Graph(
- style={"height": "inherit"},
- id="pr-graph",
- figure=pr_fig, #fig_dummy #doa_fig #fig_dummy
- )], className="monitor_card"),
- ])
- return pr_page_layout
-
-#============================================
-# CALLBACK FUNCTIONS
-#============================================
-@app.callback_connect
-def func(client, connect):
- #print(client, connect, len(app.clients))
- if connect and len(app.clients)==1:
- fetch_dsp_data()
- elif not connect and len(app.clients)==0:
- webInterface_inst.dsp_timer.cancel()
-
-def fetch_dsp_data():
- daq_status_update_flag = 0
- spectrum_update_flag = 0
- doa_update_flag = 0
- freq_update = no_update
- #############################################
- # Fetch new data from back-end ques #
- #############################################
- try:
- # Fetch new data from the receiver module
- que_data_packet = webInterface_inst.rx_data_que.get(False)
- for data_entry in que_data_packet:
- if data_entry[0] == "conn-ok":
- webInterface_inst.daq_conn_status = 1
- daq_status_update_flag = 1
- elif data_entry[0] == "disconn-ok":
- webInterface_inst.daq_conn_status = 0
- daq_status_update_flag = 1
- elif data_entry[0] == "config-ok":
- webInterface_inst.daq_cfg_iface_status = 0
- daq_status_update_flag = 1
- except queue.Empty:
- # Handle empty queue here
- webInterface_inst.logger.debug("Receiver module que is empty")
- else:
- pass
- # Handle task here and call q.task_done()
- if webInterface_inst.daq_restart: # Set by the restarting script
- daq_status_update_flag = 1
- try:
- # Fetch new data from the signal processing module
- que_data_packet = webInterface_inst.sp_data_que.get(False)
- for data_entry in que_data_packet:
- if data_entry[0] == "iq_header":
- webInterface_inst.logger.debug("Iq header data fetched from signal processing que")
- iq_header = data_entry[1]
- # Unpack header
- webInterface_inst.daq_frame_index = iq_header.cpi_index
-
- if iq_header.frame_type == iq_header.FRAME_TYPE_DATA:
- webInterface_inst.daq_frame_type = "Data"
- elif iq_header.frame_type == iq_header.FRAME_TYPE_DUMMY:
- webInterface_inst.daq_frame_type = "Dummy"
- elif iq_header.frame_type == iq_header.FRAME_TYPE_CAL:
- webInterface_inst.daq_frame_type = "Calibration"
- elif iq_header.frame_type == iq_header.FRAME_TYPE_TRIGW:
- webInterface_inst.daq_frame_type = "Trigger wait"
- else:
- webInterface_inst.daq_frame_type = "Unknown"
-
- webInterface_inst.daq_frame_sync = iq_header.check_sync_word()
- webInterface_inst.daq_power_level = iq_header.adc_overdrive_flags
- webInterface_inst.daq_sample_delay_sync = iq_header.delay_sync_flag
- webInterface_inst.daq_iq_sync = iq_header.iq_sync_flag
- webInterface_inst.daq_noise_source_state= iq_header.noise_source_state
-
- if webInterface_inst.daq_center_freq != iq_header.rf_center_freq/10**6:
- freq_update = 1
-
- webInterface_inst.daq_center_freq = iq_header.rf_center_freq/10**6
- webInterface_inst.daq_adc_fs = iq_header.adc_sampling_freq/10**6
- webInterface_inst.daq_fs = iq_header.sampling_freq/10**6
- webInterface_inst.daq_cpi = int(iq_header.cpi_length*10**3/iq_header.sampling_freq)
- gain_list_str=""
- for m in range(iq_header.active_ant_chs):
- gain_list_str+=str(iq_header.if_gains[m]/10)
- gain_list_str+=", "
- webInterface_inst.daq_if_gains =gain_list_str[:-2]
- daq_status_update_flag = 1
- elif data_entry[0] == "update_rate":
- webInterface_inst.daq_update_rate = data_entry[1]
- # Set absoluth minimum
- #if webInterface_inst.daq_update_rate < 0.1: webInterface_inst.daq_update_rate = 0.1
- if webInterface_inst._update_rate_arr is None:
- webInterface_inst._update_rate_arr = np.ones(webInterface_inst._avg_win_size)*webInterface_inst.daq_update_rate
- webInterface_inst._update_rate_arr[0:webInterface_inst._avg_win_size-2] = \
- webInterface_inst._update_rate_arr[1:webInterface_inst._avg_win_size-1]
- webInterface_inst._update_rate_arr[webInterface_inst._avg_win_size-1] = webInterface_inst.daq_update_rate
- #webInterface_inst.page_update_rate = np.average(webInterface_inst._update_rate_arr)*0.8
- elif data_entry[0] == "latency":
- webInterface_inst.daq_dsp_latency = data_entry[1] + webInterface_inst.daq_cpi
- elif data_entry[0] == "spectrum":
- webInterface_inst.logger.debug("Spectrum data fetched from signal processing que")
- spectrum_update_flag = 1
- webInterface_inst.spectrum = data_entry[1]
- elif data_entry[0] == "RD_matrix":
- webInterface_inst.logger.debug("Passive Radar RD Matrix data fetched from signal processing que")
- doa_update_flag = 1
- webInterface_inst.RD_matrix = data_entry[1]
- else:
- webInterface_inst.logger.warning("Unknown data entry: {:s}".format(data_entry[0]))
- except queue.Empty:
- # Handle empty queue here
- webInterface_inst.logger.debug("Signal processing que is empty")
- else:
- pass
- # Handle task here and call q.task_done()
-
- #current_time = time.time()
- #time_elapsed = current_time - webInterface_inst.update_time
- #webInterface_inst.update_time = current_time
-
- if (webInterface_inst.pathname == "/config" or webInterface_inst.pathname == "/") and daq_status_update_flag:
- update_daq_status()
- elif webInterface_inst.pathname == "/spectrum" and spectrum_update_flag:
- plot_spectrum()
- elif (webInterface_inst.pathname == "/pr" and doa_update_flag): #or (webInterface_inst.pathname == "/doa" and webInterface_inst.reset_doa_graph_flag):
- plot_pr()
-
- #if (pathname == "/config" or pathname=="/") and daq_status_update_flag:
- # pass
- #elif pathname == "/spectrum" and spectrum_update_flag:
- # pass
- #elif pathname == "/doa" and doa_update_flag:
- # pass
- #else:
- # pass
-
- webInterface_inst.dsp_timer = Timer(.01, fetch_dsp_data)
- webInterface_inst.dsp_timer.start()
-
-
-def update_daq_status():
-
- #############################################
- # Prepare UI component properties #
- #############################################
-
- if webInterface_inst.daq_conn_status == 1:
-
- if not webInterface_inst.daq_cfg_iface_status:
- daq_conn_status_str = "Connected"
- conn_status_style={"color": "green"}
- else: # Config interface is busy
- daq_conn_status_str = "Reconfiguration.."
- conn_status_style={"color": "orange"}
- else:
- daq_conn_status_str = "Disconnected"
- conn_status_style={"color": "red"}
-
- if webInterface_inst.daq_restart:
- daq_conn_status_str = "Restarting.."
- conn_status_style={"color": "orange"}
-
- if webInterface_inst.daq_update_rate < 1:
- daq_update_rate_str = "{:d} ms".format(round(webInterface_inst.daq_update_rate*1000))
- else:
- daq_update_rate_str = "{:.2f} s".format(webInterface_inst.daq_update_rate)
-
- daq_dsp_latency = "{:d} ms".format(webInterface_inst.daq_dsp_latency)
- daq_frame_index_str = str(webInterface_inst.daq_frame_index)
-
- daq_frame_type_str = webInterface_inst.daq_frame_type
- if webInterface_inst.daq_frame_type == "Data":
- frame_type_style = frame_type_style={"color": "green"}
- elif webInterface_inst.daq_frame_type == "Dummy":
- frame_type_style = frame_type_style={"color": "white"}
- elif webInterface_inst.daq_frame_type == "Calibration":
- frame_type_style = frame_type_style={"color": "orange"}
- elif webInterface_inst.daq_frame_type == "Trigger wait":
- frame_type_style = frame_type_style={"color": "yellow"}
- else:
- frame_type_style = frame_type_style={"color": "red"}
-
- if webInterface_inst.daq_frame_sync:
- daq_frame_sync_str = "LOSS"
- frame_sync_style={"color": "red"}
- else:
- daq_frame_sync_str = "Ok"
- frame_sync_style={"color": "green"}
- if webInterface_inst.daq_sample_delay_sync:
- daq_delay_sync_str = "Ok"
- delay_sync_style={"color": "green"}
- else:
- daq_delay_sync_str = "LOSS"
- delay_sync_style={"color": "red"}
-
- if webInterface_inst.daq_iq_sync:
- daq_iq_sync_str = "Ok"
- iq_sync_style={"color": "green"}
- else:
- daq_iq_sync_str = "LOSS"
- iq_sync_style={"color": "red"}
-
- if webInterface_inst.daq_noise_source_state:
- daq_noise_source_str = "Enabled"
- noise_source_style={"color": "red"}
- else:
- daq_noise_source_str = "Disabled"
- noise_source_style={"color": "green"}
-
- if webInterface_inst.daq_power_level:
- daq_power_level_str = "Overdrive"
- daq_power_level_style={"color": "red"}
- else:
- daq_power_level_str = "OK"
- daq_power_level_style={"color": "green"}
-
- daq_rf_center_freq_str = str(webInterface_inst.daq_center_freq)
- daq_sampling_freq_str = str(webInterface_inst.daq_fs)
- daq_cpi_str = str(webInterface_inst.daq_cpi)
- #daq_max_amp_str = "{:.1f}".format(webInterface_inst.max_amplitude)
- #daq_avg_powers_str = webInterface_inst.avg_powers
-
-
- app.push_mods({
- 'body_daq_update_rate': {'children': daq_update_rate_str},
- 'body_daq_dsp_latency': {'children': daq_dsp_latency},
- 'body_daq_frame_index': {'children': daq_frame_index_str},
- 'body_daq_frame_sync': {'children': daq_frame_sync_str},
- 'body_daq_frame_type': {'children': daq_frame_type_str},
- 'body_daq_power_level': {'children': daq_power_level_str},
- 'body_daq_conn_status': {'children': daq_conn_status_str },
- 'body_daq_delay_sync': {'children': daq_delay_sync_str},
- 'body_daq_iq_sync': {'children': daq_iq_sync_str},
- 'body_daq_noise_source': {'children': daq_noise_source_str},
- 'body_daq_rf_center_freq': {'children': daq_rf_center_freq_str},
- 'body_daq_sampling_freq': {'children': daq_sampling_freq_str},
- 'body_daq_cpi': {'children': daq_cpi_str},
- 'body_daq_if_gain': {'children': webInterface_inst.daq_if_gains},
- #'body_avg_powers': {'children': daq_avg_powers_str}
- })
-
- app.push_mods({
- 'body_daq_frame_sync': {'style': frame_sync_style},
- 'body_daq_frame_type': {'style': frame_type_style},
- 'body_daq_power_level': {'style': daq_power_level_style},
- 'body_daq_conn_status': {'style': conn_status_style},
- 'body_daq_delay_sync': {'style': delay_sync_style},
- 'body_daq_iq_sync': {'style': iq_sync_style},
- 'body_daq_noise_source': {'style': noise_source_style},
- })
-
-@app.callback(
- Output(component_id="placeholder_update_freq", component_property="children"),
- [Input(component_id ="btn-update_rx_param" , component_property="n_clicks")],
- [State(component_id ="daq_center_freq" , component_property='value'),
- State(component_id ="daq_rx_gain" , component_property='value')],
-)
-def update_daq_params(input_value, f0, gain):
- #if input_value is None:
- # raise PreventUpdate
- webInterface_inst.daq_center_freq = f0
- webInterface_inst.config_daq_rf(f0,gain)
- return 1
-
-@app.callback([Output("page-content" , "children"),
- Output("header_config" ,"className"),
- Output("header_spectrum","className"),
- Output("header_doa" ,"className")],
- [Input("url" , "pathname")])
-def display_page(pathname):
- global spectrum_fig
- global doa_fig
- webInterface_inst.pathname = pathname
-
- if pathname == "/":
- webInterface_inst.module_signal_processor.en_spectrum = False
- return [generate_config_page_layout(webInterface_inst), "header_active", "header_inactive", "header_inactive"]
- elif pathname == "/config":
- webInterface_inst.module_signal_processor.en_spectrum = False
- return [generate_config_page_layout(webInterface_inst), "header_active", "header_inactive", "header_inactive"]
- elif pathname == "/spectrum":
- webInterface_inst.module_signal_processor.en_spectrum = True
- #webInterface_inst.reset_spectrum_graph_flag = True
- #plot_spectrum()
- #while webInterface_inst.reset_spectrum_graph_flag: time.sleep(1)
- spectrum_fig = None # Force reload of graphs as axes may change etc
- time.sleep(1)
- return [spectrum_page_layout, "header_inactive", "header_active", "header_inactive"]
- elif pathname == "/pr":
- webInterface_inst.module_signal_processor.en_spectrum = False
- #webInterface_inst.module_signal_processor.en_DOA_estimation = False
- #webInterface_inst.reset_doa_graph_flag = True
- plot_pr()
- #doa_fig = {}
- #while webInterface_inst.reset_doa_graph_flag: time.sleep(1) # Wait until the graph is reset
- #while doa_fig == None : time.sleep(0.1) # Wait for doa_fig to reconfigure in timer callback
- #time.sleep(1)
- #webInterface_inst.module_signal_processor.en_DOA_estimation = True
- return [generate_pr_page_layout(webInterface_inst), "header_inactive", "header_inactive", "header_active"]
- return Output('dummy_output', 'children', '') #[no_update, no_update, no_update, no_update]
-
- #return [no_update, no_update, no_update, no_update]
-
-
-@app.callback_shared(
- None,
- [Input(component_id='btn-start_proc', component_property='n_clicks')],
-)
-def start_proc_btn(input_value):
- webInterface_inst.logger.info("Start pocessing btn pushed")
- webInterface_inst.start_processing()
-
-@app.callback_shared(
- None,
- [Input(component_id='btn-stop_proc', component_property='n_clicks')],
-)
-def stop_proc_btn(input_value):
- webInterface_inst.logger.info("Stop pocessing btn pushed")
- webInterface_inst.stop_processing()
-
-@app.callback_shared(
- None,
- [Input(component_id='btn-save_cfg' , component_property='n_clicks')],
-)
-def save_config_btn(input_value):
- webInterface_inst.logger.info("Saving DAQ and DSP Configuration")
- webInterface_inst.save_configuration()
-
-"""
-@app.callback(
- #Output(component_id='url', component_property='pathname'),
- None,
- [Input(component_id='mem_leak_refresh_interval', component_property='n_intervals')],
- [State(component_id='url', component_property='pathname')]
-)
-def heatmap_mem_leak_refresh_fix(intervals, pathname):
- if pathname == "/doa":
-
- CAFMatrix = np.abs(webInterface_inst.RD_matrix)
-
- CAFMatrix = CAFMatrix / 50 #/ np.amax(CAFMatrix) # Noramlize with the maximum value
- CAFMatrixLog = 20 * np.log10(CAFMatrix)
-
- CAFDynRange = 20
- CAFMatrixLog[CAFMatrixLog < -CAFDynRange] = -CAFDynRange
-
-
- pr_init = CAFMatrixLog
- pr_fig = go.Figure(layout=fig_layout)
- pr_fig.add_trace(go.Heatmap(
- z=pr_init,
- zsmooth='best', #False,
- #zsmooth=False, #False,
- showscale=False,
- hoverinfo='skip',
- colorscale=[[0.0, '#000020'],
- [0.0714, '#000030'],
- [0.1428, '#000050'],
- [0.2142, '#000091'],
- [0.2856, '#1E90FF'],
- [0.357, '#FFFFFF'],
- [0.4284, '#FFFF00'],
- [0.4998, '#FE6D16'],
- [0.5712, '#FE6D16'],
- [0.6426, '#FF0000'],
- [0.714, '#FF0000'],
- [0.7854, '#C60000'],
- [0.8568, '#9F0000'],
- [0.9282, '#750000'],
- [1.0, '#4A0000']]))
-
- app.push_mods({
- 'pr-graph': {'figure': pr_fig},
- #'pr-graph': {'extendData': pr_fig},
- # 'waterfall-graph': {'figure': waterfall_fig}
- })
-"""
-
-def plot_pr():
- global pr_fig
-
- if webInterface_inst.RD_matrix is not None:
-
- #start = time.time()
-
- CAFMatrix = np.abs(webInterface_inst.RD_matrix)
-
- CAFMatrix = CAFMatrix / 50 #/ np.amax(CAFMatrix) # Noramlize with the maximum value
-
- if webInterface_inst.CAFMatrixPersist is None or webInterface_inst.CAFMatrixPersist.shape != CAFMatrix.shape or not webInterface_inst.en_persist:
- webInterface_inst.CAFMatrixPersist = CAFMatrix
- else:
- webInterface_inst.CAFMatrixPersist = np.maximum(webInterface_inst.CAFMatrixPersist, CAFMatrix)*webInterface_inst.pr_persist_decay #webInterface_inst.CAFMatrixPersist * 0.5 + CAFMatrix * 0.5
-
- #CAFMatrixNew = #np.maximum(webInterface_inst.CAFMatrixOld, CAFMatrix)
- #webInterface_inst.CAFMatrixOld = CAFMatrixNew
- #webInterface_inst.CAFMatrixOld = webInterface_inst.CAFMatrixOld * 0.999
-
- CAFMatrixLog = 20 * np.log10(webInterface_inst.CAFMatrixPersist)
-
- CAFDynRange = webInterface_inst.pr_dynamic_range_min
- CAFMatrixLog[CAFMatrixLog < CAFDynRange] = CAFDynRange
-
- CAFDynRange = webInterface_inst.pr_dynamic_range_max
- CAFMatrixLog[CAFMatrixLog > CAFDynRange] = CAFDynRange
-
- #end = time.time()
- #print("WebInt Time: " + str((end-start)* 1000))
-
- app.push_mods({
- #'pr-store': {'data': CAFMatrixLog}
- 'pr-graph': {'extendData': [dict(z =[CAFMatrixLog]), [0], len(CAFMatrixLog)]}
- })
-
-
-# DOA Graph Clientside Callback
-#app.clientside_callback(
-# """
-# function (data, graph_type) {
-# return [
-# [{z: [data]}, [0], data.length]
-# ]
-#
-# }
-# """,
-# [Output('pr-graph', 'extendData')],
-# [Input('pr-store', 'data')]
-#)
-
-
-app.clientside_callback(
- """
- function (data) {
- /*return [{x: data.map(i => i.x), y: data.map(i => i.y)}, [...Array(data.length).keys()], data[0].x.length]*/
-
- /*const every_nth = (arr, nth) => arr.filter((e, i) => i % nth === (nth | 0) - 1);*/
-
- return [
- [{x: data.map(i => i.x), y: data.map(i => i.y)}, [...Array(data.length).keys()], data[0].x.length],
- /*[{z: [[every_nth(data[0].y, 1)]]}, [0], 50]*/
- [{z: [[data[0].y]]}, [0], 50]
- ]
- }
- """,
- [Output('spectrum-graph', 'extendData'),
- Output('waterfall-graph', 'extendData')],
- [Input('spectrum-store', 'data')]
-)
-
-def plot_spectrum():
- global spectrum_fig
- global waterfall_fig
- if spectrum_fig == None:
- #if webInterface_inst.reset_spectrum_graph_flag:
- spectrum_fig = go.Figure(layout=fig_layout)
- #freq_label="Frequency [MHz]"
-
- x=webInterface_inst.spectrum[0,:] + webInterface_inst.daq_center_freq*10**6
-
- # Plot traces
- for m in range(np.size(webInterface_inst.spectrum, 0)-2):
- spectrum_fig.add_trace(go.Scattergl(x=x,
- y=y, #webInterface_inst.spectrum[m+1, :],
- name="Channel {:d}".format(m),
- line = dict(color = trace_colors[m],
- width = 1)
- ))
-
- spectrum_fig.add_hline(y=webInterface_inst.module_receiver.daq_squelch_th_dB)
-
- # Add selected window plot
- m = np.size(webInterface_inst.spectrum,0)-1
- spectrum_fig.add_trace(go.Scattergl(x=x,
- y=y, #webInterface_inst.spectrum[m, :],
- name="Selected Signal Window",
- line = dict(color = trace_colors[m],
- width = 3)
- ))
-
- spectrum_fig.update_xaxes( #title_text=freq_label,
- color='rgba(255,255,255,1)',
- title_font_size=20,
- tickfont_size= 15, #figure_font_size,
- range=[np.min(x), np.max(x)],
- rangemode='normal',
- mirror=True,
- ticks='outside',
- showline=True)
- spectrum_fig.update_yaxes(title_text="Amplitude [dB]",
- color='rgba(255,255,255,1)',
- title_font_size=20,
- tickfont_size=figure_font_size,
- range=[-90, 0],
- mirror=True,
- ticks='outside',
- showline=True)
-
-
- spectrum_fig.update_layout(margin=go.layout.Margin(b=5, t=0))
-
- webInterface_inst.reset_spectrum_graph_flag = False
- app.push_mods({
- 'spectrum-graph': {'figure': spectrum_fig},
- # 'waterfall-graph': {'figure': waterfall_fig}
- })
-
- else:
- update_data = []
- for m in range(1, np.size(webInterface_inst.spectrum, 0)): #webInterface_inst.module_receiver.M+1):
- #update_data.append(dict(x=webInterface_inst.spectrum[0,:], y=webInterface_inst.spectrum[m, :]))
- update_data.append(dict(x=webInterface_inst.spectrum[0,:] + webInterface_inst.daq_center_freq*10**6, y=webInterface_inst.spectrum[m, :]))
-
- app.push_mods({
- 'spectrum-store': {'data': update_data}
- #'spectrum-graph': {'extendData': spec},
- #'waterfall-graph': {'extendData': waterfall}
- })
-
-
-@app.callback(
- #[Output(component_id="body_ant_spacing_wavelength", component_property='children')],
- #Output(component_id="label_ant_spacing_meter", component_property='children')],
- #Output(component_id="ambiguity_warning", component_property='children'),
- #Output(component_id="en_fb_avg_check", component_property="options")],
- None,
- [Input(component_id ="placeholder_update_freq" , component_property='children'),
- Input(component_id ="en_pr_check" , component_property='value'),
- Input(component_id ="en_persist_check" , component_property='value'),
- Input(component_id ="persist_decay" , component_property='value'),
- Input(component_id ="max_bistatic_range" , component_property='value'),
- Input(component_id ="max_doppler" , component_property='value'),
- Input(component_id ="clutter_cancel_algo" , component_property='value'),
- Input(component_id ="dynrange_max" , component_property='value'),
- Input(component_id ="dynrange_min" , component_property='value')]
-)
-#def update_dsp_params(freq_update, en_doa, en_fb_avg, spacing_meter, ant_arrangement, doa_fig_type, doa_method, compass_ofset): #, input_value):
-def update_dsp_params(update_freq, en_pr, en_persist, persist_decay, max_bistatic_range, max_doppler, clutter_cancel_algo, dynrange_max, dynrange_min): #, input_value):
-
- if en_pr is not None and len(en_pr):
- webInterface_inst.logger.debug("Passive Radar enabled")
- webInterface_inst.module_signal_processor.en_PR = True
- else:
- webInterface_inst.module_signal_processor.en_PR = False
-
- if en_persist is not None and len(en_persist):
- webInterface_inst.en_persist = True
- else:
- webInterface_inst.en_persist = False
-
- #webInterface_inst.module_signal_processor.DOA_ant_alignment=ant_arrangement
- webInterface_inst.module_signal_processor.PR_clutter_cancellation = clutter_cancel_algo
- webInterface_inst.module_signal_processor.max_bistatic_range = max_bistatic_range
- webInterface_inst.module_signal_processor.max_doppler = max_doppler
- webInterface_inst.pr_persist_decay = persist_decay
- webInterface_inst.pr_dynamic_range_min = dynrange_min
- webInterface_inst.pr_dynamic_range_max = dynrange_max
- #webInterface_inst._doa_fig_type = doa_fig_type
- #webInterface_inst.compass_ofset = compass_ofset
-
- #return [str(ant_spacing_wavelength)]
-
-@app.callback(
- None,
- [Input('cfg_rx_channels' ,'value'),
- Input('cfg_daq_buffer_size' ,'value'),
- Input('cfg_sample_rate' ,'value'),
- Input('en_noise_source_ctr' ,'value'),
- Input('en_squelch_mode' ,'value'),
- Input('cfg_squelch_init_th' ,'value'),
- Input('cfg_cpi_size' ,'value'),
- Input('cfg_decimation_ratio' ,'value'),
- Input('cfg_fir_bw' ,'value'),
- Input('cfg_fir_tap_size' ,'value'),
- Input('cfg_fir_window' ,'value'),
- Input('en_filter_reset' ,'value'),
- Input('cfg_corr_size' ,'value'),
- Input('cfg_std_ch_ind' ,'value'),
- Input('en_iq_cal' ,'value'),
- Input('cfg_gain_lock' ,'value'),
- Input('en_req_track_lock_intervention','value'),
- Input('cfg_cal_track_mode' ,'value'),
- Input('cfg_amplitude_cal_mode' ,'value'),
- Input('cfg_cal_frame_interval' ,'value'),
- Input('cfg_cal_frame_burst_size' ,'value'),
- Input('cfg_amplitude_tolerance' ,'value'),
- Input('cfg_phase_tolerance' ,'value'),
- Input('cfg_max_sync_fails' ,'value'),
- Input('cfg_data_block_len' ,'value'),
- Input('cfg_decimated_bw' ,'value'),
- Input('cfg_recal_interval' ,'value')]
-)
-def update_daq_ini_params(
- cfg_rx_channels,cfg_daq_buffer_size,cfg_sample_rate,en_noise_source_ctr, \
- en_squelch_mode,cfg_squelch_init_th,cfg_cpi_size,cfg_decimation_ratio, \
- cfg_fir_bw,cfg_fir_tap_size,cfg_fir_window,en_filter_reset,cfg_corr_size, \
- cfg_std_ch_ind,en_iq_cal,cfg_gain_lock,en_req_track_lock_intervention, \
- cfg_cal_track_mode,cfg_amplitude_cal_mode,cfg_cal_frame_interval, \
- cfg_cal_frame_burst_size, cfg_amplitude_tolerance,cfg_phase_tolerance, \
- cfg_max_sync_fails, cfg_data_block_len, cfg_decimated_bw, cfg_recal_interval):
- # TODO: Use disctionarry instead of parameter list
-
- ctx = dash.callback_context
- component_id = ctx.triggered[0]['prop_id'].split('.')[0]
- if ctx.triggered:
- if len(ctx.triggered) == 1: # User manually changed one parameter
- webInterface_inst.tmp_daq_ini_cfg = "Custom"
-
- # If the input was from basic DAQ config, update the actual DAQ params
- if component_id == "cfg_data_block_len" or component_id == "cfg_decimated_bw" or component_id == "cfg_recal_interval":
- if not cfg_data_block_len or not cfg_decimated_bw or not cfg_recal_interval:
- return Output('dummy_output', 'children', '') #[no_update, no_update, no_update, no_update]
-
- cfg_daq_buffer_size = 262144 # This is a reasonable DAQ buffer size to use
- cfg_corr_size = 32768 # Reasonable value that never has problems calibrating
- en_noise_source_ctr = [1]
- en_squelch_mode = [] # NOTE: For checkboxes, zero is defined by an empty array
- cfg_fir_bw = 1
- cfg_fir_window = 'hann'
- en_filter_reset = []
- cfg_std_ch_ind = 0
- en_iq_cal = [1]
- en_req_track_lock_intervention = []
- cfg_amplitude_cal_mode = 'channel_power'
- cfg_cal_frame_burst_size = 10
- cfg_amplitude_tolerance = 2
- cfg_phase_tolerance = 2
- cfg_max_sync_fails = 10
-
- # Set sample rate to something sensible for the desired decimated_bw
- """
- if cfg_decimated_bw < 3:
- cfg_sample_rate = 0.25
- cfg_corr_size = 4096
- cfg_daq_buffer_size = 16384
- elif cfg_decimated_bw < 10:
- cfg_sample_rate = 1.024
- cfg_corr_size = 16384
- else:
- cfg_sample_rate = 2.4
- """
-
- cfg_decimation_ratio = round( (cfg_sample_rate*10**6) / (cfg_decimated_bw*10**3) )
-
- cfg_cpi_size = round( (cfg_data_block_len / 10**3) * cfg_decimated_bw*10**3 )
- cfg_cal_frame_interval = round((cfg_recal_interval*60) / (cfg_data_block_len/10**3))
-
- while cfg_decimation_ratio * cfg_cpi_size < cfg_daq_buffer_size:
- cfg_daq_buffer_size = (int) (cfg_daq_buffer_size / 2)
-
- cfg_corr_size = (int) (cfg_daq_buffer_size / 2)
-
- # Choose a tap size larger than the decimation ratio
- cfg_fir_tap_size = (int)(cfg_decimation_ratio * 1.2) + 8
-
- if cfg_decimation_ratio == 1:
- cfg_fir_tap_size = 1
-
- cfg_cal_track_mode = 0
- if cfg_cal_frame_interval > 1:
- cfg_cal_track_mode = 2 #[{'label': calibration_tack_modes[1], 'value': calibration_tack_modes[1]}]
- else:
- cfg_cal_track_mode = 0
-
-
- param_list = []
- param_list.append("Custom")
- param_list.append(cfg_rx_channels)
- param_list.append(cfg_daq_buffer_size)
- param_list.append(int(cfg_sample_rate*10**6))
- if en_noise_source_ctr is not None and len(en_noise_source_ctr):
- param_list.append(1)
- else:
- param_list.append(0)
- if en_squelch_mode is not None and len(en_squelch_mode):
- param_list.append(1)
- else:
- param_list.append(0)
- param_list.append(cfg_squelch_init_th)
- param_list.append(cfg_cpi_size)
- param_list.append(cfg_decimation_ratio)
- param_list.append(cfg_fir_bw)
- param_list.append(cfg_fir_tap_size)
- param_list.append(cfg_fir_window)
- if en_filter_reset is not None and len(en_filter_reset):
- param_list.append(1)
- else:
- param_list.append(0)
- param_list.append(cfg_corr_size)
- param_list.append(cfg_std_ch_ind)
- if en_iq_cal is not None and len(en_iq_cal):
- param_list.append(1)
- else:
- param_list.append(0)
- param_list.append(cfg_gain_lock)
- if en_req_track_lock_intervention is not None and len(en_req_track_lock_intervention):
- param_list.append(1)
- else:
- param_list.append(0)
- param_list.append(cfg_cal_track_mode)
- param_list.append(cfg_amplitude_cal_mode)
- param_list.append(cfg_cal_frame_interval)
- param_list.append(cfg_cal_frame_burst_size)
- param_list.append(cfg_amplitude_tolerance)
- param_list.append(cfg_phase_tolerance)
- param_list.append(cfg_max_sync_fails)
- param_list.append(webInterface_inst.daq_ini_cfg_params[25]) # Preserve data interface information
- webInterface_inst.daq_ini_cfg_params = param_list
-
- if ctx.triggered:
- # If we updated advanced daq, update basic DAQ params
- if component_id == "cfg_sample_rate" or component_id == "cfg_decimation_ratio" or component_id == "cfg_cpi_size" or component_id == "cfg_cal_frame_interval":
- if not cfg_sample_rate or not cfg_decimation_ratio or not cfg_cpi_size:
- return Output('dummy_output', 'children', '') #[no_update, no_update, no_update, no_update]
-
- cfg_decimated_bw = ((int(cfg_sample_rate*10**6)) / cfg_decimation_ratio) / 10**3
- cfg_data_block_len = ( cfg_cpi_size / (cfg_decimated_bw) )
- cfg_recal_interval = (cfg_cal_frame_interval * (cfg_data_block_len/10**3)) / 60
-
- app.push_mods({
- 'cfg_data_block_len': {'value': cfg_data_block_len},
- 'cfg_decimated_bw': {'value': cfg_decimated_bw},
- 'cfg_recal_interval': {'value': cfg_recal_interval},
- })
- # If we updated basic DAQ, update advanced DAQ
- elif component_id == "cfg_data_block_len" or component_id == "cfg_decimated_bw" or component_id == "cfg_recal_interval":
- app.push_mods({
- 'cfg_decimation_ratio': {'value': cfg_decimation_ratio},
- 'cfg_cpi_size': {'value': cfg_cpi_size},
- 'cfg_cal_frame_interval': {'value': cfg_cal_frame_interval},
- 'cfg_fir_tap_size': {'value': cfg_fir_tap_size},
- 'cfg_sample_rate': {'value': cfg_sample_rate},
- 'cfg_daq_buffer_size': {'value': cfg_daq_buffer_size},
- 'cfg_corr_size': {'value': cfg_corr_size},
- 'en_noise_source_ctr': {'value': en_noise_source_ctr},
- 'en_squelch_mode': {'value': en_squelch_mode},
- 'cfg_fir_bw': {'value': cfg_fir_bw},
- 'cfg_fir_window': {'value': cfg_fir_window},
- 'en_filter_reset': {'value': en_filter_reset},
- 'cfg_std_ch_ind': {'value': cfg_std_ch_ind},
- 'en_iq_cal': {'value': en_iq_cal},
- 'en_req_track_lock_intervention': {'value': en_req_track_lock_intervention},
- 'cfg_amplitude_cal_mode': {'value': cfg_amplitude_cal_mode},
- 'cfg_cal_frame_burst_size': {'value': cfg_cal_frame_burst_size},
- 'cfg_amplitude_tolerance': {'value': cfg_amplitude_tolerance},
- 'cfg_phase_tolerance': {'value': cfg_phase_tolerance},
- 'cfg_max_sync_fails': {'value': cfg_max_sync_fails},
- })
-
-
-
-@app.callback(Output('adv-cfg-container', 'style'),
- [Input("en_advanced_daq_cfg", "value")]
-)
-def toggle_adv_daq(toggle_value):
- webInterface_inst.en_advanced_daq_cfg = toggle_value
- if toggle_value:
- return {'display': 'block'}
- else:
- return {'display': 'none'}
-
-@app.callback([Output("url" , "pathname")],
- [ #Input("en_advanced_daq_cfg" , "value"),
- Input("daq_cfg_files" , "value"),
- Input("placeholder_recofnig_daq" , "children"),
- Input("placeholder_update_rx" , "children")]
-)
-def reload_cfg_page(config_fname, dummy_0, dummy_1):
- #ctx = dash.callback_context
- webInterface_inst.daq_ini_cfg_params = read_config_file(config_fname)
- webInterface_inst.tmp_daq_ini_cfg = webInterface_inst.daq_ini_cfg_params[0]
-
- #if ctx.triggered:
- # component_id = ctx.triggered[0]['prop_id'].split('.')[0]
- #if component_id == "daq_cfg_files" and config_fname is not None:
- # webInterface_inst.daq_ini_cfg_params = read_config_file(config_fname)
- # webInterface_inst.tmp_daq_ini_cfg = webInterface_inst.daq_ini_cfg_params[0]
- #elif component_id == "en_advanced_daq_cfg":
- #if component_id == "en_advanced_daq_cfg":
- # if en_advanced_daq_cfg is not None and len(en_advanced_daq_cfg):
- # webInterface_inst.en_advanced_daq_cfg = True
- # else:
- # webInterface_inst.en_advanced_daq_cfg = False
- return ["/config"]
-
-@app.callback(
- None,
- [Input(component_id="btn_reconfig_daq_chain" , component_property="n_clicks")],
- [State(component_id ="daq_center_freq" , component_property='value'),
- State(component_id ="daq_rx_gain" , component_property='value')]
-)
-def reconfig_daq_chain(input_value, freq, gain):
-
- if input_value is None:
- return Output('dummy_output', 'children', '') #[no_update, no_update, no_update, no_update]
-
- #return [no_update]
-# raise PreventUpdate
-
- # TODO: Check data interface mode here !
- # Update DAQ Subsystem config file
-
- config_res, config_err = write_config_file(webInterface_inst.daq_ini_cfg_params)
- if config_res:
- webInterface_inst.daq_cfg_ini_error = config_err[0]
- return Output("placeholder_recofnig_daq", "children", '-1')
- else:
- webInterface_inst.logger.info("DAQ Subsystem configuration file edited")
-
- webInterface_inst.daq_restart = 1
-
- # Restart DAQ Subsystem
-
- # Stop signal processing
- webInterface_inst.stop_processing()
- #time.sleep(2)
- webInterface_inst.logger.debug("Signal processing stopped")
-
- # Close control and IQ data interfaces
- webInterface_inst.close_data_interfaces()
- webInterface_inst.logger.debug("Data interfaces are closed")
-
- os.chdir(daq_subsystem_path)
- # Kill DAQ subsystem
- daq_stop_script = subprocess.Popen(['bash', daq_stop_filename])#, stdout=subprocess.DEVNULL)
- daq_stop_script.wait()
- webInterface_inst.logger.debug("DAQ Subsystem halted")
-
- # Start DAQ subsystem
- daq_start_script = subprocess.Popen(['bash', daq_start_filename])#, stdout=subprocess.DEVNULL)
- daq_start_script.wait()
- webInterface_inst.logger.debug("DAQ Subsystem restarted")
-
- os.chdir(root_path)
-
- # Reinitialize receiver data interface
- if webInterface_inst.module_receiver.init_data_iface() == -1:
- webInterface_inst.logger.critical("Failed to restart the DAQ data interface")
- webInterface_inst.daq_cfg_ini_error = "Failed to restart the DAQ data interface"
- return [-1]
-
- # Reset channel number count
-# webInterface_inst.module_receiver.M = 0
- webInterface_inst.module_signal_processor.first_frame = 1
-
-
- # Restart signal processing
- webInterface_inst.start_processing()
- webInterface_inst.logger.debug("Signal processing started")
- webInterface_inst.daq_restart = 0
-
-
- # Gain is always reset to zero, need to set gains to what is in the web interface
- #webInterface_inst.config_daq_rf(freq,gain)
-
-
- # Set local Squelch-DSP parameters
- #if webInterface_inst.daq_ini_cfg_params[5]: # Squelch is enabled
- # webInterface_inst.module_signal_processor.en_squelch = True
- # webInterface_inst.module_receiver.daq_squelch_th_dB = -80 #round(20*np.log10(webInterface_inst.daq_ini_cfg_params[6]),1)
-
- #webInterface_inst.module_signal_processor.squelch_threshold = webInterface_inst.daq_ini_cfg_params[6]
- # Note: There is no need to set the thresold in the DAQ Subsystem as it is configured from the ini-file.
- #else: # Squelch is disabled
- # webInterface_inst.module_signal_processor.en_squelch = False
-
- # Set number of channels
- # Reset first_frame on signal processor so new channel count is read
- #webInterface_inst.module_signal_processor.channel_number = webInterface_inst.daq_ini_cfg_params[1]
-
- webInterface_inst.daq_cfg_ini_error = ""
- webInterface_inst.active_daq_ini_cfg = webInterface_inst.daq_ini_cfg_params[0] #webInterface_inst.tmp_daq_ini_cfg
-
-
- return Output("daq_cfg_files", "value", daq_config_filename), Output("active_daq_ini_cfg", "children", "Active Configuration: " + webInterface_inst.active_daq_ini_cfg)
-
- #return Output("placeholder_recofnig_daq", "children", '1')
-# return [0]
-
-
-if __name__ == "__main__":
- # For Development only, otherwise use gunicorn
- # Debug mode does not work when the data interface is set to shared-memory "shmem"!
- app.run_server(debug=False, host="0.0.0.0")
- #waitress #serve(app.server, host="0.0.0.0", port=8050)
-
-"""
-html.Div([
- html.H2("System Logs"),
- dcc.Textarea(
- placeholder = "Enter a value...",
- value = "System logs .. - Curently NOT used",
- style = {"width": "100%", "background-color": "#000000", "color":"#02c93d"}
- )
-], className="card")
-"""
diff --git a/util/_UI/_web_interface/tooltips.py b/util/_UI/_web_interface/tooltips.py
deleted file mode 100644
index b4ebfd1..0000000
--- a/util/_UI/_web_interface/tooltips.py
+++ /dev/null
@@ -1,210 +0,0 @@
-import dash_html_components as html
-import dash_bootstrap_components as dbc
-
-dsp_config_tooltips = html.Div([
- # Antenna arrangement selection
- dbc.Tooltip([
- html.P("ULA - Uniform Linear Array"),
- html.P("Antenna elements placed on a line with having equal distances between each other"),
- html.P("UCA - Uniform Circular Array"),
- html.P("Antenna elements are placed on circle equaly distributed on 360°")],
- target="label_ant_arrangement",
- placement="bottom",
- className="tooltip"
- ),
- # Antenna Spacing
-# dbc.Tooltip([
-# html.P("When ULA is selected: Spacing between antenna elements"),
-# html.P("When UCA is selected: Radius of the circle on which the elements are placed")],
-# target="label_ant_spacing",
-# placement="bottom",
-# className="tooltip"
-# ),
- # Enable F-B averaging
- dbc.Tooltip([
- html.P("Forward-backward averegaing improves the performance of DoA estimation in multipath environment"),
- html.P("(Available only for ULA antenna systems)")],
- target="label_en_fb_avg",
- placement="bottom",
- className="tooltip"
- ),
- ])
-
-daq_ini_config_tooltips = html.Div([
- # DAQ buffer size
- dbc.Tooltip([
- html.P("Buffer size of the realtek driver")],
- target="label_daq_buffer_size",
- placement="bottom",
- className="tooltip"
- ),
- # Sampling frequency
- dbc.Tooltip([
- html.P("Raw - ADC sampling frequency of the realtek chip")],
- target="label_sample_rate",
- placement="bottom",
- className="tooltip"
- ),
- # Enable noise source control
- dbc.Tooltip([
- html.P("Enables the utilization of the built-in noise source for calibration")],
- target="label_en_noise_source_ctr",
- placement="bottom",
- className="tooltip"
- ),
- # Enable squelch mode
- dbc.Tooltip([
- html.P("Enable DAQ-side squelch to capture burst like signals - NOTE DISABLED IN THIS VERSION, THIS VERSION USES DSP SIDE SQUELCH ONLY")],
- target="label_en_squelch",
- placement="bottom",
- className="tooltip"
- ),
- # Squelch threshold
- dbc.Tooltip([
- html.P("Amplitude threshold used for the squelch feature."),
- html.P("Should take values on range: 0...1"),
- html.P("When set to zero the squelch is bypassed")],
- target="label_squelch_init_threshold",
- placement="bottom",
- className="tooltip"
- ),
- # CPI size
- dbc.Tooltip([
- html.P("Length of the Coherent Processing Interval (CPI) after decimation")],
- target="label_cpi_size",
- placement="bottom",
- className="tooltip"
- ),
- # Decimation raito
- dbc.Tooltip([
- html.P("Decimation factor")],
- target="label_decimation_ratio",
- placement="bottom",
- className="tooltip"
- ),
- # FIR relative bandwidth
- dbc.Tooltip([
- html.P("Anti-aliasing filter bandwith after decimation"),
- html.P("Should take values on range: (0, 1]"),
- html.P("E.g.: ADC sampling frequency: 1 MHz (IQ!) , Decimation ratio: 2, FIR relative bandwith:0.25"),
- html.P("Resulting passband bandwidth: 125 kHz ")],
- target="label_fir_relative_bw",
- placement="bottom",
- className="tooltip"
- ),
- # FIR tap size
- dbc.Tooltip([
- html.P("Anti-aliasing FIR filter tap size - Do not set too large, or CPU utilization will be 100%"),
- html.P("Should be greater than the decimation ratio")],
- target="label_fir_tap_size",
- placement="bottom",
- className="tooltip"
- ),
- # FIR tap size
- dbc.Tooltip([
- html.P("Window function type for designing the anti-aliasing FIR filter"),
- html.P("https://en.wikipedia.org/wiki/Window_function")],
- target="label_fir_window",
- placement="bottom",
- className="tooltip"
- ),
- # Enable filter reset
- dbc.Tooltip([
- html.P("If enabled, the memory of the anti-aliasing FIR filter is reseted at the begining of every new CPI")],
- target="label_en_filter_reset",
- placement="bottom",
- className="tooltip"
- ),
- # Correlation size
- dbc.Tooltip([
- html.P("Number of samples used for the calibration procedure (sample delay and IQ compensation)")],
- target="label_correlation_size",
- placement="bottom",
- className="tooltip"
- ),
- # Standard channel index
- dbc.Tooltip([
- html.P("The selected channel is used as a reference for the IQ compensation")],
- target="label_std_ch_index",
- placement="bottom",
- className="tooltip"
- ),
- # Enable IQ calibration
- dbc.Tooltip([
- html.P("Enables to compensate the amplitude and phase differences of the receiver channels")],
- target="label_en_iq_calibration",
- placement="bottom",
- className="tooltip"
- ),
- # Gain lock interval
- dbc.Tooltip([
- html.P("Minimum number of stable frames before terminating the gain tuning procedure")],
- target="label_gain_lock_interval",
- placement="bottom",
- className="tooltip"
- ),
- # Require track lock intervention
- dbc.Tooltip([
- html.P("When enabled the DAQ firmware waits for manual intervention during the calibraiton procedure"),
- html.P("Should be used only for hardave version 1.0")],
- target="label_require_track_lock",
- placement="bottom",
- className="tooltip"
- ),
- # Amplitude calibraiton mode
- dbc.Tooltip([
- html.P("Amplitude difference compensation method applied as part of the IQ compensation"),
- html.P("default: Amplitude differences are estimated by calculating the cross-correlations of the channels"),
- html.P("disabled: Amplitude differences are not compensated"),
- html.P("channel_power: Ampltiude compensation is set in a way to achieve equal channel powers")],
- target="label_amplitude_calibration_mode",
- placement="bottom",
- className="tooltip"
- ),
- dbc.Tooltip([
- html.P("When periodic calibration track mode is selected the firmware regularly turn on the noise source for a short burst to\
- check whether the IQ calibration is still valid or not. In case the calibrated state is lost, the firmware automatically\
- initiates a reclaibration procedure")],
- target="label_calibration_track_mode",
- placement="bottom",
- className="tooltip"
- ),
-
- # Calibration frame interval
- dbc.Tooltip([
- html.P("Number of data frames between two consecutive calibration burst. Used when periodic calibration mode is selected")],
- target="label_calibration_frame_interval",
- placement="bottom",
- className="tooltip"
- ),
- # Calibration frame burst size
- dbc.Tooltip([
- html.P("Number of calibration frames generated in the periodic calibration mode")],
- target="label_calibration_frame_burst_size",
- placement="bottom",
- className="tooltip"
- ),
- # Amplitude tolerance
- dbc.Tooltip([
- html.P("Maximum allowed amplitude difference between the receiver channels")],
- target="label_amplitude_tolerance",
- placement="bottom",
- className="tooltip"
- ),
- # Phase tolerance
- dbc.Tooltip([
- html.P("Maximum allowed phase difference between the receiver channels")],
- target="label_phase_tolerance",
- placement="bottom",
- className="tooltip"
- ),
- # Maximum sync fails
- dbc.Tooltip([
- html.P("Maximum allowed consecutive IQ difference check failures before initiating a recalibration")],
- target="label_max_sync_fails",
- placement="bottom",
- className="tooltip"
- ),
- ])
-
-