コード例 #1
0
    def __init__(self, controller, main_window):
        self.controller = controller
        controller.device_change.connect(self.device_changed)
        controller.state_change.connect(self.state_changed)
        controller.plot_change.connect(self.plot_changed)
        controller.capture_receive.connect(self.capture_received)
        controller.options_change.connect(self.options_changed)

        self._main_window = main_window

        self.ref_level = 0
        self.dut = None
        self.control_widgets = []
        super(MainPanel, self).__init__()
        screen = QtGui.QDesktopWidget().screenGeometry()
        self.setMinimumWidth(MINIMUM_WIDTH)
        self.setMinimumHeight(MINIMUM_HEIGHT)
        self.plot_state = None
        self.gui_state = None
        # plot window
        self._plot = Plot(controller, self)
        self._plot.user_xrange_change.connect(controller.user_xrange_changed)

        self._vrt_context = {}
        self.initUI()
        self.disable_controls()
        self.plot_state = None

        self._waterfall_range = None, None, None

        self.options_changed(
            controller.get_options(),
            ['iq_plots', 'waterfall_plot', 'persistence_plot'])
コード例 #2
0
ファイル: gui.py プロジェクト: wardi/pyrf
    def __init__(self, controller, main_window):
        self.controller = controller
        controller.device_change.connect(self.device_changed)
        controller.state_change.connect(self.state_changed)
        controller.capture_receive.connect(self.capture_received)
        controller.options_change.connect(self.options_changed)

        self._main_window = main_window

        self.ref_level = 0
        self.dut = None
        self.control_widgets = []
        super(MainPanel, self).__init__()
        screen = QtGui.QDesktopWidget().screenGeometry()
        self.setMinimumWidth(MINIMUM_WIDTH)
        self.setMinimumHeight(MINIMUM_HEIGHT)
        self.plot_state = None
        self.gui_state = None
        # plot window
        self._plot = Plot(controller, self)
        self._plot.user_xrange_change.connect(controller.user_xrange_changed)

        self._vrt_context = {}
        self.initUI()
        self.disable_controls()
        self.plot_state = None

        self._waterfall_range = None, None, None

        self.options_changed(controller.get_options(), ["iq_plots", "waterfall_plot"])
コード例 #3
0
ファイル: gui.py プロジェクト: wardi/pyrf
class MainPanel(QtGui.QWidget):
    """
    The spectrum view and controls
    """

    def __init__(self, controller, main_window):
        self.controller = controller
        controller.device_change.connect(self.device_changed)
        controller.state_change.connect(self.state_changed)
        controller.capture_receive.connect(self.capture_received)
        controller.options_change.connect(self.options_changed)

        self._main_window = main_window

        self.ref_level = 0
        self.dut = None
        self.control_widgets = []
        super(MainPanel, self).__init__()
        screen = QtGui.QDesktopWidget().screenGeometry()
        self.setMinimumWidth(MINIMUM_WIDTH)
        self.setMinimumHeight(MINIMUM_HEIGHT)
        self.plot_state = None
        self.gui_state = None
        # plot window
        self._plot = Plot(controller, self)
        self._plot.user_xrange_change.connect(controller.user_xrange_changed)

        self._vrt_context = {}
        self.initUI()
        self.disable_controls()
        self.plot_state = None

        self._waterfall_range = None, None, None

        self.options_changed(controller.get_options(), ["iq_plots", "waterfall_plot"])

    def device_changed(self, dut):
        self.plot_state = gui_config.PlotState(dut.properties)
        self.trace_group.plot_state = self.plot_state
        self.dut_prop = dut.properties

        self.enable_controls()

    def state_changed(self, state, changed):
        """
        signal handler for speca state changes
        :param state: new SpecAState object
        :param changed: list of attribute names changed
        """
        self.gui_state = state

        if "mode" in changed:
            rfe_mode = state.rfe_mode()
            self._update_iq_plot_visibility()

            if rfe_mode in ("DD", "IQIN"):
                freq = self.dut_prop.MIN_TUNABLE[rfe_mode]
                full_bw = self.dut_prop.FULL_BW[rfe_mode]

                self._plot.center_view(
                    freq, full_bw, self._amplitude_group.get_min_level(), self._amplitude_group.get_ref_level()
                )
                self._plot.iq_window.setYRange(IQ_PLOT_YMIN[rfe_mode], IQ_PLOT_YMAX[rfe_mode])
            else:
                freq = state.center
                full_bw = state.span

                self._plot.center_view(
                    freq - full_bw / 2,
                    freq + full_bw / 2,
                    self._amplitude_group.get_min_level(),
                    self._amplitude_group.get_ref_level(),
                )
                self._plot.iq_window.setYRange(IQ_PLOT_YMIN[rfe_mode], IQ_PLOT_YMAX[rfe_mode])
        if "device_settings.iq_output_path" in changed:
            if state.device_settings["iq_output_path"] == "CONNECTOR":
                # remove plots
                self._amplitude_group.hide()
                self._plot_layout.hide()
                if self._main_window.isMaximized():
                    self._main_window.showNormal()

                # resize window
                for x in range(self.plot_width):
                    self._grid.setColumnMinimumWidth(x, 0)
                screen = QtGui.QDesktopWidget().screenGeometry()

                self.setMinimumWidth(0)
                self.setMinimumHeight(0)
                self._main_window.setMinimumWidth(0)
                self._main_window.setMinimumHeight(0)
                self.resize(0, 0)
                self._main_window.resize(0, 0)

            else:
                # show plots
                self._plot_layout.show()

                # resize window
                for x in range(self.plot_width):
                    self._grid.setColumnMinimumWidth(x, 300)
                screen = QtGui.QDesktopWidget().screenGeometry()
                self.setMinimumWidth(MINIMUM_WIDTH)
                self.setMinimumHeight(MINIMUM_HEIGHT)
                WINDOW_WIDTH = max(screen.width() * 0.7, MINIMUM_WIDTH)
                WINDOW_HEIGHT = max(screen.height() * 0.6, MINIMUM_HEIGHT)
                self.resize(WINDOW_WIDTH, WINDOW_HEIGHT)

    def keyPressEvent(self, event):
        if not self.dut_prop:
            return

        hotkey_dict = {"M": self.trace_group._marker_control, "P": self.trace_group._find_peak}

        arrow_dict = {
            "32": "SPACE",
            "16777235": "UP KEY",
            "16777237": "DOWN KEY",
            "16777234": "LEFT KEY",
            "16777236": "RIGHT KEY",
        }

        if str(event.key()) in arrow_dict:
            hotkey = arrow_dict[str(event.key())]
        else:
            hotkey = str(event.text()).upper()
        if hotkey in hotkey_dict:
            hotkey_dict[hotkey]()

    def mousePressEvent(self, event):
        if not self.controller._dut:
            return

        for marker in self._plot.markers:
            if marker.selected:
                break
        else:
            return

        trace = self._plot.traces[marker.trace_index]
        if event.button() == QtCore.Qt.MouseButton.LeftButton:
            click_pos = event.pos().x() - 68  # FIXME: declare this as a constant?
            plot_window_width = self._plot.window.width() - 68

            if click_pos < plot_window_width and click_pos > 0:
                window_freq = self._plot.view_box.viewRange()[0]
                window_bw = window_freq[1] - window_freq[0]
                click_freq = ((float(click_pos) / float(plot_window_width)) * float(window_bw)) + window_freq[0]
                index = find_nearest_index(click_freq, trace.freq_range)
                marker.data_index = index

    def initUI(self):
        grid = QtGui.QGridLayout()
        grid.setSpacing(10)
        self.plot_width = 8

        for x in range(self.plot_width):
            grid.setColumnMinimumWidth(x, 300)

        grid.addWidget(self._plot_layout(), 0, 0, 13, self.plot_width)

        self.marker_labels = []
        marker_label, delta_label, diff_label = self._marker_labels()
        self.marker_labels.append(marker_label)
        self.marker_labels.append(delta_label)
        grid.addWidget(marker_label, 0, 1, 1, 2)
        grid.addWidget(delta_label, 0, 3, 1, 2)
        grid.addWidget(diff_label, 0, 5, 1, 2)

        y = 0
        x = self.plot_width
        controls_layout = QtGui.QVBoxLayout()

        controls_layout.addWidget(self._freq_controls())
        controls_layout.addWidget(self._amplitude_controls())
        controls_layout.addWidget(self._device_controls())
        controls_layout.addWidget(self._trace_controls())
        controls_layout.addStretch()
        grid.addLayout(controls_layout, y, x, 13, 5)

        self._grid = grid
        self.setLayout(grid)

    def _plot_layout(self):
        vsplit = QtGui.QSplitter()
        vsplit.setOrientation(QtCore.Qt.Vertical)
        vsplit.addWidget(self._plot.window)
        if self._plot.waterfall_window:
            vsplit.addWidget(self._plot.waterfall_window)

        hsplit = QtGui.QSplitter()
        hsplit.addWidget(self._plot.const_window)
        hsplit.addWidget(self._plot.iq_window)
        self._plot.const_window.hide()
        self._plot.iq_window.hide()
        vsplit.addWidget(hsplit)

        self._plot_layout = vsplit
        return self._plot_layout

    def _freq_controls(self):
        self._freq_group = FrequencyControls(self.controller)
        self.control_widgets.append(self._freq_group)
        return self._freq_group

    def _amplitude_controls(self):
        self._amplitude_group = AmplitudeControls(self.controller, self._plot)
        self.control_widgets.append(self._amplitude_group)
        return self._amplitude_group

    def _trace_controls(self):
        self.trace_group = TraceControls(self.controller, self._plot)
        self.control_widgets.append(self.trace_group)
        return self.trace_group

    def _dsp_controls(self):
        self._dsp_group = DSPWidget()
        self.control_widgets.append(self._dsp_group)
        return self._dsp_group

    def _device_controls(self):
        self._dev_group = DeviceControls(self.controller)
        self.control_widgets.append(self._dev_group)
        return self._dev_group

    def _marker_labels(self):
        marker_label = QtGui.QLabel("")
        marker_label.setStyleSheet("color: %s;" % colors.TEAL)
        marker_label.setMinimumHeight(25)

        delta_label = QtGui.QLabel("")
        delta_label.setStyleSheet("color: %s;" % colors.TEAL)
        delta_label.setMinimumHeight(25)

        diff_label = QtGui.QLabel("")
        diff_label.setStyleSheet("color: %s;" % colors.WHITE)
        diff_label.setMinimumHeight(25)
        self._diff_lab = diff_label
        return marker_label, delta_label, diff_label

    def capture_received(self, state, fstart, fstop, raw, power, usable, segments):
        """
        :param state: SpecAState when capture was requested
        :param fstart: lowest frequency included in data in Hz
        :param fstop: highest frequency included in data in Hz
        :param raw: raw samples (None if not available)
        :param power: power spectrum
        :param usable: usable bins from power (None when sweeping)
        :param segments: bin segments from power (None when not sweeping)
        """
        self.raw_data = raw
        self.pow_data = power
        self.usable_bins = usable
        self.sweep_segments = segments

        self.xdata = np.linspace(fstart, fstop, len(power))

        self.update_trace()
        self.update_marker()
        self.update_diff()
        if not self.controller.applying_user_xrange():
            self._plot.center_view(
                fstart, fstop, self._amplitude_group.get_min_level(), self._amplitude_group.get_ref_level()
            )

        if self.iq_plots_enabled:
            self.update_iq()

        if self.waterfall_plot_enabled:
            if (fstart, fstop, len(power)) != self._waterfall_range:
                self._plot.waterfall_data.reset(self.xdata)
                self._waterfall_range = (fstart, fstop, len(power))
            self._plot.waterfall_data.add_row(power)

    def options_changed(self, options, changed):
        self.iq_plots_enabled = options["iq_plots"]
        self.waterfall_plot_enabled = options["waterfall_plot"]

        if "iq_plots" in changed:
            self._update_iq_plot_visibility()

        ww = self._plot.waterfall_window
        if "waterfall_plot" in changed and ww:
            if options["waterfall_plot"]:
                ww.show()
            else:
                ww.hide()

    def _update_iq_plot_visibility(self):
        if not self.gui_state:
            return
        if self.gui_state.sweeping() or not self.iq_plots_enabled:
            self._plot.const_window.hide()
            self._plot.iq_window.hide()
        else:
            self._plot.const_window.show()
            self._plot.iq_window.show()

        ww = self._plot.waterfall_window
        if ww:
            if self.waterfall_plot_enabled:
                ww.show()
            else:
                ww.hide()

    def update_trace(self):
        for trace in self._plot.traces:
            trace.update_curve(self.xdata, self.pow_data, self.usable_bins, self.sweep_segments)

    def update_iq(self):

        if not self.raw_data:
            return
        trace = self._plot.traces[0]

        if not (trace.write or trace.max_hold or trace.min_hold or trace.store):
            return
        if not trace.store:
            data_pkt = self.raw_data
            trace.raw_packet = self.raw_data
        else:
            data_pkt = trace.raw_packet

        if data_pkt.stream_id == VRT_IFDATA_I14Q14:
            data = data_pkt.data.numpy_array()
            i_data = np.array(data[:, 0], dtype=float) / ZIF_BITS
            q_data = np.array(data[:, 1], dtype=float) / ZIF_BITS
            self._plot.i_curve.setData(i_data)
            self._plot.q_curve.setData(q_data)
            self._plot.const_plot.clear()
            self._plot.const_plot.addPoints(
                x=i_data[0:CONST_POINTS], y=q_data[0:CONST_POINTS], symbol="o", size=1, pen="y", brush="y"
            )

        else:
            data = data_pkt.data.numpy_array()
            i_data = np.array(data, dtype=float)

            if data_pkt.stream_id == VRT_IFDATA_I14:
                i_data = i_data / ZIF_BITS

            elif data_pkt.stream_id == VRT_IFDATA_I24:
                i_data = i_data / (np.mean(i_data)) - 1
            self._plot.i_curve.setData(i_data)

            self._plot.q_curve.clear()

    def update_marker(self):

        for marker, marker_label in zip(self._plot.markers, self.marker_labels):
            if marker.enabled:
                trace = self._plot.traces[marker.trace_index]

                if not trace.blank:
                    marker_label.setStyleSheet(
                        fonts.MARKER_LABEL_FONT % (trace.color[0], trace.color[1], trace.color[2])
                    )

                    marker.update_pos(trace.freq_range, trace.data)
                    marker_text = "Frequency: %0.2f MHz \n Power %0.2f dBm" % (
                        trace.freq_range[marker.data_index] / 1e6,
                        trace.data[marker.data_index],
                    )
                    marker_label.setText(marker_text)

            else:
                marker_label.setText("")

    def update_diff(self):

        num_markers = 0
        traces = []
        data_indices = []
        for marker in self._plot.markers:

            if marker.enabled == True:
                num_markers += 1
                traces.append(self._plot.traces[marker.trace_index])
                data_indices.append(marker.data_index)

        if num_markers == len(labels.MARKERS):
            freq_diff = np.abs(
                (traces[0].freq_range[data_indices[0]] / 1e6) - (traces[1].freq_range[data_indices[1]] / 1e6)
            )

            power_diff = np.abs((traces[0].data[data_indices[0]]) - (traces[1].data[data_indices[1]]))
            self._diff_lab.setStyleSheet(fonts.MARKER_LABEL_FONT % (colors.WHITE_NUM))
            delta_text = "Delta : %0.1f MHz \nDelta %0.2f dB" % (freq_diff, power_diff)
            self._diff_lab.setText(delta_text)
        else:
            self._diff_lab.setText("")

    def enable_controls(self):
        for item in self.control_widgets:
            item.setEnabled(True)

    def disable_controls(self):
        for item in self.control_widgets:
            item.setEnabled(False)
コード例 #4
0
ファイル: gui.py プロジェクト: rwarren/pyrf
class MainPanel(QtGui.QWidget):
    """
    The spectrum view and controls
    """
    def __init__(self, controller,  main_window):
        self.controller = controller
        controller.device_change.connect(self.device_changed)
        controller.state_change.connect(self.state_changed)
        controller.capture_receive.connect(self.capture_received)
        controller.options_change.connect(self.options_changed)

        self._main_window = main_window

        self.ref_level = 0
        self.dut = None
        self.control_widgets = []
        super(MainPanel, self).__init__()
        screen = QtGui.QDesktopWidget().screenGeometry()
        self.setMinimumWidth(MINIMUM_WIDTH)
        self.setMinimumHeight(MINIMUM_HEIGHT)
        self.plot_state = None
        self.gui_state = None
        # plot window
        self._plot = Plot(controller, self)
        self._plot.user_xrange_change.connect(controller.user_xrange_changed)

        self._vrt_context = {}
        self.initUI()
        self.disable_controls()
        self.plot_state = None

        self._waterfall_range = None, None, None

        self.options_changed(controller.get_options(),
            ['iq_plots', 'waterfall_plot', 'persistence_plot'])

    def device_changed(self, dut):
        self.plot_state = gui_config.PlotState(dut.properties)
        self.trace_group.plot_state = self.plot_state
        self.dut_prop = dut.properties

        self.enable_controls()

    def state_changed(self, state, changed):
        """
        signal handler for speca state changes
        :param state: new SpecAState object
        :param changed: list of attribute names changed
        """
        self.gui_state = state
        if 'mode' in changed:
            rfe_mode = state.rfe_mode()
            self._update_iq_plot_visibility()
            self.update_rbw_label()
            if rfe_mode in ('DD', 'IQIN'):
                freq = self.dut_prop.MIN_TUNABLE[rfe_mode]
                full_bw = self.dut_prop.FULL_BW[rfe_mode]

                self._plot.center_view(freq,
                                       full_bw,
                                       self._amplitude_group.get_min_level(),
                                       self._amplitude_group.get_ref_level())
                self._plot.iq_window.setYRange(IQ_PLOT_YMIN[rfe_mode],
                                               IQ_PLOT_YMAX[rfe_mode])
            else:
                freq = state.center
                full_bw = state.span

                self._plot.center_view(freq - full_bw/2,
                                        freq + full_bw/2,
                                       self._amplitude_group.get_min_level(),
                                       self._amplitude_group.get_ref_level())
                self._plot.iq_window.setYRange(IQ_PLOT_YMIN[rfe_mode],
                                        IQ_PLOT_YMAX[rfe_mode])
        if 'device_settings.iq_output_path' in changed:
            if state.device_settings['iq_output_path'] == 'CONNECTOR':
                # remove plots
                self._plot_layout.hide()
                self.hide_labels()
                if self._main_window.isMaximized():
                    self._main_window.showNormal()
                # resize window
                for x in range(self.plot_width):
                    self._grid.setColumnMinimumWidth(x, 0)
                screen = QtGui.QDesktopWidget().screenGeometry()
                self.setMinimumWidth(0)
                self.setMinimumHeight(0)
                self._main_window.setMinimumWidth(0)
                self._main_window.setMinimumHeight(0)
                self.resize(0,0)
                self._main_window.resize(0,0)
            else:
                # show plots
                self._plot_layout.show()
                self.show_labels()
                # resize window
                for x in range(self.plot_width):
                    self._grid.setColumnMinimumWidth(x, 300)
                screen = QtGui.QDesktopWidget().screenGeometry()
                self.setMinimumWidth(MINIMUM_WIDTH)
                self.setMinimumHeight(MINIMUM_HEIGHT)
                WINDOW_WIDTH = max(screen.width() * 0.7, MINIMUM_WIDTH)
                WINDOW_HEIGHT = max(screen.height() * 0.7, MINIMUM_HEIGHT)
                self._main_window.resize(WINDOW_WIDTH,WINDOW_HEIGHT)

        if 'rbw' in changed:
            self.update_rbw_label()

        if 'span' in changed:
            self.update_span_label()

    def show_labels(self):
        self._rbw_label.show()
        self._span_label.show()
        self._diff_label.show()
        self._mask_label.show()
        for m in self.marker_labels:
            m.show()

    def hide_labels(self):
        self._rbw_label.hide()
        self._span_label.hide()
        self._diff_label.hide()
        self._mask_label.hide()
        for m in self.marker_labels:
            m.hide()

    def update_rbw_label(self):
        rfe_mode = self.gui_state.rfe_mode()
        if rfe_mode == 'HDR':
            self._rbw_label.setText("RBW:\n%0.2f Hz" % (self.gui_state.rbw))
        else:
            self._rbw_label.setText("RBW:\n%0.2f KHz" % (self.gui_state.rbw / 1e3))

    def update_span_label(self):
        rfe_mode = self.gui_state.rfe_mode()
        if rfe_mode == 'HDR':
            self._span_label.setText("SPAN:\n%0.2f KHz" % (self.gui_state.span / 1e3))
        else:
            self._span_label.setText("SPAN:\n%0.2f MHz" % (self.gui_state.span/ M))

    def initUI(self):
        grid = QtGui.QGridLayout()
        grid.setSpacing(10)
        self.plot_width = 11

        for x in range(self.plot_width):
            grid.setColumnMinimumWidth(x, 300)

        self._mask_label = QtGui.QLabel()
        self._mask_label.setStyleSheet('background-color: black')

        self.marker_labels = []
        marker_label, delta_label, diff_label, rbw_label, span_label = self._marker_labels()

        grid.addWidget(self._mask_label, 0, 0, 2, self.plot_width)
        grid.addWidget(marker_label, 0, 3, 1, 2)
        grid.addWidget(delta_label, 0, 5, 1, 2)
        grid.addWidget(diff_label , 0, 7, 1, 2)
        grid.addWidget(self._rbw_label, 0, 0, 1, 2)
        grid.addWidget(self._span_label, 0, 9, 1, 2)
        grid.addWidget(self._plot_layout(), 1, 0, 14, self.plot_width)
        y = 0
        x = self.plot_width
        controls_layout = QtGui.QVBoxLayout()

        controls_layout.addWidget(self._freq_controls())
        controls_layout.addWidget(self._amplitude_controls())
        controls_layout.addWidget(self._device_controls())
        controls_layout.addWidget(self._trace_controls())
        controls_layout.addStretch()
        grid.addLayout(controls_layout, y, x, 14, 5)

        self._grid = grid
        self.setLayout(grid)

    def _plot_layout(self):
        vsplit = QtGui.QSplitter()
        vsplit.setOrientation(QtCore.Qt.Vertical)
        vsplit.addWidget(self._plot.window)
        if self._plot.waterfall_window:
            vsplit.addWidget(self._plot.waterfall_window)
        
        persist = QtGui.QHBoxLayout()
        # FIXME: reaching too far into plot..
        persist.addWidget(self._plot.persistence_window.gradient_editor)
        persist.addWidget(self._plot.persistence_window)
        persist_widget = QtGui.QWidget()
        persist_widget.setLayout(persist)
        self.persist_widget = persist_widget
        vsplit.addWidget(persist_widget)

        hsplit = QtGui.QSplitter()
        hsplit.addWidget(self._plot.const_window)
        hsplit.addWidget(self._plot.iq_window)
        self._plot.const_window.hide()
        self._plot.iq_window.hide()
        vsplit.addWidget(hsplit)

        self._plot_layout = vsplit
        return self._plot_layout

    def _freq_controls(self):
        self._freq_group = FrequencyControls(self.controller)
        self.control_widgets.append(self._freq_group)
        return self._freq_group
    
    def _amplitude_controls(self):
        self._amplitude_group = AmplitudeControls(self.controller, self._plot)
        self.control_widgets.append(self._amplitude_group)
        return self._amplitude_group

    def _trace_controls(self):
        self.trace_group = TraceControls(self.controller, self._plot)
        self.control_widgets.append(self.trace_group)
        return self.trace_group

    def _dsp_controls(self):
        self._dsp_group = DSPWidget()
        self.control_widgets.append(self._dsp_group)
        return self._dsp_group

    def _device_controls(self):
        self._dev_group = DeviceControls(self.controller)
        self.control_widgets.append(self._dev_group)
        return self._dev_group

    def _marker_labels(self):

        marker_label = QtGui.QLabel('')
        marker_label.setAlignment(QtCore.Qt.AlignLeft)

        delta_label = QtGui.QLabel('')
        delta_label.setAlignment(QtCore.Qt.AlignLeft)

        span_label = QtGui.QLabel('')
        span_label.setStyleSheet(fonts.MARKER_LABEL_FONT % (colors.BLACK_NUM + colors.GREY_NUM))
        span_label.setAlignment(QtCore.Qt.AlignLeft)

        rbw_label = QtGui.QLabel('')
        rbw_label.setStyleSheet(fonts.MARKER_LABEL_FONT % (colors.BLACK_NUM + colors.GREY_NUM))
        rbw_label.setAlignment(QtCore.Qt.AlignRight)

        diff_label = QtGui.QLabel('')
        diff_label.setAlignment(QtCore.Qt.AlignLeft)
        self._diff_label = diff_label
        self._rbw_label = rbw_label
        self._span_label = span_label
        self.marker_labels.append(marker_label)

        self.marker_labels.append(delta_label)
        return marker_label,delta_label, diff_label, rbw_label, span_label

    def capture_received(self, state, fstart, fstop, raw, power, usable, segments):
        """
        :param state: SpecAState when capture was requested
        :param fstart: lowest frequency included in data in Hz
        :param fstop: highest frequency included in data in Hz
        :param raw: raw samples (None if not available)
        :param power: power spectrum
        :param usable: usable bins from power (None when sweeping)
        :param segments: bin segments from power (None when not sweeping)
        """

        self.raw_data = raw
        self.pow_data = power
        self.usable_bins = usable
        self.sweep_segments = segments

        self.xdata = np.linspace(fstart, fstop, len(power))

        self.update_trace()
        self.update_marker()
        self.update_diff()
        if (not self.controller.applying_user_xrange() and
                not self.controller.get_options()['free_plot_adjustment']):
            self._plot.center_view(fstart,
                                   fstop,
                                   self._amplitude_group.get_min_level(),
                                   self._amplitude_group.get_ref_level())

        if self.iq_plots_enabled:
            self.update_iq()

        if self.waterfall_plot_enabled or self.persistence_plot_enabled:
            if (fstart, fstop, len(power)) != self._waterfall_range:
                self._plot.waterfall_data.reset(self.xdata)
                self._waterfall_range = (fstart, fstop, len(power))
            self._plot.waterfall_data.add_row(power)


    def options_changed(self, options, changed):
        self.iq_plots_enabled = options['iq_plots']
        self.waterfall_plot_enabled = options['waterfall_plot']
        self.persistence_plot_enabled = options['persistence_plot']

        if 'iq_plots' in changed:
            self._update_iq_plot_visibility()

        ww = self._plot.waterfall_window
        if 'waterfall_plot' in changed and ww:
            if self.waterfall_plot_enabled:
                ww.show()
            else:
                ww.hide()

        if 'persistence_plot' in changed:
            self.persist_widget.setVisible(self.persistence_plot_enabled)

    def _update_iq_plot_visibility(self):
        if not self.gui_state:
            return
        if self.gui_state.sweeping() or not self.iq_plots_enabled:
            self._plot.const_window.hide()
            self._plot.iq_window.hide()
        else:
            self._plot.const_window.show()
            self._plot.iq_window.show()

        ww = self._plot.waterfall_window
        if ww:
            if self.waterfall_plot_enabled:
                ww.show()
            else:
                ww.hide()

    def update_trace(self):
        for trace in self._plot.traces:
            trace.update_curve(
                self.xdata,
                self.pow_data,
                self.usable_bins,
                self.sweep_segments)

    def update_iq(self):

        if not self.raw_data:
                return
        trace = self._plot.traces[0]

        if not (trace.write or trace.max_hold or trace.min_hold or trace.store):
            return
        if not trace.store:
            data_pkt = self.raw_data
            trace.raw_packet = self.raw_data
        else:
            data_pkt = trace.raw_packet

        if data_pkt.stream_id == VRT_IFDATA_I14Q14:
            data = data_pkt.data.numpy_array()
            i_data = np.array(data[:,0], dtype=float)/ZIF_BITS
            q_data = np.array(data[:,1], dtype=float)/ZIF_BITS
            self._plot.i_curve.setData(i_data)
            self._plot.q_curve.setData(q_data)
            self._plot.const_plot.clear()
            self._plot.const_plot.addPoints(
                x = i_data[0:CONST_POINTS],
                y = q_data[0:CONST_POINTS],
                symbol = 'o',
                size = 1, pen = 'y',
                brush = 'y')

        else:
            data = data_pkt.data.numpy_array()
            i_data = np.array(data, dtype=float)

            if data_pkt.stream_id == VRT_IFDATA_I14:
                i_data = i_data /ZIF_BITS

            elif data_pkt.stream_id == VRT_IFDATA_I24:
                i_data = i_data / (np.mean(i_data)) - 1
            self._plot.i_curve.setData(i_data)

            self._plot.q_curve.clear()

    def update_marker(self):
            num = 1
            for marker, marker_label in zip(self._plot.markers, self.marker_labels):
                if marker.enabled:
                    trace = self._plot.traces[marker.trace_index]
                    marker_label.show()
                    if not trace.blank:

                        marker_label.setStyleSheet(fonts.MARKER_LABEL_FONT % (colors.BLACK_NUM + marker.draw_color))
                        marker.update_pos(trace.freq_range, trace.data)
                        if self.gui_state.rfe_mode() == 'HDR':
                            marker_text = 'M%d: %0.4f MHz \n %0.2f dBm' % (num, trace.freq_range[marker.data_index]/1e6, 
                                                                           trace.data[marker.data_index])
                        else:
                            marker_text = 'M%d: %0.2f MHz \n %0.2f dBm' % (num, trace.freq_range[marker.data_index]/1e6, 
                                                                                   trace.data[marker.data_index])
                        num += 1
                        marker_label.setText(marker_text)
                        self._mask_label.show()
                else:
                    marker_label.hide()

    def update_diff(self):

        num_markers = 0
        traces = []
        data_indices = []
        for marker in self._plot.markers:

            if marker.enabled == True:
                num_markers += 1
                traces.append(self._plot.traces[marker.trace_index])
                data_indices.append(marker.data_index)

        if num_markers == len(labels.MARKERS):

            self._diff_label.show()

            freq_diff = np.abs((traces[0].freq_range[data_indices[0]]/1e6) - (traces[1].freq_range[data_indices[1]]/1e6))

            power_diff = np.abs((traces[0].data[data_indices[0]]) - (traces[1].data[data_indices[1]]))
            self._diff_label.setStyleSheet(fonts.MARKER_LABEL_FONT % (colors.BLACK_NUM + colors.GREY_NUM))
            if self.gui_state.rfe_mode() == 'HDR':
                delta_text = 'Delta: %0.2f KHz \n %0.2f dB' % (freq_diff * 1000, power_diff )
            else:
                delta_text = 'Delta: %0.1f MHz \n %0.2f dB' % (freq_diff, power_diff )
            self._diff_label.setText(delta_text)
        else:
            self._diff_label.hide()
    def enable_controls(self):
        for item in self.control_widgets:
            item.setEnabled(True)

    def disable_controls(self):
        for item in self.control_widgets:
            item.setEnabled(False)
コード例 #5
0
class MainPanel(QtGui.QWidget):
    """
    The spectrum view and controls
    """
    def __init__(self, controller, main_window):
        self.controller = controller
        controller.device_change.connect(self.device_changed)
        controller.state_change.connect(self.state_changed)
        controller.plot_change.connect(self.plot_changed)
        controller.capture_receive.connect(self.capture_received)
        controller.options_change.connect(self.options_changed)

        self._main_window = main_window

        self.ref_level = 0
        self.dut = None
        self.control_widgets = []
        super(MainPanel, self).__init__()
        screen = QtGui.QDesktopWidget().screenGeometry()
        self.setMinimumWidth(MINIMUM_WIDTH)
        self.setMinimumHeight(MINIMUM_HEIGHT)
        self.plot_state = None
        self.gui_state = None
        # plot window
        self._plot = Plot(controller, self)
        self._plot.user_xrange_change.connect(controller.user_xrange_changed)

        self._vrt_context = {}
        self.initUI()
        self.disable_controls()
        self.plot_state = None

        self._waterfall_range = None, None, None

        self.options_changed(
            controller.get_options(),
            ['iq_plots', 'waterfall_plot', 'persistence_plot'])

    def device_changed(self, dut):
        self.plot_state = gui_config.PlotState(dut.properties)
        self.trace_group.plot_state = self.plot_state
        self.dut_prop = dut.properties
        self.enable_controls()

    def state_changed(self, state, changed):
        """
        signal handler for speca state changes
        :param state: new SpecAState object
        :param changed: list of attribute names changed
        """

        self.gui_state = state
        if 'mode' in changed:
            rfe_mode = state.rfe_mode()
            self._update_iq_plot_visibility()
            self.update_rbw_label()
            if rfe_mode in ('DD', 'IQIN'):
                freq = self.dut_prop.MIN_TUNABLE[rfe_mode]
                full_bw = self.dut_prop.FULL_BW[rfe_mode]

                self._plot.center_view(freq, full_bw)
                self._plot.center_iq_plots()
            else:
                freq = state.center
                full_bw = state.span

                self._plot.center_view(freq - full_bw / 2, freq + full_bw / 2)
                self._plot.center_iq_plots()
        if 'device_settings.iq_output_path' in changed:
            if state.device_settings['iq_output_path'] == 'CONNECTOR':
                # remove plots
                self._plot_layout.hide()
                self.hide_labels()
                if self._main_window.isMaximized():
                    self._main_window.showNormal()
                # resize window
                for x in range(self.plot_width):
                    self._grid.setColumnMinimumWidth(x, 0)
                screen = QtGui.QDesktopWidget().screenGeometry()
                self.setMinimumWidth(0)
                self.setMinimumHeight(0)
                self._main_window.setMinimumWidth(0)
                self._main_window.setMinimumHeight(0)
                self.resize(0, 0)
                self._main_window.resize(0, 0)
            else:
                # show plots
                self._plot_layout.show()
                self.show_labels()
                # resize window
                for x in range(self.plot_width):
                    self._grid.setColumnMinimumWidth(x, 300)
                screen = QtGui.QDesktopWidget().screenGeometry()
                self.setMinimumWidth(MINIMUM_WIDTH)
                self.setMinimumHeight(MINIMUM_HEIGHT)
                WINDOW_WIDTH = max(screen.width() * 0.7, MINIMUM_WIDTH)
                WINDOW_HEIGHT = max(screen.height() * 0.7, MINIMUM_HEIGHT)
                self._main_window.resize(WINDOW_WIDTH, WINDOW_HEIGHT)

        if 'rbw' in changed:
            self.update_rbw_label()

        if 'span' in changed:
            self.update_span_label()

    def plot_changed(self, state, changed):
        if 'marker_dragged' in changed:
            self.update_marker_labels()
        self.plot_state = state

    def show_labels(self):
        self._rbw_label.show()
        self._span_label.show()
        self._diff_label.show()
        self._mask_label.show()
        for m in self.marker_labels:
            m.show()
        for c in self.channel_power_labels:
            c.show()

    def hide_labels(self):
        self._rbw_label.hide()
        self._span_label.hide()
        self._diff_label.hide()
        self._mask_label.hide()
        for m in self.marker_labels:
            m.hide()
        for c in self.channel_power_labels:
            c.hide()

    def update_rbw_label(self):
        rfe_mode = self.gui_state.rfe_mode()
        if rfe_mode == 'HDR':
            self._rbw_label.setText("RBW:\n%0.2f Hz" % (self.gui_state.rbw))
        else:
            self._rbw_label.setText("RBW:\n%0.2f KHz" %
                                    (self.gui_state.rbw / 1e3))

    def update_span_label(self):
        rfe_mode = self.gui_state.rfe_mode()
        if rfe_mode == 'HDR':
            self._span_label.setText("SPAN:\n%0.2f KHz" %
                                     (self.gui_state.span / 1e3))
        else:
            self._span_label.setText("SPAN:\n%0.2f MHz" %
                                     (self.gui_state.span / M))

    def initUI(self):
        grid = QtGui.QGridLayout()
        grid.setSpacing(10)
        self.plot_width = 11

        for x in range(self.plot_width):
            grid.setColumnMinimumWidth(x, 300)

        self._mask_label = QtGui.QLabel()
        self._mask_label.setStyleSheet('background-color: black')

        self.marker_labels = []
        marker_label, delta_label, diff_label, rbw_label, span_label = self._marker_labels(
        )
        channel_power_labels = self._channel_power_labels()
        grid.addWidget(self._mask_label, 0, 0, 15, 11)
        grid.addWidget(marker_label, 0, 3, 1, 2)
        grid.addWidget(delta_label, 0, 5, 1, 2)
        grid.addWidget(diff_label, 0, 7, 1, 2)
        grid.addWidget(self._rbw_label, 0, 0, 1, 2)
        grid.addWidget(self._span_label, 0, 9, 1, 2)
        grid.addWidget(self._plot_layout(), 1, 0, 14, self.plot_width)
        x = 2
        for label in channel_power_labels:
            grid.addWidget(label, 1, x, 1, 2)
            x += 3

        self._add_docking_controls(self._freq_controls(), "Frequency Control")
        self._add_docking_controls(self._measurement_controls(),
                                   "Measurement Control")
        self._add_docking_controls(self._capture_controls(), "Capture Control")
        self._add_docking_controls(self._amplitude_controls(),
                                   "Amplitude Control")
        self._add_docking_controls(self._device_controls(), "Device Control")
        self._add_docking_controls(self._trace_controls(), "Trace Control")

        self._grid = grid
        self.setLayout(grid)

    def _add_docking_controls(self, widget, title):
        dock = QtGui.QDockWidget(title, self)
        dock.setAllowedAreas(QtCore.Qt.LeftDockWidgetArea
                             | QtCore.Qt.RightDockWidgetArea)
        dock.setWidget(widget)
        # FIXME we should be doing this in the MainWindow
        self._main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
        self._main_window.view_menu.addAction(dock.toggleViewAction())

    def _plot_layout(self):
        vsplit = QtGui.QSplitter()
        vsplit.setOrientation(QtCore.Qt.Vertical)
        vsplit.addWidget(self._plot.spectral_window)

        if self._plot.waterfall_window:
            vsplit.addWidget(self._plot.waterfall_window)

        persist = QtGui.QHBoxLayout()
        # FIXME: reaching too far into plot..
        persist.addWidget(self._plot.persistence_window.gradient_editor)
        persist.addWidget(self._plot.persistence_window)
        persist_widget = QtGui.QWidget()
        persist_widget.setLayout(persist)
        self.persist_widget = persist_widget
        vsplit.addWidget(persist_widget)

        hsplit = QtGui.QSplitter()
        hsplit.addWidget(self._plot.const_window)
        hsplit.addWidget(self._plot.iq_window)
        self._plot.const_window.hide()
        self._plot.iq_window.hide()
        vsplit.addWidget(hsplit)

        self._plot_layout = vsplit
        return self._plot_layout

    def _freq_controls(self):
        self._freq_group = FrequencyControls(self.controller)
        self.control_widgets.append(self._freq_group)
        return self._freq_group

    def _amplitude_controls(self):
        self._amplitude_group = AmplitudeControls(self.controller, self._plot)
        self.control_widgets.append(self._amplitude_group)
        return self._amplitude_group

    def _trace_controls(self):
        self.trace_group = TraceControls(self.controller, self._plot)
        self.control_widgets.append(self.trace_group)
        return self.trace_group

    def _measurement_controls(self):
        self.measure_group = MeasurementControls(self.controller)
        self.control_widgets.append(self.measure_group)
        return self.measure_group

    def _capture_controls(self):
        self.capture_group = CaptureControls(self.controller)
        self.control_widgets.append(self.capture_group)
        return self.capture_group

    def _device_controls(self):
        self._dev_group = DeviceControls(self.controller)
        self.control_widgets.append(self._dev_group)
        return self._dev_group

    def _marker_labels(self):
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding,
                                       QtGui.QSizePolicy.Fixed)

        marker_label = QtGui.QLabel('')
        marker_label.setAlignment(QtCore.Qt.AlignLeft)
        marker_label.setSizePolicy(sizePolicy)

        delta_label = QtGui.QLabel('')
        delta_label.setAlignment(QtCore.Qt.AlignLeft)
        delta_label.setSizePolicy(sizePolicy)

        span_label = QtGui.QLabel('')
        span_label.setStyleSheet(fonts.MARKER_LABEL_FONT %
                                 (colors.BLACK_NUM + colors.GREY_NUM))
        span_label.setAlignment(QtCore.Qt.AlignLeft)
        span_label.setSizePolicy(sizePolicy)

        rbw_label = QtGui.QLabel('')
        rbw_label.setStyleSheet(fonts.MARKER_LABEL_FONT %
                                (colors.BLACK_NUM + colors.GREY_NUM))
        rbw_label.setAlignment(QtCore.Qt.AlignRight)
        rbw_label.setSizePolicy(sizePolicy)

        diff_label = QtGui.QLabel('')
        diff_label.setAlignment(QtCore.Qt.AlignLeft)
        diff_label.setSizePolicy(sizePolicy)

        self._diff_label = diff_label
        self._rbw_label = rbw_label
        self._span_label = span_label
        self.marker_labels.append(marker_label)

        self.marker_labels.append(delta_label)
        return marker_label, delta_label, diff_label, rbw_label, span_label

    def _channel_power_labels(self):
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding,
                                       QtGui.QSizePolicy.Fixed)

        self.channel_power_labels = []

        for color in colors.TRACE_COLORS:
            label = QtGui.QLabel('')
            label.setSizePolicy(sizePolicy)
            label.setStyleSheet(fonts.MARKER_LABEL_FONT %
                                (colors.BLACK_NUM + color))
            self.channel_power_labels.append(label)
        return self.channel_power_labels

    def capture_received(self, state, fstart, fstop, raw, power, usable,
                         segments):
        """
        :param state: SpecAState when capture was requested
        :param fstart: lowest frequency included in data in Hz
        :param fstop: highest frequency included in data in Hz
        :param raw: raw samples (None if not available)
        :param power: power spectrum
        :param usable: usable bins from power (None when sweeping)
        :param segments: bin segments from power (None when not sweeping)
        """
        self.raw_data = raw
        self.pow_data = power
        self.usable_bins = usable
        self.sweep_segments = segments

        self.xdata = np.linspace(fstart, fstop, len(power))
        self.update_trace()
        self.update_marker()
        self.update_marker_labels()
        self.update_channel_power()
        if (not self.controller.applying_user_xrange()
                and self.plot_state['mouse_tune']):
            self._plot.center_view(fstart, fstop)

        if self.iq_plots_enabled:
            self.update_iq()

        if self.waterfall_plot_enabled or self.persistence_plot_enabled:
            if (fstart, fstop, len(power)) != self._waterfall_range:
                self._plot.waterfall_data.reset(self.xdata)
                self._waterfall_range = (fstart, fstop, len(power))
            self._plot.waterfall_data.add_row(power)

    def options_changed(self, options, changed):
        self.iq_plots_enabled = options['iq_plots']
        self.waterfall_plot_enabled = options['waterfall_plot']
        self.persistence_plot_enabled = options['persistence_plot']

        if 'iq_plots' in changed:
            self._update_iq_plot_visibility()

        ww = self._plot.waterfall_window
        if 'waterfall_plot' in changed and ww:
            if self.waterfall_plot_enabled:
                ww.show()
            else:
                ww.hide()

        if 'persistence_plot' in changed:
            self.persist_widget.setVisible(self.persistence_plot_enabled)

    def _update_iq_plot_visibility(self):
        if not self.gui_state:
            return
        if self.gui_state.sweeping() or not self.iq_plots_enabled:
            self._plot.const_window.hide()
            self._plot.iq_window.hide()
        else:
            self._plot.const_window.show()
            self._plot.iq_window.show()

        ww = self._plot.waterfall_window
        if ww:
            if self.waterfall_plot_enabled:
                ww.show()
            else:
                ww.hide()

    def update_trace(self):
        for trace in self._plot.traces:
            trace.update_curve(self.xdata, self.pow_data, self.usable_bins,
                               self.sweep_segments)

    def update_iq(self):

        if not self.raw_data:
            return
        self._plot.update_iq_plots(self.raw_data)

    def update_marker(self):
        num = 1
        for marker in self._plot.markers:
            if marker.enabled:
                trace = self._plot.traces[marker.trace_index]
                if not trace.blank:
                    marker.update_pos(trace.freq_range, trace.data)

    def update_marker_labels(self):
        num = 1
        for marker, marker_label in zip(self._plot.markers,
                                        self.marker_labels):
            if marker.enabled:
                trace = self._plot.traces[marker.trace_index]
                marker_label.show()
                if marker.data_index is None:
                    marker.data_index = int(len(trace.data) / 2)
                    marker.update_pos(trace.freq_range, trace.data)
                if not trace.blank:
                    marker_label.setStyleSheet(
                        fonts.MARKER_LABEL_FONT %
                        (colors.BLACK_NUM + marker.draw_color))
                    if self.gui_state.rfe_mode() == 'HDR':
                        marker_text = 'M%d: %0.8f MHz \n %0.2f dBm' % (
                            num, trace.freq_range[marker.data_index] / 1e6,
                            trace.data[marker.data_index])
                    else:
                        marker_text = 'M%d: %0.2f MHz \n %0.2f dBm' % (
                            num, trace.freq_range[marker.data_index] / 1e6,
                            trace.data[marker.data_index])
                    num += 1
                    marker_label.setText(marker_text)
                    self._mask_label.show()
            else:
                marker_label.hide()
        self.update_diff()

    def update_diff(self):

        num_markers = 0
        traces = []
        data_indices = []
        for marker in self._plot.markers:

            if marker.enabled == True:
                num_markers += 1
                traces.append(self._plot.traces[marker.trace_index])
                data_indices.append(marker.data_index)

        if num_markers == len(labels.MARKERS):

            self._diff_label.show()

            freq_diff = np.abs((traces[0].freq_range[data_indices[0]] / 1e6) -
                               (traces[1].freq_range[data_indices[1]] / 1e6))

            power_diff = np.abs((traces[0].data[data_indices[0]]) -
                                (traces[1].data[data_indices[1]]))
            self._diff_label.setStyleSheet(
                fonts.MARKER_LABEL_FONT % (colors.BLACK_NUM + colors.GREY_NUM))
            if self.gui_state.rfe_mode() == 'HDR':
                delta_text = 'Delta: %0.8f KHz \n %0.2f dB' % (
                    freq_diff * 1000, power_diff)
            else:
                delta_text = 'Delta: %0.1f MHz \n %0.2f dB' % (freq_diff,
                                                               power_diff)
            self._diff_label.setText(delta_text)
        else:
            self._diff_label.hide()

    def update_channel_power(self):

        for label, trace in zip(self.channel_power_labels, self._plot.traces):
            if trace.calc_channel_power and not trace.blank:
                label.setStyleSheet(fonts.MARKER_LABEL_FONT %
                                    (colors.BLACK_NUM + trace.color))
                label.setText(
                    ("Channel Power: %0.2f dBm" % trace.channel_power))
            else:
                label.setText('')

    def enable_controls(self):
        for item in self.control_widgets:
            item.setEnabled(True)

    def disable_controls(self):
        for item in self.control_widgets:
            item.setEnabled(False)
コード例 #6
0
ファイル: gui.py プロジェクト: jgobuyan/pyrf
class MainPanel(QtGui.QWidget):
    """
    The spectrum view and controls
    """
    def __init__(self, controller,  main_window):
        self.controller = controller
        controller.device_change.connect(self.device_changed)
        controller.state_change.connect(self.state_changed)
        controller.plot_change.connect(self.plot_changed)
        controller.capture_receive.connect(self.capture_received)
        controller.options_change.connect(self.options_changed)

        self._main_window = main_window

        self.ref_level = 0
        self.dut = None
        self.control_widgets = []
        super(MainPanel, self).__init__()
        screen = QtGui.QDesktopWidget().screenGeometry()
        self.setMinimumWidth(MINIMUM_WIDTH)
        self.setMinimumHeight(MINIMUM_HEIGHT)
        self.plot_state = None
        self.gui_state = None
        # plot window
        self._plot = Plot(controller, self)
        self._plot.user_xrange_change.connect(controller.user_xrange_changed)

        self._vrt_context = {}
        self.initUI()
        self.disable_controls()
        self.plot_state = None

        self._waterfall_range = None, None, None

        self.options_changed(controller.get_options(),
            ['iq_plots', 'waterfall_plot', 'persistence_plot'])

    def device_changed(self, dut):
        self.plot_state = gui_config.PlotState(dut.properties)
        self.trace_group.plot_state = self.plot_state
        self.dut_prop = dut.properties
        self.enable_controls()

    def state_changed(self, state, changed):
        """
        signal handler for speca state changes
        :param state: new SpecAState object
        :param changed: list of attribute names changed
        """

        self.gui_state = state
        if 'mode' in changed:
            rfe_mode = state.rfe_mode()
            self._update_iq_plot_visibility()
            self.update_rbw_label()
            if rfe_mode in ('DD', 'IQIN'):
                freq = self.dut_prop.MIN_TUNABLE[rfe_mode]
                full_bw = self.dut_prop.FULL_BW[rfe_mode]

                self._plot.center_view(freq,
                                       full_bw)
                self._plot.center_iq_plots()
            else:
                freq = state.center
                full_bw = state.span

                self._plot.center_view(freq - full_bw/2,
                                        freq + full_bw/2)
                self._plot.center_iq_plots()
        if 'device_settings.iq_output_path' in changed:
            if state.device_settings['iq_output_path'] == 'CONNECTOR':
                # remove plots
                self._plot_layout.hide()
                self.hide_labels()
                if self._main_window.isMaximized():
                    self._main_window.showNormal()
                # resize window
                for x in range(self.plot_width):
                    self._grid.setColumnMinimumWidth(x, 0)
                screen = QtGui.QDesktopWidget().screenGeometry()
                self.setMinimumWidth(0)
                self.setMinimumHeight(0)
                self._main_window.setMinimumWidth(0)
                self._main_window.setMinimumHeight(0)
                self.resize(0,0)
                self._main_window.resize(0,0)
            else:
                # show plots
                self._plot_layout.show()
                self.show_labels()
                # resize window
                for x in range(self.plot_width):
                    self._grid.setColumnMinimumWidth(x, 300)
                screen = QtGui.QDesktopWidget().screenGeometry()
                self.setMinimumWidth(MINIMUM_WIDTH)
                self.setMinimumHeight(MINIMUM_HEIGHT)
                WINDOW_WIDTH = max(screen.width() * 0.7, MINIMUM_WIDTH)
                WINDOW_HEIGHT = max(screen.height() * 0.7, MINIMUM_HEIGHT)
                self._main_window.resize(WINDOW_WIDTH,WINDOW_HEIGHT)

        if 'rbw' in changed:
            self.update_rbw_label()

        if 'span' in changed:
            self.update_span_label()

    def plot_changed(self, state, changed):
        if 'marker_dragged' in changed:
            self.update_marker_labels()
        self.plot_state = state

    def show_labels(self):
        self._rbw_label.show()
        self._span_label.show()
        self._diff_label.show()
        self._mask_label.show()
        for m in self.marker_labels:
            m.show()
        for c in self.channel_power_labels:
            c.show()

    def hide_labels(self):
        self._rbw_label.hide()
        self._span_label.hide()
        self._diff_label.hide()
        self._mask_label.hide()
        for m in self.marker_labels:
            m.hide()
        for c in self.channel_power_labels:
            c.hide()

    def update_rbw_label(self):
        rfe_mode = self.gui_state.rfe_mode()
        if rfe_mode == 'HDR':
            self._rbw_label.setText("RBW:\n%0.2f Hz" % (self.gui_state.rbw))
        else:
            self._rbw_label.setText("RBW:\n%0.2f KHz" % (self.gui_state.rbw / 1e3))

    def update_span_label(self):
        rfe_mode = self.gui_state.rfe_mode()
        if rfe_mode == 'HDR':
            self._span_label.setText("SPAN:\n%0.2f KHz" % (self.gui_state.span / 1e3))
        else:
            self._span_label.setText("SPAN:\n%0.2f MHz" % (self.gui_state.span/ M))

    def initUI(self):
        grid = QtGui.QGridLayout()
        grid.setSpacing(10)
        self.plot_width = 11

        for x in range(self.plot_width):
            grid.setColumnMinimumWidth(x, 300)

        self._mask_label = QtGui.QLabel()
        self._mask_label.setStyleSheet('background-color: black')

        self.marker_labels = []
        marker_label, delta_label, diff_label, rbw_label, span_label = self._marker_labels()
        channel_power_labels = self._channel_power_labels()
        grid.addWidget(self._mask_label, 0, 0, 15, 11)
        grid.addWidget(marker_label, 0, 3, 1, 2)
        grid.addWidget(delta_label, 0, 5, 1, 2)
        grid.addWidget(diff_label , 0, 7, 1, 2)
        grid.addWidget(self._rbw_label, 0, 0, 1, 2)
        grid.addWidget(self._span_label, 0, 9, 1, 2)
        grid.addWidget(self._plot_layout(), 1, 0, 14, self.plot_width)
        x = 2
        for label in channel_power_labels:
            grid.addWidget(label, 1, x, 1, 2)
            x += 3

        self._add_docking_controls(self._freq_controls(), "Frequency Control")
        self._add_docking_controls(
            self._measurement_controls(), "Measurement Control")
        self._add_docking_controls(
            self._capture_controls(), "Capture Control")
        self._add_docking_controls(
            self._amplitude_controls(), "Amplitude Control")
        self._add_docking_controls(self._device_controls(), "Device Control")
        self._add_docking_controls(self._trace_controls(), "Trace Control")

        self._grid = grid
        self.setLayout(grid)

    def _add_docking_controls(self, widget, title):
        dock = QtGui.QDockWidget(title, self)
        dock.setAllowedAreas(
            QtCore.Qt.LeftDockWidgetArea | QtCore.Qt.RightDockWidgetArea)
        dock.setWidget(widget)
        # FIXME we should be doing this in the MainWindow
        self._main_window.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
        self._main_window.view_menu.addAction(dock.toggleViewAction())

    def _plot_layout(self):
        vsplit = QtGui.QSplitter()
        vsplit.setOrientation(QtCore.Qt.Vertical)
        vsplit.addWidget(self._plot.spectral_window)

        if self._plot.waterfall_window:
            vsplit.addWidget(self._plot.waterfall_window)
        
        persist = QtGui.QHBoxLayout()
        # FIXME: reaching too far into plot..
        persist.addWidget(self._plot.persistence_window.gradient_editor)
        persist.addWidget(self._plot.persistence_window)
        persist_widget = QtGui.QWidget()
        persist_widget.setLayout(persist)
        self.persist_widget = persist_widget
        vsplit.addWidget(persist_widget)

        hsplit = QtGui.QSplitter()
        hsplit.addWidget(self._plot.const_window)
        hsplit.addWidget(self._plot.iq_window)
        self._plot.const_window.hide()
        self._plot.iq_window.hide()
        vsplit.addWidget(hsplit)

        self._plot_layout = vsplit
        return self._plot_layout

    def _freq_controls(self):
        self._freq_group = FrequencyControls(self.controller)
        self.control_widgets.append(self._freq_group)
        return self._freq_group

    def _amplitude_controls(self):
        self._amplitude_group = AmplitudeControls(self.controller, self._plot)
        self.control_widgets.append(self._amplitude_group)
        return self._amplitude_group

    def _trace_controls(self):
        self.trace_group = TraceControls(self.controller, self._plot)
        self.control_widgets.append(self.trace_group)
        return self.trace_group

    def _measurement_controls(self):
        self.measure_group = MeasurementControls(self.controller)
        self.control_widgets.append(self.measure_group)
        return self.measure_group

    def _capture_controls(self):
        self.capture_group = CaptureControls(self.controller)
        self.control_widgets.append(self.capture_group)
        return self.capture_group

    def _device_controls(self):
        self._dev_group = DeviceControls(self.controller)
        self.control_widgets.append(self._dev_group)
        return self._dev_group

    def _marker_labels(self):
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Fixed)

        marker_label = QtGui.QLabel('')
        marker_label.setAlignment(QtCore.Qt.AlignLeft)
        marker_label.setSizePolicy(sizePolicy)

        delta_label = QtGui.QLabel('')
        delta_label.setAlignment(QtCore.Qt.AlignLeft)
        delta_label.setSizePolicy(sizePolicy)

        span_label = QtGui.QLabel('')
        span_label.setStyleSheet(fonts.MARKER_LABEL_FONT % (colors.BLACK_NUM + colors.GREY_NUM))
        span_label.setAlignment(QtCore.Qt.AlignLeft)
        span_label.setSizePolicy(sizePolicy)

        rbw_label = QtGui.QLabel('')
        rbw_label.setStyleSheet(fonts.MARKER_LABEL_FONT % (colors.BLACK_NUM + colors.GREY_NUM))
        rbw_label.setAlignment(QtCore.Qt.AlignRight)
        rbw_label.setSizePolicy(sizePolicy)

        diff_label = QtGui.QLabel('')
        diff_label.setAlignment(QtCore.Qt.AlignLeft)
        diff_label.setSizePolicy(sizePolicy)

        self._diff_label = diff_label
        self._rbw_label = rbw_label
        self._span_label = span_label
        self.marker_labels.append(marker_label)

        self.marker_labels.append(delta_label)
        return marker_label,delta_label, diff_label, rbw_label, span_label

    def _channel_power_labels(self):
        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.MinimumExpanding, QtGui.QSizePolicy.Fixed)

        self.channel_power_labels = []

        for color in colors.TRACE_COLORS:
            label = QtGui.QLabel('')
            label.setSizePolicy(sizePolicy)
            label.setStyleSheet(fonts.MARKER_LABEL_FONT % (colors.BLACK_NUM + color))
            self.channel_power_labels.append(label)
        return self.channel_power_labels

    def capture_received(self, state, fstart, fstop, raw, power, usable, segments):
        """
        :param state: SpecAState when capture was requested
        :param fstart: lowest frequency included in data in Hz
        :param fstop: highest frequency included in data in Hz
        :param raw: raw samples (None if not available)
        :param power: power spectrum
        :param usable: usable bins from power (None when sweeping)
        :param segments: bin segments from power (None when not sweeping)
        """
        self.raw_data = raw
        self.pow_data = power
        self.usable_bins = usable
        self.sweep_segments = segments

        self.xdata = np.linspace(fstart, fstop, len(power))
        self.update_trace()
        self.update_marker()
        self.update_marker_labels()
        self.update_channel_power()
        if (not self.controller.applying_user_xrange() and self.plot_state['mouse_tune']):
            self._plot.center_view(fstart,
                                   fstop)

        if self.iq_plots_enabled:
            self.update_iq()

        if self.waterfall_plot_enabled or self.persistence_plot_enabled:
            if (fstart, fstop, len(power)) != self._waterfall_range:
                self._plot.waterfall_data.reset(self.xdata)
                self._waterfall_range = (fstart, fstop, len(power))
            self._plot.waterfall_data.add_row(power)


    def options_changed(self, options, changed):
        self.iq_plots_enabled = options['iq_plots']
        self.waterfall_plot_enabled = options['waterfall_plot']
        self.persistence_plot_enabled = options['persistence_plot']

        if 'iq_plots' in changed:
            self._update_iq_plot_visibility()

        ww = self._plot.waterfall_window
        if 'waterfall_plot' in changed and ww:
            if self.waterfall_plot_enabled:
                ww.show()
            else:
                ww.hide()

        if 'persistence_plot' in changed:
            self.persist_widget.setVisible(self.persistence_plot_enabled)

    def _update_iq_plot_visibility(self):
        if not self.gui_state:
            return
        if self.gui_state.sweeping() or not self.iq_plots_enabled:
            self._plot.const_window.hide()
            self._plot.iq_window.hide()
        else:
            self._plot.const_window.show()
            self._plot.iq_window.show()

        ww = self._plot.waterfall_window
        if ww:
            if self.waterfall_plot_enabled:
                ww.show()
            else:
                ww.hide()

    def update_trace(self):
        for trace in self._plot.traces:
            trace.update_curve(
                self.xdata,
                self.pow_data,
                self.usable_bins,
                self.sweep_segments)

    def update_iq(self):

        if not self.raw_data:
                return
        self._plot.update_iq_plots(self.raw_data)

    def update_marker(self):
            num = 1
            for marker in self._plot.markers:
                if marker.enabled:
                    trace = self._plot.traces[marker.trace_index]
                    if not trace.blank:
                        marker.update_pos(trace.freq_range, trace.data)

    def update_marker_labels(self):
            num = 1
            for marker, marker_label in zip(self._plot.markers, self.marker_labels):
                if marker.enabled:
                    trace = self._plot.traces[marker.trace_index]
                    marker_label.show()
                    if marker.data_index is None:
                        marker.data_index = int(len(trace.data) / 2)
                        marker.update_pos(trace.freq_range, trace.data)
                    if not trace.blank:
                        marker_label.setStyleSheet(fonts.MARKER_LABEL_FONT % (colors.BLACK_NUM + marker.draw_color))
                        if self.gui_state.rfe_mode() == 'HDR':
                            marker_text = 'M%d: %0.8f MHz \n %0.2f dBm' % (num, trace.freq_range[marker.data_index]/1e6, 
                                                                           trace.data[marker.data_index])
                        else:
                            marker_text = 'M%d: %0.2f MHz \n %0.2f dBm' % (num, trace.freq_range[marker.data_index]/1e6, 
                                                                                   trace.data[marker.data_index])
                        num += 1
                        marker_label.setText(marker_text)
                        self._mask_label.show()
                else:
                    marker_label.hide()
            self.update_diff()

    def update_diff(self):

        num_markers = 0
        traces = []
        data_indices = []
        for marker in self._plot.markers:

            if marker.enabled == True:
                num_markers += 1
                traces.append(self._plot.traces[marker.trace_index])
                data_indices.append(marker.data_index)

        if num_markers == len(labels.MARKERS):

            self._diff_label.show()

            freq_diff = np.abs((traces[0].freq_range[data_indices[0]]/1e6) - (traces[1].freq_range[data_indices[1]]/1e6))

            power_diff = np.abs((traces[0].data[data_indices[0]]) - (traces[1].data[data_indices[1]]))
            self._diff_label.setStyleSheet(fonts.MARKER_LABEL_FONT % (colors.BLACK_NUM + colors.GREY_NUM))
            if self.gui_state.rfe_mode() == 'HDR':
                delta_text = 'Delta: %0.8f KHz \n %0.2f dB' % (freq_diff * 1000, power_diff )
            else:
                delta_text = 'Delta: %0.1f MHz \n %0.2f dB' % (freq_diff, power_diff )
            self._diff_label.setText(delta_text)
        else:
            self._diff_label.hide()

    def update_channel_power(self):

        for label, trace in zip(self.channel_power_labels, self._plot.traces):
            if trace.calc_channel_power and not trace.blank:
                label.setStyleSheet(fonts.MARKER_LABEL_FONT % (colors.BLACK_NUM + trace.color))
                label.setText(("Channel Power: %0.2f dBm" % trace.channel_power))
            else:
                label.setText('')

    def enable_controls(self):
        for item in self.control_widgets:
            item.setEnabled(True)


    def disable_controls(self):
        for item in self.control_widgets:
            item.setEnabled(False)