示例#1
0
    def add_canvas(self):
        layout_v = QVBoxLayout()
        is_image = self.plot_typ == 'image'
        canvas_settings = {
            'parent': self,
            'no_grid': is_image,
            'plot_type': self.plot_typ,
        }
        self.canvas = MplCanvasWidget(**canvas_settings)
        self._canvas_list.append(self.canvas)
        self._plot_ref.append(None)
        self._mean_ref.append(None)
        self._median_ref.append(None)

        if self.twin_container is not None and not is_image:
            self.twin_canvas = MplCanvasWidget(**canvas_settings, is_twin=True)
            self._canvas_list.append(self.twin_canvas)
            self.twin_container.add_to_layout(self.plot_typ, self.twin_canvas)
            self._plot_ref.append(None)
            self._mean_ref.append(None)
            self._median_ref.append(None)
        else:
            self.twin_canvas = None

        toolbar = NavigationToolbar(self.canvas.mpl_canvas, self)
        toolbar.actions()[0].triggered.connect(self.force_update)

        layout_v.addWidget(toolbar)
        layout_v.addWidget(self.canvas, stretch=1)

        self.layout_canvas.addLayout(layout_v)
示例#2
0
    def __createFigure(self):
        ##      self.__fig=mpl.figure.Figure(figsize=(8, 5),constrained_layout=True, tight_layout=None)  #单位英寸
        ##      self.__fig=mpl.figure.Figure(figsize=(8, 5))  #单位英寸
        self.__fig = mpl.figure.Figure()
        figCanvas = FigureCanvas(self.__fig)  #创建FigureCanvas对象,必须传递一个Figure对象
        self.__fig.suptitle("suptitle:matplotlib in Qt GUI",
                            fontsize=16,
                            fontweight='bold')  # 总的图标题

        naviToolbar = NavigationToolbar(figCanvas,
                                        self)  #创建NavigationToolbar工具栏
        actList = naviToolbar.actions()  #关联的Action列表
        count = len(actList)  #Action的个数
        lastAction = actList[count - 1]  #最后一个Action

        labCurAxes = QLabel("当前子图")
        naviToolbar.insertWidget(lastAction, labCurAxes)
        self.__comboAxes = QComboBox(self)  #子图列表,用于选择子图
        self.__comboAxes.setToolTip("选择当前子图")
        self.__comboAxes.currentIndexChanged.connect(self.do_currentAxesChaned)
        naviToolbar.insertWidget(lastAction, self.__comboAxes)

        naviToolbar.insertAction(lastAction,
                                 self.ui.actQuit)  #在最后一个Action之前插入一个Action
        ##      naviToolbar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)  #ToolButtonTextUnderIcon
        self.addToolBar(naviToolbar)  #添加作为主窗口工具栏

        splitter = QSplitter(self)
        splitter.setOrientation(Qt.Horizontal)
        splitter.addWidget(self.ui.toolBox)  #左侧控制面板
        splitter.addWidget(figCanvas)  #右侧FigureCanvas对象
        self.setCentralWidget(splitter)
示例#3
0
文件: plotter.py 项目: mfkiwl/DGP
    def get_toolbar(self, parent=None) -> QtWidgets.QToolBar:
        """
        Get a Matplotlib Toolbar for the current plot instance, and set toolbar actions (pan/zoom) specific to this plot.
        Parameters
        ----------
        [parent]
            Optional Qt Parent for this object

        Returns
        -------
        QtWidgets.QToolBar : Matplotlib Qt Toolbar used to control this plot instance
        """
        toolbar = NavigationToolbar(self, parent=parent)
        toolbar.actions()[4].triggered.connect(self.toggle_pan)
        toolbar.actions()[5].triggered.connect(self.toggle_zoom)
        return toolbar
示例#4
0
    def __createFigure(self):  # figure对象为绘图的画布对象,figurecanvas可以放在页面上
        self.__fig = mpl.figure.Figure()
        figCanvas = FigureCanvas(self.__fig)  # 创建FigureCanvas对象,必须传递一个Figure对象
        self.__fig.suptitle("可压性曲线")

        naviToolbar = NavigationToolbar(figCanvas,
                                        self)  # 创建NavigationToolbar工具栏
        actList = naviToolbar.actions()  # 关联的Action列表
        count = len(actList)  # Action的个数
        self.addToolBar(naviToolbar)

        self.ui.layout_curve.addWidget(figCanvas)
class SoundProfileWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)

        self.fig = Figure(tight_layout=True)

        self.canvas = FigureCanvas(self.fig)
        self.toolbar = NavigationToolbar(self.canvas, self)

        unwanted_buttons = ['Subplots', 'Save']
        for action in self.toolbar.actions():
            if action.text() in unwanted_buttons:
                self.toolbar.removeAction(action)

        lay = QVBoxLayout(self)
        lay.addWidget(self.toolbar)
        lay.addWidget(self.canvas)

        self.axe = self.fig.add_subplot(111)
        self.line, *_ = self.axe.plot([])

        self.axe.grid(True, which='major', axis='y', color='r', linewidth=2)
        self.axe.grid(True, which='minor', axis='y')
        self.axe.set_xlabel('time [s]', fontsize=19)
        self.axe.set_ylabel('volume', fontsize=19)

        self.axe.yaxis.set_major_locator(MultipleLocator(0.05))
        self.axe.yaxis.set_major_formatter(FormatStrFormatter('%.2f'))
        self.axe.yaxis.set_minor_locator(MultipleLocator(0.01))

    @Slot(list)
    def update_plot(self, title, x_data, y_data):
        self.fig.suptitle(title, fontsize=25)

        self.line.set_data(x_data, y_data)

        self.axe.set_xlim(0, x_data[-1])
        self.axe.set_ylim(min(y_data), max(0.1, max(y_data) / 2))
        self.canvas.draw()
示例#6
0
    def init_graph(self):
        """Initialize the viewer

        Parameters
        ----------
        self : DXF_Slot
            a DXF_Slot object
        """
        # Init fig
        fig, axes = plt.subplots(tight_layout=False)
        self.fig = fig
        self.axes = axes
        # Set plot layout
        canvas = FigureCanvasQTAgg(fig)
        toolbar = NavigationToolbar(canvas, self)
        # Remove Subplots button
        unwanted_buttons = ["Subplots", "Customize", "Save"]
        for x in toolbar.actions():
            if x.text() in unwanted_buttons:
                toolbar.removeAction(x)
        # Adding custom icon on mpl toobar
        icons_buttons = [
            "Home",
            "Pan",
            "Zoom",
            "Back",
            "Forward",
        ]
        for action in toolbar.actions():
            if action.text(
            ) in icons_buttons and "mpl_" + action.text() in pixmap_dict:
                action.setIcon(QIcon(pixmap_dict["mpl_" + action.text()]))
        # Change default file name
        canvas.get_default_filename = "DXF_slot_visu.png"
        self.layout_plot.insertWidget(1, toolbar)
        self.layout_plot.insertWidget(2, canvas)
        self.canvas = canvas
        axes.set_axis_off()
        self.toolbar = toolbar
        self.xlim = self.axes.get_xlim()
        self.ylim = self.axes.get_ylim()

        def on_draw(event):
            self.xlim = self.axes.get_xlim()
            self.ylim = self.axes.get_ylim()

        # Setup interaction with graph
        def select_line(event):
            """Function to select/unselect the closest line from click"""
            # Ignore if matplotlib action is clicked
            is_ignore = False
            for action in self.toolbar.actions():
                if action.isChecked():
                    is_ignore = True
            if not is_ignore:
                X = event.xdata  # X position of the click
                Y = event.ydata  # Y position of the click
                # Get closer pyleecan object
                Z = X + 1j * Y
                min_dist = float("inf")
                closest_id = -1
                for ii, line in enumerate(self.line_list):
                    line_dist = line.comp_distance(Z)
                    if line_dist < min_dist:
                        closest_id = ii
                        min_dist = line_dist
                # Select/unselect line
                self.selected_list[
                    closest_id] = not self.selected_list[closest_id]
                # Change line color
                point_list = array(self.line_list[closest_id].discretize(20))
                if self.selected_list[closest_id]:
                    color = "r"
                else:
                    color = "k"
                axes.plot(point_list.real, point_list.imag, color, zorder=2)
                self.axes.set_xlim(self.xlim)
                self.axes.set_ylim(self.ylim)
                self.canvas.draw()

        def zoom(event):
            """Function to zoom/unzoom according the mouse wheel"""

            base_scale = 0.8  # Scaling factor
            # get the current x and y limits
            ax = self.axes
            cur_xlim = ax.get_xlim()
            cur_ylim = ax.get_ylim()
            cur_xrange = (cur_xlim[1] - cur_xlim[0]) * 0.5
            cur_yrange = (cur_ylim[1] - cur_ylim[0]) * 0.5
            xdata = event.xdata  # get event x location
            ydata = event.ydata  # get event y location
            if event.button == "down":
                # deal with zoom in
                scale_factor = 1 / base_scale
            elif event.button == "up":
                # deal with zoom out
                scale_factor = base_scale
            else:
                # deal with something that should never happen
                scale_factor = 1
            # set new limits
            ax.set_xlim([
                xdata - cur_xrange * scale_factor,
                xdata + cur_xrange * scale_factor
            ])
            ax.set_ylim([
                ydata - cur_yrange * scale_factor,
                ydata + cur_yrange * scale_factor
            ])
            self.canvas.draw()  # force re-draw

        # Connect the function
        self.canvas.mpl_connect("draw_event", on_draw)
        self.canvas.mpl_connect("button_press_event", select_line)
        self.canvas.mpl_connect("scroll_event", zoom)

        # Axis cleanup
        axes.axis("equal")
        axes.set_axis_off()
示例#7
0
class Scanner(QMainWindow, Ui_Scanner):
    def __init__(self):
        super(Scanner, self).__init__()
        self.setupUi(self)
        # IP address validator
        rx = QRegExp(
            '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'
        )
        self.addrValue.setValidator(QRegExpValidator(rx, self.addrValue))
        # state variable
        self.idle = True
        # number of samples to show on the plot
        self.xsize = self.xsizeValue.value()
        self.ysize = self.xsizeValue.value()
        self.size = self.xsize * self.ysize
        self.x = np.arange(self.xsize)  #X array for plotting
        self.y = np.arange(self.ysize)  #Y array for plotting
        self.freq = 125.0

        figure = Figure()
        figure.set_facecolor('none')
        self.axes = figure.add_subplot(111)
        self.canvas = FigureCanvas(figure)
        self.plotLayout.addWidget(self.canvas)
        self.change_scan_size()
        self.plotLayout.addWidget(self.toolbar)

        # create TCP socket
        self.socket = QTcpSocket(self)
        self.socket.connected.connect(self.connected)
        self.socket.readyRead.connect(self.read_data)
        self.socket.error.connect(self.display_error)
        # connect signals from buttons and boxes
        self.connectButton.clicked.connect(self.start)
        self.scanButton.clicked.connect(self.scan)
        self.periodValue.valueChanged.connect(self.set_period)
        self.trgtimeValue.valueChanged.connect(self.set_trgtime)
        self.trginvCheck.stateChanged.connect(self.set_trginv)
        self.shdelayValue.valueChanged.connect(self.set_shdelay)
        self.shtimeValue.valueChanged.connect(self.set_shtime)
        self.shinvCheck.stateChanged.connect(self.set_shinv)
        self.acqdelayValue.valueChanged.connect(self.set_acqdelay)
        self.samplesValue.valueChanged.connect(self.set_samples)
        self.pulsesValue.valueChanged.connect(self.set_pulses)
        self.xsizeValue.valueChanged.connect(self.set_xsize)
        self.ysizeValue.valueChanged.connect(self.set_ysize)

        # create timers
        self.startTimer = QTimer(self)
        self.startTimer.timeout.connect(self.timeout)
        self.meshTimer = QTimer(self)
        self.meshTimer.timeout.connect(self.update_mesh)
        # set default values
        self.periodValue.setValue(200.0)

    def start(self):
        if self.idle:
            self.connectButton.setEnabled(False)
            self.socket.connectToHost(self.addrValue.text(), 1001)
            self.startTimer.start(5000)
        else:
            self.stop()

    def stop(self):
        self.idle = True
        self.socket.abort()
        self.offset = 0
        self.connectButton.setText('Connect')
        self.connectButton.setEnabled(True)
        self.scanButton.setEnabled(True)

    def timeout(self):
        self.display_error('timeout')

    def connected(self):
        self.startTimer.stop()
        self.idle = False
        self.set_period(self.periodValue.value())
        self.set_trgtime(self.trgtimeValue.value())
        self.set_trginv(self.trginvCheck.checkState())
        self.set_shdelay(self.shdelayValue.value())
        self.set_shtime(self.shtimeValue.value())
        self.set_shinv(self.shinvCheck.checkState())
        self.set_acqdelay(self.acqdelayValue.value())
        self.set_samples(self.samplesValue.value())
        self.set_pulses(self.pulsesValue.value())
        # start pulse generators
        self.socket.write(struct.pack('<I', 11 << 28))
        self.connectButton.setText('Disconnect')
        self.connectButton.setEnabled(True)
        self.scanButton.setEnabled(True)

    def read_data(self):
        size = self.socket.bytesAvailable()
        if self.offset + size < 8 * self.size:
            self.buffer[self.offset:self.offset +
                        size] = self.socket.read(size)
            self.offset += size
#      plt.figure()
#      plt.plot(np.frombuffer(self.buffer,  np.int32)[0::2])
#      plt.show()
        else:
            self.meshTimer.stop()
            self.buffer[self.offset:8 *
                        self.size] = self.socket.read(8 * self.size -
                                                      self.offset)
            self.offset = 0
            self.update_mesh()
            plt.figure()
            plt.plot(self.data[0::2])
            plt.show()
            self.scanButton.setEnabled(True)

    def display_error(self, socketError):
        self.startTimer.stop()
        if socketError == 'timeout':
            QMessageBox.information(self, 'Scanner',
                                    'Error: connection timeout.')
        else:
            QMessageBox.information(self, 'Scanner',
                                    'Error: %s.' % self.socket.errorString())
        self.stop()

    def set_period(self, value):
        # set maximum delays and times to half period
        maximum = int(value * 5.0 + 0.5) / 10.0
        self.trgtimeValue.setMaximum(maximum)
        self.shdelayValue.setMaximum(maximum)
        self.shtimeValue.setMaximum(maximum)
        self.acqdelayValue.setMaximum(maximum)
        # set maximum number of samples per pulse
        maximum = int(value * 500.0 + 0.5) / 10.0
        if maximum > 256.0: maximum = 256.0
        self.samplesValue.setMaximum(maximum)
        shdelay = value * 0.25
        samples = value * 0.5
        if self.idle: return
        self.socket.write(struct.pack('<I', 0 << 28 | int(value * self.freq)))

    def set_trgtime(self, value):
        if self.idle: return
        self.socket.write(struct.pack('<I', 1 << 28 | int(value * self.freq)))

    def set_trginv(self, checked):
        if self.idle: return
        self.socket.write(
            struct.pack('<I', 2 << 28 | int(checked == Qt.Checked)))

    def set_shdelay(self, value):
        if self.idle: return
        self.socket.write(struct.pack('<I', 3 << 28 | int(value * self.freq)))

    def set_shtime(self, value):
        if self.idle: return
        self.socket.write(struct.pack('<I', 4 << 28 | int(value * self.freq)))

    def set_shinv(self, checked):
        if self.idle: return
        self.socket.write(
            struct.pack('<I', 5 << 28 | int(checked == Qt.Checked)))

    def set_acqdelay(self, value):
        if self.idle: return
        self.socket.write(struct.pack('<I', 6 << 28 | int(value * self.freq)))

    def set_samples(self, value):
        if self.idle: return
        self.socket.write(struct.pack('<I', 7 << 28 | int(value)))

    def set_pulses(self, value):
        if self.idle: return
        self.socket.write(struct.pack('<I', 8 << 28 | int(value)))

    def set_xsize(self, value):
        self.xsize = value
        self.size = self.xsize * self.ysize
        self.y = np.arange(self.xsize)
        self.change_scan_size()

    def set_ysize(self, value):
        self.ysize = value
        self.size = self.xsize * self.ysize
        self.y = np.arange(self.ysize)
        self.change_scan_size()

    def change_scan_size(self):
        self.x = np.arange(self.xsize)  #X array for plotting
        self.y = np.arange(self.ysize)  #Y array for plotting

        # buffer and offset for the incoming samples
        self.buffer = bytearray(8 * self.xsize * self.ysize)
        self.offset = 0
        self.data = np.frombuffer(self.buffer, np.int32)
        # create figure
        self.axes.axis((0.0, self.ysize, 0.0, self.xsize))
        x, y = np.meshgrid(np.linspace(0.0, self.ysize, self.ysize + 1),
                           np.linspace(0.0, self.xsize, self.xsize + 1))
        z = x / self.xsize + y * 0.0
        self.mesh = self.axes.pcolormesh(x, y, z, cmap=cm.gray, vmin=0, vmax=1)
        # create navigation toolbar
        self.toolbar = NavigationToolbar(self.canvas, self.plotWidget, False)
        # remove subplots action
        actions = self.toolbar.actions()
        if int(matplotlib.__version__[0]) < 2:
            self.toolbar.removeAction(actions[7])
        else:
            self.toolbar.removeAction(actions[6])
        self.canvas.draw()


#  def set_coordinates(self):
#    if self.idle: return
#    self.socket.write(struct.pack('<I', 9<<28))
#    for i in range(self.xsize):
#      for j in range(self.ysize):
#        value = (i + 0 << 18) | (j << 4)
#        self.socket.write(struct.pack('<I', 10<<28 | int(value)))

    def set_coordinates(self):
        if self.idle: return
        self.socket.write(struct.pack('<I', 9 << 28))
        for i in range(self.xco.size):
            value = (self.xco_prop[i] + 0 << 18) | (self.yco_prop[i] << 4)
            self.socket.write(struct.pack('<I', 10 << 28 | int(value)))

    def scan(self):
        if self.idle: return
        print('start scanning')
        self.scanButton.setEnabled(False)
        scan_name = self.comboBoxScan.currentText()
        xco, yco = spc.LoadScanPattern(scan_name, self.xsize, self.ysize)
        #Change the coordinate such that we scan the full fov
        self.propx = int(np.ceil(512 / (self.xsize)))
        self.propy = int(np.ceil(512 / (self.ysize)))
        self.xco = xco
        self.yco = yco
        self.xco_prop = self.propx * self.xco
        self.yco_prop = self.propy * self.yco
        self.data[:] = np.zeros(2 * self.xsize * self.ysize, np.int32)
        self.update_mesh()
        self.set_coordinates()
        self.socket.write(struct.pack('<I', 12 << 28))
        self.meshTimer.start(500)

    def update_mesh(self):
        result = self.data[0::2] / (self.samplesValue.value() *
                                    self.pulsesValue.value() * 8192.0)
        result = result - np.min(result)
        result = result.reshape(self.xsize, self.ysize)
        result = result[self.x[self.xco], self.y[self.yco]]
        self.mesh.set_array(result.reshape(self.xsize * self.ysize))
        self.mesh.set_clim(vmin=result.min(), vmax=result.max())
        self.canvas.draw()
示例#8
0
    def initUI(self):
        # example dataframe
        df = pd.DataFrame({
            'Sample':
            list(range(1, 11)),
            'Y': [
                9.030, 8.810, 9.402, 8.664, 8.773, 8.774, 8.416, 9.101, 8.687,
                8.767
            ]
        })
        # SPC metrics
        spec_usl = 9.97
        spec_target = 8.70
        spec_lsl = 7.43
        value_mean = df.describe().at['mean', 'Y']

        # spc chart
        fig = plt.figure(dpi=100)
        ax = fig.add_subplot(111, title="SPC Chart Example")
        plt.subplots_adjust(bottom=0.2, left=0.2, right=0.8, top=0.9)
        ax.grid(True)

        # horizontal lines
        ax.axhline(y=spec_usl, linewidth=1, color='red', label='USL')
        ax.axhline(y=spec_target, linewidth=1, color='blue', label='Target')
        ax.axhline(y=spec_lsl, linewidth=1, color='red', label='LSL')
        ax.axhline(y=value_mean, linewidth=1, color='green', label='Avg')

        # trend
        ax.plot(df['Sample'], df['Y'], color="gray", marker="o", markersize=10)
        ax.yaxis.label.set_color('gray')
        ax.tick_params(axis='y', colors='gray')

        # add extra ticks
        extraticks = [spec_lsl, spec_target, spec_usl]
        ax.set_yticks(list(ax.get_yticks()) + extraticks)
        fig.canvas.draw()

        # label
        labels = [item.get_text() for item in ax.get_yticklabels()]
        n = len(labels)
        labels[n - 3] = 'LSL = ' + str(spec_lsl)
        labels[n - 2] = 'Target = ' + str(spec_target)
        labels[n - 1] = 'USL = ' + str(spec_usl)
        ax.set_yticklabels(labels)

        # color
        yticklabels = ax.get_yticklabels()
        n = len(yticklabels)
        yticklabels[n - 3].set_color('red')
        yticklabels[n - 2].set_color('blue')
        yticklabels[n - 1].set_color('red')

        # add second y axis wish same range as first y axis
        ax2 = ax.twinx()
        ax2.set_ylim(ax.get_ylim())
        ax2.tick_params(axis='y', colors='gray')

        # add extra ticks
        extraticks2 = [value_mean]
        ax2.set_yticks(list(ax2.get_yticks()) + extraticks2)
        # fig.canvas.draw(); # no need to update

        # label for second y axis
        labels2 = [item.get_text() for item in ax2.get_yticklabels()]
        n = len(labels2)
        labels2[n - 1] = 'Avg = ' + str(value_mean)
        ax2.set_yticklabels(labels2)

        # color for second y axis
        yticklabels2 = ax2.get_yticklabels()
        n = len(yticklabels2)
        yticklabels2[n - 1].set_color('green')

        canvas = FigureCanvas(fig)
        toolbar = NavigationToolbar(canvas, self)
        # reference: https://stackoverflow.com/questions/55779944/how-to-remove-toolbar-buttons-from-matplotlib
        unwanted_buttons = ['Back', 'Forward']
        for x in toolbar.actions():
            if x.text() in unwanted_buttons:
                toolbar.removeAction(x)
        layout = QVBoxLayout(self)
        layout.addWidget(toolbar)
        layout.addWidget(canvas)
示例#9
0
class Scanner(QMainWindow, Ui_Scanner):
    def __init__(self):
        super(Scanner, self).__init__()
        self.setupUi(self)
        # IP address validator
        rx = QRegExp(
            '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'
        )
        self.addrValue.setValidator(QRegExpValidator(rx, self.addrValue))
        # state variable
        self.idle = True
        # number of samples to show on the plot
        self.size = 512 * 512
        self.freq = 143.0
        # buffer and offset for the incoming samples
        self.buffer = bytearray(8 * self.size)
        self.offset = 0
        self.data = np.frombuffer(self.buffer, np.int32)
        # create figure
        figure = Figure()
        figure.set_facecolor('none')
        self.axes = figure.add_subplot(111)
        self.canvas = FigureCanvas(figure)
        self.plotLayout.addWidget(self.canvas)
        self.axes.axis((0.0, 512.0, 0.0, 512.0))
        x, y = np.meshgrid(np.linspace(0.0, 512.0, 513),
                           np.linspace(0.0, 512.0, 513))
        z = x / 512.0 + y * 0.0
        self.mesh = self.axes.pcolormesh(x, y, z, cmap=cm.plasma)
        # create navigation toolbar
        self.toolbar = NavigationToolbar(self.canvas, self.plotWidget, False)
        # remove subplots action
        actions = self.toolbar.actions()
        if int(matplotlib.__version__[0]) < 2:
            self.toolbar.removeAction(actions[7])
        else:
            self.toolbar.removeAction(actions[6])
        self.plotLayout.addWidget(self.toolbar)
        # create TCP socket
        self.socket = QTcpSocket(self)
        self.socket.connected.connect(self.connected)
        self.socket.readyRead.connect(self.read_data)
        self.socket.error.connect(self.display_error)
        # connect signals from buttons and boxes
        self.connectButton.clicked.connect(self.start)
        self.scanButton.clicked.connect(self.scan)
        self.periodValue.valueChanged.connect(self.set_period)
        self.trgtimeValue.valueChanged.connect(self.set_trgtime)
        self.trginvCheck.stateChanged.connect(self.set_trginv)
        self.shdelayValue.valueChanged.connect(self.set_shdelay)
        self.shtimeValue.valueChanged.connect(self.set_shtime)
        self.shinvCheck.stateChanged.connect(self.set_shinv)
        self.acqdelayValue.valueChanged.connect(self.set_acqdelay)
        self.samplesValue.valueChanged.connect(self.set_samples)
        self.pulsesValue.valueChanged.connect(self.set_pulses)
        # create timers
        self.startTimer = QTimer(self)
        self.startTimer.timeout.connect(self.timeout)
        self.meshTimer = QTimer(self)
        self.meshTimer.timeout.connect(self.update_mesh)
        # set default values
        self.periodValue.setValue(200.0)

    def start(self):
        if self.idle:
            self.connectButton.setEnabled(False)
            self.socket.connectToHost(self.addrValue.text(), 1001)
            self.startTimer.start(5000)
        else:
            self.stop()

    def stop(self):
        self.idle = True
        self.socket.abort()
        self.offset = 0
        self.connectButton.setText('Connect')
        self.connectButton.setEnabled(True)
        self.scanButton.setEnabled(True)

    def timeout(self):
        self.display_error('timeout')

    def connected(self):
        self.startTimer.stop()
        self.idle = False
        self.set_period(self.periodValue.value())
        self.set_trgtime(self.trgtimeValue.value())
        self.set_trginv(self.trginvCheck.checkState())
        self.set_shdelay(self.shdelayValue.value())
        self.set_shtime(self.shtimeValue.value())
        self.set_shinv(self.shinvCheck.checkState())
        self.set_acqdelay(self.acqdelayValue.value())
        self.set_samples(self.samplesValue.value())
        self.set_pulses(self.pulsesValue.value())
        # start pulse generators
        self.socket.write(struct.pack('<I', 9 << 28))
        self.connectButton.setText('Disconnect')
        self.connectButton.setEnabled(True)
        self.scanButton.setEnabled(True)

    def read_data(self):
        size = self.socket.bytesAvailable()
        if self.offset + size < 8 * self.size:
            self.buffer[self.offset:self.offset +
                        size] = self.socket.read(size)
            self.offset += size
        else:
            self.meshTimer.stop()
            self.buffer[self.offset:8 *
                        self.size] = self.socket.read(8 * self.size -
                                                      self.offset)
            self.offset = 0
            self.update_mesh()
            self.scanButton.setEnabled(True)

    def display_error(self, socketError):
        self.startTimer.stop()
        if socketError == 'timeout':
            QMessageBox.information(self, 'Scanner',
                                    'Error: connection timeout.')
        else:
            QMessageBox.information(self, 'Scanner',
                                    'Error: %s.' % self.socket.errorString())
        self.stop()

    def set_period(self, value):
        # set maximum delays and times to half period
        maximum = int(value * 5.0 + 0.5) / 10.0
        self.trgtimeValue.setMaximum(maximum)
        self.shdelayValue.setMaximum(maximum)
        self.shtimeValue.setMaximum(maximum)
        self.acqdelayValue.setMaximum(maximum)
        # set maximum number of samples per pulse
        maximum = int(value * 500.0 + 0.5) / 10.0
        if maximum > 256.0: maximum = 256.0
        self.samplesValue.setMaximum(maximum)
        shdelay = value * 0.25
        samples = value * 0.5
        if self.idle: return
        self.socket.write(struct.pack('<I', 0 << 28 | int(value * self.freq)))

    def set_trgtime(self, value):
        if self.idle: return
        self.socket.write(struct.pack('<I', 1 << 28 | int(value * self.freq)))

    def set_trginv(self, checked):
        if self.idle: return
        self.socket.write(
            struct.pack('<I', 2 << 28 | int(checked == Qt.Checked)))

    def set_shdelay(self, value):
        if self.idle: return
        self.socket.write(struct.pack('<I', 3 << 28 | int(value * self.freq)))

    def set_shtime(self, value):
        if self.idle: return
        self.socket.write(struct.pack('<I', 4 << 28 | int(value * self.freq)))

    def set_shinv(self, checked):
        if self.idle: return
        self.socket.write(
            struct.pack('<I', 5 << 28 | int(checked == Qt.Checked)))

    def set_acqdelay(self, value):
        if self.idle: return
        self.socket.write(struct.pack('<I', 6 << 28 | int(value * self.freq)))

    def set_samples(self, value):
        if self.idle: return
        self.socket.write(struct.pack('<I', 7 << 28 | int(value)))

    def set_pulses(self, value):
        if self.idle: return
        self.socket.write(struct.pack('<I', 8 << 28 | int(value)))

    def scan(self):
        if self.idle: return
        self.scanButton.setEnabled(False)
        self.data[:] = np.zeros(2 * 512 * 512, np.int32)
        self.update_mesh()
        self.socket.write(struct.pack('<I', 10 << 28))
        self.meshTimer.start(1000)

    def update_mesh(self):
        self.mesh.set_array(
            self.data[0::2] /
            (self.samplesValue.value() * self.pulsesValue.value() * 8192.0))
        self.canvas.draw()
示例#10
0
class PyQtScope(QMainWindow, Ui_PyQtScope):

    cursors = {'OFF': 'OFF', 'HBARS': 'AMPLITUDE', 'VBARS': 'TIME'}
    colors = ['orange', 'turquoise']

    def __init__(self):
        super(PyQtScope, self).__init__()
        self.setupUi(self)
        # data buffers
        self.buffer1 = bytearray(2500)
        self.buffer2 = bytearray(2500)
        self.data1 = np.frombuffer(self.buffer1, np.int8)
        self.data2 = np.frombuffer(self.buffer2, np.int8)
        self.format1 = ['0'] * 11
        self.format2 = ['0'] * 11
        # create figure
        self.figure = Figure()
        self.figure.set_facecolor('none')
        self.figure.subplots_adjust(left=0.01,
                                    bottom=0.06,
                                    right=0.99,
                                    top=0.99)
        self.axes = self.figure.add_subplot(111)
        self.canvas = FigureCanvas(self.figure)
        self.plotLayout.addWidget(self.canvas)
        self.curve1, = self.axes.plot(np.zeros(2500), color=self.colors[0])
        self.curve2, = self.axes.plot(np.zeros(2500), color=self.colors[1])
        self.axes.set_xticks(np.arange(0, 2501, 250))
        self.axes.set_yticks(np.arange(-100, 101, 25))
        self.axes.set_xticklabels([])
        self.axes.set_yticklabels([])
        self.axes.grid()
        self.sca1 = None
        self.sca2 = None
        self.scam = None
        # create navigation toolbar
        self.toolbar = NavigationToolbar(self.canvas, self.plotWidget, False)
        # remove subplots action
        actions = self.toolbar.actions()
        self.toolbar.removeAction(actions[7])
        self.plotLayout.addWidget(self.toolbar)
        # connect signals from buttons and boxes
        self.readButton.clicked.connect(self.read_data)
        self.saveButton.clicked.connect(self.save_data)
        # setup USB connection
        self.btag = 0
        self.device = None
        if os.name == 'nt':
            backend = usb.backend.libusb1.get_backend(
                find_library=lambda x: 'libusb-1.0.dll')
            self.device = usb.core.find(idVendor=0x0699,
                                        idProduct=0x0369,
                                        backend=backend)
            while self.device is None:
                reply = QMessageBox.critical(
                    self, 'PyQtScope', 'Cannot access USB device',
                    QMessageBox.Abort | QMessageBox.Retry | QMessageBox.Ignore)
                if reply == QMessageBox.Abort:
                    sys.exit(1)
                elif reply == QMessageBox.Retry:
                    self.device = usb.core.find(idVendor=0x0699,
                                                idProduct=0x0369,
                                                backend=backend)
                else:
                    break
            self.device.set_configuration()
        else:
            try:
                list = glob.glob('/dev/usbtmc*')
                self.device = open(list[0], 'r+b')
            except:
                pass
            while self.device is None:
                reply = QMessageBox.critical(
                    self, 'PyQtScope', 'Cannot access USB device',
                    QMessageBox.Abort | QMessageBox.Retry | QMessageBox.Ignore)
                if reply == QMessageBox.Abort:
                    sys.exit(1)
                elif reply == QMessageBox.Retry:
                    try:
                        list = glob.glob('/dev/usbtmc*')
                        self.device = open(list[0], 'r+b')
                    except:
                        pass
                else:
                    break
        if self.device:
            self.transmit_command(b'DESE 1')
            self.transmit_command(b'*ESE 1')
            self.transmit_command(b'*SRE 32')
            self.transmit_command(b'HEAD 0')
            self.transmit_command(b'DAT INIT')
            self.transmit_command(b'*IDN?')
            print(self.receive_result())

    def transmit_command(self, command):
        if os.name == 'nt':
            size = len(command)
            self.btag = (self.btag % 255) + 1
            data = struct.pack('BBBx', 1, self.btag, ~self.btag & 0xFF)
            data += struct.pack('<LBxxx', size, 1)
            data += command + b'\0' * ((4 - (size % 4)) % 4)
            self.device.write(0x06, data, 1000)
        else:
            self.device.write(command + b'\n')

    def receive_result(self, size=None):
        if os.name == 'nt':
            result = b''
            stop = 0
            while not stop:
                self.btag = (self.btag % 255) + 1
                data = struct.pack('BBBx', 2, self.btag, ~self.btag & 0xFF)
                data += struct.pack('<LBxxx', 1024, 0)
                self.device.write(0x06, data, 1000)
                data = self.device.read(0x85, 1036, 1000).tobytes()
                size, stop = struct.unpack_from('<LBxxx', data, 4)
                result += data[12:size + 12]
        elif size is None:
            result = self.device.readline()
        else:
            result = self.device.read(size)
        return result

    def read_data(self):
        if not self.device: return
        #  0: WFId <Qstring> - description
        #  1: PT_Fmt { ENV | Y } - format
        #  2: XINcr <NR3> - time scale
        #  3: PT_Off <NR1> - always 0
        #  4: XZEro <NR3> - time of the first sample
        #  5: XUNit <QString> - time units
        #  6: YMUlt <NR3> - sample scale
        #  7: YZEro <NR3> - always 0
        #  8: YOFf <NR3> - sample offset
        #  9: YUNit <QString> - sample unit
        # 10: NR_Pt <NR1> - number of points
        # Xn = XZEro + XINcr * n
        # Yn = YZEro + YMUlt * (yn - YOFf)
        progress = QProgressDialog('Data transfer status', 'Cancel', 0, 5)
        progress.setModal(True)
        progress.setMinimumDuration(0)
        try:
            progress.setValue(0)
            # read channel and time scales
            self.transmit_command(b'CH1:SCA?;:CH2:SCA?;:HOR:MAI:SCA?')
            sca = self.receive_result()[:-1].decode('utf-8').rsplit(';')
            if self.sca1:
                self.sca1.remove()
                self.sca1 = None
            self.sca1 = self.figure.text(0.01,
                                         0.01,
                                         'CH1 %sV' %
                                         metric_prefix(float(sca[0])),
                                         color=self.colors[0])
            if self.sca2:
                self.sca2.remove()
                self.sca2 = None
            self.sca2 = self.figure.text(0.31,
                                         0.01,
                                         'CH2 %sV' %
                                         metric_prefix(float(sca[1])),
                                         color=self.colors[1])
            if self.scam:
                self.scam.remove()
                self.scam = None
            self.scam = self.figure.text(
                0.61, 0.01, 'M %ss' % metric_prefix(float(sca[2])))
            progress.setValue(1)
            # read formats
            self.transmit_command(b'WFMPre:CH1?')
            self.format1 = self.receive_result()[:-1].decode('utf-8').rsplit(
                ';')
            self.transmit_command(b'WFMPre:CH2?')
            self.format2 = self.receive_result()[:-1].decode('utf-8').rsplit(
                ';')
            progress.setValue(2)
            # read curves
            self.transmit_command(b'DAT:SOU CH1;:CURV?')
            self.buffer1[:] = self.receive_result(2507)[6:-1]
            self.curve1.set_ydata(self.data1)
            self.transmit_command(b'DAT:SOU CH2;:CURV?')
            self.buffer2[:] = self.receive_result(2507)[6:-1]
            self.curve2.set_ydata(self.data2)
            self.canvas.draw()
            progress.setValue(3)
            # read measurements
            self.transmit_command(
                b'MEASU:MEAS1?;:MEASU:MEAS1:VAL?;:MEASU:MEAS2?;:MEASU:MEAS2:VAL?;:MEASU:MEAS3?;:MEASU:MEAS3:VAL?'
            )
            result = self.receive_result()[:-1] + b';'
            self.transmit_command(
                b'MEASU:MEAS4?;:MEASU:MEAS4:VAL?;:MEASU:MEAS5?;:MEASU:MEAS5:VAL?'
            )
            result += self.receive_result()[:-1]
            meas = result.decode('utf-8').rsplit(';')
            for i in range(0, 5):
                typ = meas[i * 4 + 0]
                uni = meas[i * 4 + 1]
                sou = meas[i * 4 + 2]
                val = meas[i * 4 + 3]
                if typ == 'NONE':
                    val = ''
                    uni = ''
                elif abs(float(val)) > 9.9E9:
                    val = '?'
                    uni = ''
                else:
                    val = metric_prefix(float(meas[i * 4 + 3]))
                    uni = uni.strip('"')
                getattr(self, 'meas%d' % (i + 1)).setText('%s %s %s%s' %
                                                          (sou, typ, val, uni))
            progress.setValue(4)
            # read cursors
            self.transmit_command(
                b'CURS?;:CURS:VBA:HPOS1?;:CURS:VBA:HPOS2?;:CURS:HBA:DELT?;:CURS:VBA:DELT?'
            )
            curs = self.receive_result()[:-1].decode('utf-8').rsplit(';')
            self.curst.setText('%s %s' % (curs[1], self.cursors[curs[0]]))
            if curs[0] == 'VBARS':
                val = float(curs[8])
                if abs(val) > 9.9E9:
                    self.curs1.setText('%ss' % (metric_prefix(float(curs[3]))))
                    self.curs2.setText('')
                else:
                    self.curs1.setText('%ss' % (metric_prefix(float(curs[3]))))
                    self.curs2.setText('%sV' % (metric_prefix(float(curs[8]))))
                val = float(curs[9])
                if abs(val) > 9.9E9:
                    self.curs3.setText('%ss' % (metric_prefix(float(curs[4]))))
                    self.curs4.setText('')
                else:
                    self.curs3.setText('%ss' % (metric_prefix(float(curs[4]))))
                    self.curs4.setText('%sV' % (metric_prefix(float(curs[9]))))
                self.delta.setText('dt = %ss' %
                                   (metric_prefix(float(curs[11]))))
            elif curs[0] == 'HBARS':
                self.curs1.setText('%sV' % metric_prefix(float(curs[6])))
                self.curs2.setText('')
                self.curs3.setText('%sV' % metric_prefix(float(curs[7])))
                self.curs4.setText('')
                self.delta.setText('dV = %sV' %
                                   (metric_prefix(float(curs[10]))))
            else:
                self.curs1.setText('')
                self.curs2.setText('')
                self.curs3.setText('')
                self.curs4.setText('')
                self.delta.setText('')
            progress.setValue(5)
        except:
            print('Error: %s' % sys.exc_info()[1])
            progress.setValue(5)

    def save_data(self):
        dialog = QFileDialog(self, 'Write csv file', '.', '*.csv')
        dialog.setDefaultSuffix('csv')
        dialog.setAcceptMode(QFileDialog.AcceptSave)
        dialog.setOptions(QFileDialog.DontConfirmOverwrite)
        t = np.linspace(0.0, 2499.0, 2500) * float(self.format1[2]) + float(
            self.format1[4])
        ch1 = (self.data1 - float(self.format1[8])) * float(self.format1[6])
        ch2 = (self.data2 - float(self.format2[8])) * float(self.format2[6])
        if dialog.exec() == QDialog.Accepted:
            name = dialog.selectedFiles()
            fh = open(name[0], 'w')
            fh.write('     t          ;     ch1      ;     ch2\n')
            for i in range(0, 2500):
                fh.write('%16.11f;%14.9f;%14.9f\n' % (t[i], ch1[i], ch2[i]))
            fh.close()
示例#11
0
class PlotWidget(QWidget):
    """A wrapper over CanvasWidget to handle additional MOOSE-specific
    stuff.

    modelRoot - path to the entire model our plugin is handling

    dataRoot - path to the container of data tables.

    pathToLine - map from moose path to Line2D objects in plot. Can
    one moose table be plotted multiple times? Maybe yes (e.g., when
    you want multiple other tables to be compared with the same data).

    lineToDataSource - map from Line2D objects to moose paths

    """

    widgetClosedSignal = pyqtSignal(object)
    addGraph = pyqtSignal(object)

    def __init__(self, model, graph, index, parentWidget, *args, **kwargs):
        super(PlotWidget, self).__init__()
        self.model = model
        self.graph = graph
        self.index = index

        self.menu = self.getContextMenu()
        self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.contextMenuRequested)
        #  self.connect( self
        #  , SIGNAL("customContextMenuRequested(QPoint)")
        #  , self
        #  , SLOT("contextMenuRequested(QPoint)")
        #  )

        self.canvas = CanvasWidget(self.model, self.graph, self.index)
        self.canvas.setParent(self)
        self.navToolbar = NavigationToolbar(self.canvas, self)
        self.hackNavigationToolbar()
        self.canvas.mpl_connect('pick_event', self.togglePlot)
        layout = QGridLayout()
        layout.addWidget(self.navToolbar, 0, 0)
        layout.addWidget(self.canvas, 1, 0)
        self.setLayout(layout)
        self.pathToLine = defaultdict(set)
        self.lineToDataSource = {}
        self.axesRef = self.canvas.addSubplot(1, 1)
        self.legend = None
        desktop = QApplication.desktop()
        self.setMinimumSize(desktop.screenGeometry().width() // 4,
                            desktop.screenGeometry().height() // 3)
        self.canvas.updateSignal.connect(self.plotAllData)
        self.plotAllData()

    def hackNavigationToolbar(self):
        # ADD Graph Action
        pixmap = QtGui.QPixmap(
            os.path.join(config.MOOSE_ICON_DIR, 'add_graph.png'))
        icon = QtGui.QIcon(pixmap)
        action = QAction(icon, "Add a graph", self.navToolbar)
        # self.navToolbar.addAction(action)
        action.triggered.connect(self.addGraph.emit)
        self.navToolbar.insertAction(self.navToolbar.actions()[0], action)

        # Delete Graph Action
        pixmap = QtGui.QPixmap(
            os.path.join(config.MOOSE_ICON_DIR, "delete_graph.png"))
        icon = QtGui.QIcon(pixmap)
        action = QAction(icon, "Delete this graph", self.navToolbar)
        action.triggered.connect(self.delete)
        self.navToolbar.insertAction(self.navToolbar.actions()[1], action)

        #Toggle Grid Action
        pixmap = QtGui.QPixmap(os.path.join(config.MOOSE_ICON_DIR, "grid.png"))
        icon = QtGui.QIcon(pixmap)
        action = QAction(icon, "Toggle Grid", self.navToolbar)
        action.triggered.connect(self.canvas.toggleGrid)
        self.navToolbar.insertAction(self.navToolbar.actions()[2], action)
        self.navToolbar.insertSeparator(self.navToolbar.actions()[3])

    @property
    def plotAll(self):
        return len(self.pathToLine) == 0

    def toggleLegend(self):
        if self.legend is not None:
            self.legend.set_visible(not self.legend.get_visible())
        self.canvas.draw()

    def getContextMenu(self):
        menu = QMenu()
        # closeAction      = menu.addAction("Delete")
        exportCsvAction = menu.addAction("Export to CSV")
        exportCsvAction.triggered.connect(self.saveAllCsv)
        toggleLegendAction = menu.addAction("Toggle legend")
        toggleLegendAction.triggered.connect(self.toggleLegend)
        self.removeSubmenu = menu.addMenu("Remove")
        # configureAction.triggered.connect(self.configure)
        # self.connect(,SIGNAL("triggered()"),
        #                 self,SLOT("slotShow500x500()"))
        # self.connect(action1,SIGNAL("triggered()"),
        #                 self,SLOT("slotShow100x100()"))

        return menu

    def deleteGraph(self):
        """ If there is only one graph in the view, please don't delete it """
        print("Deleting %s " % self.graph.path)
        moose.delete(self.graph.path)

    def delete(self, event):
        """FIXME: The last element should not be deleted """
        _logger.info("Deleting PlotWidget ")
        self.deleteGraph()
        self.close()
        self.widgetClosedSignal.emit(self)

    def configure(self, event):
        print("Displaying configure view!")
        self.plotView.getCentralWidget().show()

    @pyqtSlot(QtCore.QPoint)
    def contextMenuRequested(self, point):
        self.menu.exec_(self.mapToGlobal(point))

    def setModelRoot(self, path):
        self.modelRoot = path

    def setDataRoot(self, path):
        self.dataRoot = path
        #plotAllData()

    def genColorMap(self, tableObject):
        species = tableObject + '/info'
        colormap_file = open(
            os.path.join(config.settings[config.KEY_COLORMAP_DIR],
                         'rainbow2.pkl'), 'rb')
        self.colorMap = pickle.load(colormap_file)
        colormap_file.close()
        hexchars = "0123456789ABCDEF"
        color = 'white'
        #Genesis model exist the path and color will be set but not xml file so bypassing
        #print "here genColorMap ",moose.exists(species)
        if moose.exists(species):
            color = moose.element(species).getField('color')
            if ((not isinstance(color, (list, tuple)))):
                if color.isdigit():
                    tc = int(color)
                    tc = (tc * 2)
                    r, g, b = self.colorMap[tc]
                    color = "#" + hexchars[r / 16] + hexchars[
                        r % 16] + hexchars[g / 16] + hexchars[
                            g % 16] + hexchars[b / 16] + hexchars[b % 16]
            else:
                color = 'white'
        return color

    def removePlot(self, table):
        print(("removePlot =>", table))
        moose.delete(table)
        self.plotAllData()

    def makeRemovePlotAction(self, label, table):
        action = self.removeSubmenu.addAction(label)
        action.triggered.connect(lambda: self.removePlot(table))
        return action

    def plotAllData(self):
        """Plot data from existing tables"""
        self.axesRef.lines = []
        self.pathToLine.clear()
        self.removeSubmenu.clear()
        if self.legend is not None:
            self.legend.set_visible(False)
        path = self.model.path
        modelroot = self.model.path
        time = moose.Clock('/clock').currentTime
        tabList = []
        #for tabId in moose.wildcardFind('%s/##[TYPE=Table]' % (path)):
        #harsha: policy graphs will be under /model/modelName need to change in kkit
        #for tabId in moose.wildcardFind('%s/##[TYPE=Table]' % (modelroot)):

        plotTables = list(
            moose.wildcardFind(self.graph.path + '/##[TYPE=Table]'))
        plotTables.extend(
            moose.wildcardFind(self.graph.path + '/##[TYPE=Table2]'))
        if len(plotTables) > 0:
            for tabId in plotTables:
                tab = moose.Table(tabId)
                #print("Table =>", tab)
                line_list = []
                tableObject = tab.neighbors['requestOut']
                # Not a good way
                #tableObject.msgOut[0]
                if len(tableObject) > 0:

                    # This is the default case: we do not plot the same
                    # table twice. But in special cases we want to have
                    # multiple variations of the same table on different
                    # axes.
                    #
                    #Harsha: Adding color to graph for signalling model, check if given path has cubemesh or cylmesh

                    color = '#FFFFFF'
                    if moose.exists(tableObject[0].path + '/info'):
                        color = getColor(tableObject[0].path + '/info')
                        color = str(color[1].name()).upper()

                    lines = self.pathToLine[tab.path]
                    if len(lines) == 0:
                        #Harsha: pass color for plot if exist and not white else random color
                        #print "tab in plotAllData ",tab, tab.path,tab.name
                        field = tab.path.rpartition(".")[-1]
                        if field.endswith("[0]") or field.endswith("_0_"):
                            field = field[:-3]
                        # label = ( tableObject[0].path.partition(self.model.path + "/model[0]/")[-1]
                        #         + "."
                        #         + field
                        #         )
                        label = (tableObject[0].path.rpartition("/")[-1] +
                                 "." + field)
                        self.makeRemovePlotAction(label, tab)
                        if (color != '#FFFFFF'):
                            newLines = self.addTimeSeries(tab,
                                                          label=label,
                                                          color=color)
                        else:
                            newLines = self.addTimeSeries(tab, label=label)
                        self.pathToLine[tab.path].update(newLines)
                        for line in newLines:
                            self.lineToDataSource[line] = PlotDataSource(
                                x='/clock', y=tab.path, z='')
                    else:
                        for line in lines:
                            dataSrc = self.lineToDataSource[line]
                            xSrc = moose.element(dataSrc.x)
                            ySrc = moose.element(dataSrc.y)
                            if isinstance(xSrc, moose.Clock):
                                ts = np.linspace(0, time, len(tab.vector))
                            elif isinstance(xSrc, moose.Table):
                                ts = xSrc.vector.copy()
                            line.set_data(ts, tab.vector.copy())
                    tabList.append(tab)

            # if len(tabList) > 0:
        self.legend = self.canvas.callAxesFn(
            'legend',
            loc='upper right',
            prop={'size': 10}
            # , bbox_to_anchor=(1.0, 0.5)
            ,
            fancybox=True,
            shadow=False,
            ncol=1)
        if self.legend is not None:
            self.legend.draggable()
            self.legend.get_frame().set_alpha(0.5)
            self.legend.set_visible(True)

        self.canvas.draw()

        #     # leg = self.canvas.callAxesFn( 'legend'
        #     #                             , loc               ='upper right'
        #     #                             , prop              = {'size' : 10 }
        #     #                             # , bbox_to_anchor    = (0.5, -0.03)
        #     #                              , fancybox          = False
        #     #                             # , shadow            = True
        #     #                             , ncol              = 1
        #     #                             )
        #     # leg.draggable(False)
        #     # print(leg.get_window_extent())
        #             #leg = self.canvas.callAxesFn('legend')
        #             #leg = self.canvas.callAxesFn('legend',loc='upper left', fancybox=True, shadow=True)
        #             #global legend
        #             #legend =leg
        #     for legobj in leg.legendHandles:
        #         legobj.set_linewidth(5.0)
        #         legobj.set_picker(True)
        # else:
        #     print "returning as len tabId is zero ",tabId, " tableObject ",tableObject, " len ",len(tableObject)

    def togglePlot(self, event):
        #print "onclick",event1.artist.get_label()
        #harsha:To workout with double-event-registered on onclick event
        #http://stackoverflow.com/questions/16278358/double-event-registered-on-mouse-click-if-legend-is-outside-axes
        legline = event.artist
        for line in self.axesRef.lines:
            if line.get_label() == event.artist.get_label():
                vis = not line.get_visible()
                line.set_visible(vis)
                if vis:
                    legline.set_alpha(1.0)
                else:
                    legline.set_alpha(0.2)
                break
        self.canvas.draw()

    def addTimeSeries(self, table, *args, **kwargs):
        ts = np.linspace(0,
                         moose.Clock('/clock').currentTime, len(table.vector))
        return self.canvas.plot(ts, table.vector, *args, **kwargs)

    def addRasterPlot(self, eventtable, yoffset=0, *args, **kwargs):
        """Add raster plot of events in eventtable.

        yoffset - offset along Y-axis.
        """
        y = np.ones(len(eventtable.vector)) * yoffset
        return self.canvas.plot(eventtable.vector, y, '|')

    def updatePlots(self):
        for path, lines in list(self.pathToLine.items()):
            element = moose.element(path)
            if isinstance(element, moose.Table2):
                tab = moose.Table2(path)
            else:
                tab = moose.Table(path)
            data = tab.vector
            ts = np.linspace(0, moose.Clock('/clock').currentTime, len(data))
            for line in lines:
                line.set_data(ts, data)
        self.canvas.draw()

    def extendXAxes(self, xlim):
        for axes in list(self.canvas.axes.values()):
            # axes.autoscale(False, axis='x', tight=True)
            axes.set_xlim(right=xlim)
            axes.autoscale_view(tight=True, scalex=True, scaley=True)
        self.canvas.draw()

    def rescalePlots(self):
        """This is to rescale plots at the end of simulation.

        ideally we should set xlim from simtime.
        """
        for axes in list(self.canvas.axes.values()):
            axes.autoscale(True, tight=True)
            axes.relim()
            axes.autoscale_view(tight=True, scalex=True, scaley=True)
        self.canvas.draw()

    def saveCsv(self, line, directory):
        """Save selected plot data in CSV file"""
        src = self.lineToDataSource[line]
        xSrc = moose.element(src.x)
        ySrc = moose.element(src.y)
        y = ySrc.vector.copy()
        if isinstance(xSrc, moose.Clock):
            x = np.linspace(0, xSrc.currentTime, len(y))
        elif isinstance(xSrc, moose.Table):
            x = xSrc.vector.copy()
        nameVec = ySrc.neighbors['requestOut']
        name = moose.element(nameVec[0]).name
        filename = str(directory) + '/' + '%s.csv' % (name)
        np.savetxt(filename, np.vstack((x, y)).transpose())
        print('Saved data from %s and %s in %s' %
              (xSrc.path, ySrc.path, filename))

    def saveAllCsv(self):
        """Save data for all currently plotted lines"""
        #Harsha: Plots were saved in GUI folder instead provided QFileDialog box to save to
        #user choose
        fileDialog2 = QFileDialog(self)
        fileDialog2.setFileMode(QFileDialog.Directory)
        fileDialog2.setWindowTitle('Select Directory to save plots')
        fileDialog2.setOptions(QFileDialog.ShowDirsOnly)
        fileDialog2.setLabelText(QFileDialog.Accept, self.tr("Save"))
        targetPanel = QFrame(fileDialog2)
        targetPanel.setLayout(QVBoxLayout())
        layout = fileDialog2.layout()
        layout.addWidget(targetPanel)
        if fileDialog2.exec_():
            directory = fileDialog2.directory().path()
            for line in list(self.lineToDataSource.keys()):
                self.saveCsv(line, directory)

    def getMenus(self):
        if not hasattr(self, '_menus'):
            self._menus = []
            self.plotAllAction = QAction('Plot all data', self)
            self.plotAllAction.triggered.connect(self.plotAllData)
            self.plotMenu = QMenu('Plot')
            self.plotMenu.addAction(self.plotAllAction)
            self.saveAllCsvAction = QAction('Save all data in CSV files', self)
            self.saveAllCsvAction.triggered.connect(self.saveAllCsv)
            self.plotMenu.addAction(self.saveAllCsvAction)
            self._menus.append(self.plotMenu)
        return self._menus
示例#12
0
class FigureTab:
  cursors = [15000, 45000]
  colors = ['orange', 'violet']

  def __init__(self, layout, vna):
    # create figure
    self.figure = Figure()
    if sys.platform != 'win32':
      self.figure.set_facecolor('none')
    self.canvas = FigureCanvas(self.figure)
    layout.addWidget(self.canvas)
    # create navigation toolbar
    self.toolbar = NavigationToolbar(self.canvas, None, False)
    self.toolbar.layout().setSpacing(6)
    # remove subplots action
    actions = self.toolbar.actions()
    if int(matplotlib.__version__[0]) < 2:
      self.toolbar.removeAction(actions[7])
    else:
      self.toolbar.removeAction(actions[6])
    self.toolbar.addSeparator()
    self.cursorLabels = {}
    self.cursorValues = {}
    self.cursorMarkers = {}
    self.cursorPressed = {}
    for i in range(len(self.cursors)):
      self.cursorMarkers[i] = None
      self.cursorPressed[i] = False
      self.cursorLabels[i] = QLabel('Cursor %d, kHz' % (i + 1))
      self.cursorLabels[i].setStyleSheet('color: %s' % self.colors[i])
      self.cursorValues[i] = QSpinBox()
      self.cursorValues[i].setMinimumSize(90, 0)
      self.cursorValues[i].setSingleStep(10)
      self.cursorValues[i].setAlignment(Qt.AlignRight | Qt.AlignTrailing | Qt.AlignVCenter)
      self.toolbar.addWidget(self.cursorLabels[i])
      self.toolbar.addWidget(self.cursorValues[i])
      self.cursorValues[i].valueChanged.connect(partial(self.set_cursor, i))
      self.canvas.mpl_connect('button_press_event', partial(self.press_marker, i))
      self.canvas.mpl_connect('motion_notify_event', partial(self.move_marker, i))
      self.canvas.mpl_connect('button_release_event', partial(self.release_marker, i))
    self.toolbar.addSeparator()
    self.plotButton = QPushButton('Rescale')
    self.toolbar.addWidget(self.plotButton)
    layout.addWidget(self.toolbar)
    self.plotButton.clicked.connect(self.plot)
    self.mode = None
    self.vna = vna

  def add_cursors(self, axes):
    if self.mode == 'gain_short' or self.mode == 'gain_open':
      columns = ['Freq., kHz', 'G, dB', r'$\angle$ G, deg']
    else:
      columns = ['Freq., kHz', 'Re(Z), \u03A9', 'Im(Z), \u03A9', '|Z|, \u03A9', r'$\angle$ Z, deg', 'SWR', r'|$\Gamma$|', r'$\angle$ $\Gamma$, deg', 'RL, dB']
    y = len(self.cursors) * 0.04 + 0.01
    for i in range(len(columns)):
      self.figure.text(0.19 + 0.1 * i, y, columns[i], horizontalalignment = 'right')
    self.cursorRows = {}
    for i in range(len(self.cursors)):
      y = len(self.cursors) * 0.04 - 0.03 - 0.04 * i
      self.figure.text(0.01, y, 'Cursor %d' % (i + 1), color = self.colors[i])
      self.cursorRows[i] = {}
      for j in range(len(columns)):
        self.cursorRows[i][j] = self.figure.text(0.19 + 0.1 * j, y, '', horizontalalignment = 'right')
      if self.mode == 'smith':
        self.cursorMarkers[i], = axes.plot(0.0, 0.0, marker = 'o', color = self.colors[i])
      else:
        self.cursorMarkers[i] = axes.axvline(0.0, color = self.colors[i], linewidth = 2)
      self.set_cursor(i, self.cursorValues[i].value())

  def set_cursor(self, index, value):
    FigureTab.cursors[index] = value
    marker = self.cursorMarkers[index]
    if marker is None: return
    row = self.cursorRows[index]
    freq = value
    gamma = self.vna.gamma(freq)
    if self.mode == 'smith':
      marker.set_xdata(gamma.real)
      marker.set_ydata(gamma.imag)
    else:
      marker.set_xdata(freq)
    row[0].set_text('%d' % freq)
    if self.mode == 'gain_short':
      gain = self.vna.gain_short(freq)
      magnitude = 20.0 * np.log10(np.absolute(gain))
      angle = np.angle(gain, deg = True)
      row[1].set_text(unicode_minus('%.1f' % magnitude))
      row[2].set_text(unicode_minus('%.1f' % angle))
    elif self.mode == 'gain_open':
      gain = self.vna.gain_open(freq)
      magnitude = 20.0 * np.log10(np.absolute(gain))
      angle = np.angle(gain, deg = True)
      row[1].set_text(unicode_minus('%.1f' % magnitude))
      row[2].set_text(unicode_minus('%.1f' % angle))
    else:
      swr = self.vna.swr(freq)
      z = self.vna.impedance(freq)
      rl = 20.0 * np.log10(np.absolute(gamma))
      if rl > -0.01: rl = 0.0
      row[1].set_text(metric_prefix(z.real))
      row[2].set_text(metric_prefix(z.imag))
      row[3].set_text(metric_prefix(np.absolute(z)))
      angle = np.angle(z, deg = True)
      if np.abs(angle) < 0.1: angle = 0.0
      row[4].set_text(unicode_minus('%.1f' % angle))
      row[5].set_text(unicode_minus('%.2f' % swr))
      row[6].set_text(unicode_minus('%.2f' % np.absolute(gamma)))
      angle = np.angle(gamma, deg = True)
      if np.abs(angle) < 0.1: angle = 0.0
      row[7].set_text(unicode_minus('%.1f' % angle))
      row[8].set_text(unicode_minus('%.2f' % rl))
    self.canvas.draw()

  def press_marker(self, index, event):
    if not event.inaxes: return
    if self.mode == 'smith': return
    marker = self.cursorMarkers[index]
    if marker is None: return
    contains, misc = marker.contains(event)
    if not contains: return
    self.cursorPressed[index] = True

  def move_marker(self, index, event):
    if not event.inaxes: return
    if self.mode == 'smith': return
    if not self.cursorPressed[index]: return
    self.cursorValues[index].setValue(event.xdata)

  def release_marker(self, index, event):
    self.cursorPressed[index] = False

  def xlim(self, freq):
    start = freq[0]
    stop = freq[-1]
    min = np.minimum(start, stop)
    max = np.maximum(start, stop)
    margin = (max - min) / 50
    return (min - margin, max + margin)

  def plot(self):
    getattr(self, 'plot_%s' % self.mode)()

  def update(self, mode):
    start = self.vna.dut.freq[0]
    stop = self.vna.dut.freq[-1]
    min = np.minimum(start, stop)
    max = np.maximum(start, stop)
    for i in range(len(self.cursors)):
      value = self.cursors[i]
      self.cursorValues[i].setRange(min, max)
      self.cursorValues[i].setValue(value)
      self.set_cursor(i, value)
    getattr(self, 'update_%s' % mode)()

  def plot_curves(self, freq, data1, label1, limit1, data2, label2, limit2):
    matplotlib.rcdefaults()
    matplotlib.rcParams['axes.formatter.use_mathtext'] = True
    self.figure.clf()
    bottom = len(self.cursors) * 0.04 + 0.13
    self.figure.subplots_adjust(left = 0.16, bottom = bottom, right = 0.84, top = 0.96)
    axes1 = self.figure.add_subplot(111)
    axes1.cla()
    axes1.xaxis.grid()
    axes1.set_xlabel('kHz')
    axes1.set_ylabel(label1)
    xlim = self.xlim(freq)
    axes1.set_xlim(xlim)
    if limit1 is not None: axes1.set_ylim(limit1)
    self.curve1, = axes1.plot(freq, data1, color = 'blue', label = label1)
    self.add_cursors(axes1)
    if data2 is None:
      self.canvas.draw()
      return
    axes1.tick_params('y', color = 'blue', labelcolor = 'blue')
    axes1.yaxis.label.set_color('blue')
    axes2 = axes1.twinx()
    axes2.spines['left'].set_color('blue')
    axes2.spines['right'].set_color('red')
    axes2.set_ylabel(label2)
    axes2.set_xlim(xlim)
    if limit2 is not None: axes2.set_ylim(limit2)
    axes2.tick_params('y', color = 'red', labelcolor = 'red')
    axes2.yaxis.label.set_color('red')
    self.curve2, = axes2.plot(freq, data2, color = 'red', label = label2)
    self.canvas.draw()

  def plot_gain(self, gain):
    freq = self.vna.dut.freq
    data1 = 20.0 * np.log10(np.absolute(gain))
    data2 = np.angle(gain, deg = True)
    self.plot_curves(freq, data1, 'G, dB', (-110, 110.0), data2, r'$\angle$ G, deg', (-198, 198))

  def plot_gain_short(self):
    self.mode = 'gain_short'
    self.plot_gain(self.vna.gain_short(self.vna.dut.freq))

  def plot_gain_open(self):
    self.mode = 'gain_open'
    self.plot_gain(self.vna.gain_open(self.vna.dut.freq))

  def update_gain(self, gain, mode):
    if self.mode == mode:
      self.curve1.set_xdata(self.vna.dut.freq)
      self.curve1.set_ydata(20.0 * np.log10(np.absolute(gain)))
      self.curve2.set_xdata(self.vna.dut.freq)
      self.curve2.set_ydata(np.angle(gain, deg = True))
      self.canvas.draw()
    else:
      self.mode = mode
      self.plot_gain(gain)

  def update_gain_short(self):
    self.update_gain(self.vna.gain_short(self.vna.dut.freq), 'gain_short')

  def update_gain_open(self):
    self.update_gain(self.vna.gain_open(self.vna.dut.freq), 'gain_open')

  def plot_magphase(self, freq, data, label, mode):
    self.mode = mode
    data1 = np.absolute(data)
    data2 = np.angle(data, deg = True)
    max = np.fmax(0.01, data1.max())
    label1 = r'|%s|' % label
    label2 = r'$\angle$ %s, deg' % label
    self.plot_curves(freq, data1, label1, (-0.05 * max, 1.05 * max), data2, label2, (-198, 198))

  def update_magphase(self, freq, data, label, mode):
    if self.mode == mode:
      self.curve1.set_xdata(freq)
      self.curve1.set_ydata(np.absolute(data))
      self.curve2.set_xdata(freq)
      self.curve2.set_ydata(np.angle(data, deg = True))
      self.canvas.draw()
    else:
      self.plot_magphase(freq, data, label, mode)

  def plot_open(self):
    self.plot_magphase(self.vna.open.freq, self.vna.open.data, 'open', 'open')

  def update_open(self):
    self.update_magphase(self.vna.open.freq, self.vna.open.data, 'open', 'open')

  def plot_short(self):
    self.plot_magphase(self.vna.short.freq, self.vna.short.data, 'short', 'short')

  def update_short(self):
    self.update_magphase(self.vna.short.freq, self.vna.short.data, 'short', 'short')

  def plot_load(self):
    self.plot_magphase(self.vna.load.freq, self.vna.load.data, 'load', 'load')

  def update_load(self):
    self.update_magphase(self.vna.load.freq, self.vna.load.data, 'load', 'load')

  def plot_dut(self):
    self.plot_magphase(self.vna.dut.freq, self.vna.dut.data, 'dut', 'dut')

  def update_dut(self):
    self.update_magphase(self.vna.dut.freq, self.vna.dut.data, 'dut', 'dut')

  def plot_smith_grid(self, axes, color):
    load = 50.0
    ticks = np.array([0.0, 0.2, 0.5, 1.0, 2.0, 5.0])
    for tick in ticks * load:
      axis = np.logspace(-4, np.log10(1.0e3), 200) * load
      z = tick + 1.0j * axis
      gamma = (z - load)/(z + load)
      axes.plot(gamma.real, gamma.imag, color = color, linewidth = 0.4, alpha = 0.3)
      axes.plot(gamma.real, -gamma.imag, color = color, linewidth = 0.4, alpha = 0.3)
      z = axis + 1.0j * tick
      gamma = (z - load)/(z + load)
      axes.plot(gamma.real, gamma.imag, color = color, linewidth = 0.4, alpha = 0.3)
      axes.plot(gamma.real, -gamma.imag, color = color, linewidth = 0.4, alpha = 0.3)
      if tick == 0.0:
        axes.text(1.0, 0.0, u'\u221E', color = color, ha = 'left', va = 'center', clip_on = True, fontsize = 'x-large')
        axes.text(-1.0, 0.0, u'0\u03A9', color = color, ha = 'left', va = 'bottom', clip_on = True)
        continue
      lab = u'%d\u03A9' % tick
      x = (tick - load) / (tick + load)
      axes.text(x, 0.0, lab, color = color, ha = 'left', va = 'bottom', clip_on = True)
      lab = u'j%d\u03A9' % tick
      z =  1.0j * tick
      gamma = (z - load)/(z + load) * 1.05
      x = gamma.real
      y = gamma.imag
      angle = np.angle(gamma) * 180.0 / np.pi - 90.0
      axes.text(x, y, lab, color = color, ha = 'center', va = 'center', clip_on = True, rotation = angle)
      lab = u'\u2212j%d\u03A9' % tick
      axes.text(x, -y, lab, color = color, ha = 'center', va = 'center', clip_on = True, rotation = -angle)

  def plot_smith(self):
    self.mode = 'smith'
    matplotlib.rcdefaults()
    self.figure.clf()
    bottom = len(self.cursors) * 0.04 + 0.05
    self.figure.subplots_adjust(left = 0.0, bottom = bottom, right = 1.0, top = 1.0)
    axes1 = self.figure.add_subplot(111)
    self.plot_smith_grid(axes1, 'blue')
    gamma = self.vna.gamma(self.vna.dut.freq)
    self.curve1, = axes1.plot(gamma.real, gamma.imag, color = 'red')
    axes1.axis('equal')
    axes1.set_xlim(-1.12, 1.12)
    axes1.set_ylim(-1.12, 1.12)
    axes1.xaxis.set_visible(False)
    axes1.yaxis.set_visible(False)
    for loc, spine in axes1.spines.items():
      spine.set_visible(False)
    self.add_cursors(axes1)
    self.canvas.draw()

  def update_smith(self):
    if self.mode == 'smith':
      gamma = self.vna.gamma(self.vna.dut.freq)
      self.curve1.set_xdata(gamma.real)
      self.curve1.set_ydata(gamma.imag)
      self.canvas.draw()
    else:
      self.plot_smith()

  def plot_imp(self):
    self.mode = 'imp'
    freq = self.vna.dut.freq
    z = self.vna.impedance(freq)
    data1 = np.fmin(9.99e4, np.absolute(z))
    data2 = np.angle(z, deg = True)
    max = np.fmax(0.01, data1.max())
    self.plot_curves(freq, data1, '|Z|, \u03A9', (-0.05 * max, 1.05 * max), data2, r'$\angle$ Z, deg', (-198, 198))

  def update_imp(self):
    if self.mode == 'imp':
      freq = self.vna.dut.freq
      z = self.vna.impedance(freq)
      data1 = np.fmin(9.99e4, np.absolute(z))
      data2 = np.angle(z, deg = True)
      self.curve1.set_xdata(freq)
      self.curve1.set_ydata(data1)
      self.curve2.set_xdata(freq)
      self.curve2.set_ydata(data2)
      self.canvas.draw()
    else:
      self.plot_imp()

  def plot_swr(self):
    self.mode = 'swr'
    freq = self.vna.dut.freq
    data1 = self.vna.swr(freq)
    self.plot_curves(freq, data1, 'SWR', (0.9, 3.1), None, None, None)

  def update_swr(self):
    if self.mode == 'swr':
      self.curve1.set_xdata(self.vna.dut.freq)
      self.curve1.set_ydata(self.vna.swr(self.vna.dut.freq))
      self.canvas.draw()
    else:
      self.plot_swr()

  def plot_gamma(self):
    self.plot_magphase(self.vna.dut.freq, self.vna.gamma(self.vna.dut.freq), r'$\Gamma$', 'gamma')

  def update_gamma(self):
    self.update_magphase(self.vna.dut.freq, self.vna.gamma(self.vna.dut.freq), r'$\Gamma$', 'gamma')

  def plot_rl(self):
    self.mode = 'rl'
    freq = self.vna.dut.freq
    gamma = self.vna.gamma(freq)
    data1 = 20.0 * np.log10(np.absolute(gamma))
    self.plot_curves(freq, data1, 'RL, dB', (-105, 5.0), None, None, None)

  def update_rl(self):
    if self.mode == 'rl':
      freq = self.vna.dut.freq
      gamma = self.vna.gamma(freq)
      data1 = 20.0 * np.log10(np.absolute(gamma))
      self.curve1.set_xdata(freq)
      self.curve1.set_ydata(data1)
      self.canvas.draw()
    else:
      self.plot_rl()
示例#13
0
class FigureTab:
    cursors = [15000, 45000]
    colors = ['orange', 'violet']

    def __init__(self, layout, vna):
        # create figure
        self.figure = Figure()
        if sys.platform != 'win32':
            self.figure.set_facecolor('none')
        self.canvas = FigureCanvas(self.figure)
        layout.addWidget(self.canvas)
        # create navigation toolbar
        self.toolbar = NavigationToolbar(self.canvas, None, False)
        self.toolbar.layout().setSpacing(6)
        # remove subplots action
        actions = self.toolbar.actions()
        if int(matplotlib.__version__[0]) < 2:
            self.toolbar.removeAction(actions[7])
        else:
            self.toolbar.removeAction(actions[6])
        self.toolbar.addSeparator()
        self.cursorLabels = {}
        self.cursorValues = {}
        self.cursorMarkers = {}
        self.cursorPressed = {}
        for i in range(len(self.cursors)):
            self.cursorMarkers[i] = None
            self.cursorPressed[i] = False
            self.cursorLabels[i] = QLabel('Cursor %d, kHz' % (i + 1))
            self.cursorLabels[i].setStyleSheet('color: %s' % self.colors[i])
            self.cursorValues[i] = QSpinBox()
            self.cursorValues[i].setMinimumSize(90, 0)
            self.cursorValues[i].setSingleStep(10)
            self.cursorValues[i].setAlignment(Qt.AlignRight | Qt.AlignTrailing
                                              | Qt.AlignVCenter)
            self.toolbar.addWidget(self.cursorLabels[i])
            self.toolbar.addWidget(self.cursorValues[i])
            self.cursorValues[i].valueChanged.connect(
                partial(self.set_cursor, i))
            self.canvas.mpl_connect('button_press_event',
                                    partial(self.press_marker, i))
            self.canvas.mpl_connect('motion_notify_event',
                                    partial(self.move_marker, i))
            self.canvas.mpl_connect('button_release_event',
                                    partial(self.release_marker, i))
        self.toolbar.addSeparator()
        self.plotButton = QPushButton('Rescale')
        self.toolbar.addWidget(self.plotButton)
        layout.addWidget(self.toolbar)
        self.plotButton.clicked.connect(self.plot)
        self.mode = None
        self.vna = vna

    def add_cursors(self, axes):
        if self.mode == 'gain_short' or self.mode == 'gain_open':
            columns = ['Freq., kHz', 'G, dB', r'$\angle$ G, deg']
        else:
            columns = [
                'Freq., kHz', 'Re(Z), \u03A9', 'Im(Z), \u03A9', '|Z|, \u03A9',
                r'$\angle$ Z, deg', 'SWR', r'|$\Gamma$|',
                r'$\angle$ $\Gamma$, deg', 'RL, dB'
            ]
        y = len(self.cursors) * 0.04 + 0.01
        for i in range(len(columns)):
            self.figure.text(0.19 + 0.1 * i,
                             y,
                             columns[i],
                             horizontalalignment='right')
        self.cursorRows = {}
        for i in range(len(self.cursors)):
            y = len(self.cursors) * 0.04 - 0.03 - 0.04 * i
            self.figure.text(0.01,
                             y,
                             'Cursor %d' % (i + 1),
                             color=self.colors[i])
            self.cursorRows[i] = {}
            for j in range(len(columns)):
                self.cursorRows[i][j] = self.figure.text(
                    0.19 + 0.1 * j, y, '', horizontalalignment='right')
            if self.mode == 'smith':
                self.cursorMarkers[i], = axes.plot(0.0,
                                                   0.0,
                                                   marker='o',
                                                   color=self.colors[i])
            else:
                self.cursorMarkers[i] = axes.axvline(0.0,
                                                     color=self.colors[i],
                                                     linewidth=2)
            self.set_cursor(i, self.cursorValues[i].value())

    def set_cursor(self, index, value):
        FigureTab.cursors[index] = value
        marker = self.cursorMarkers[index]
        if marker is None: return
        row = self.cursorRows[index]
        freq = value
        gamma = self.vna.gamma(freq)
        if self.mode == 'smith':
            marker.set_xdata(gamma.real)
            marker.set_ydata(gamma.imag)
        else:
            marker.set_xdata(freq)
        row[0].set_text('%d' % freq)
        if self.mode == 'gain_short':
            gain = self.vna.gain_short(freq)
            magnitude = 20.0 * np.log10(np.absolute(gain))
            angle = np.angle(gain, deg=True)
            row[1].set_text(unicode_minus('%.1f' % magnitude))
            row[2].set_text(unicode_minus('%.1f' % angle))
        elif self.mode == 'gain_open':
            gain = self.vna.gain_open(freq)
            magnitude = 20.0 * np.log10(np.absolute(gain))
            angle = np.angle(gain, deg=True)
            row[1].set_text(unicode_minus('%.1f' % magnitude))
            row[2].set_text(unicode_minus('%.1f' % angle))
        else:
            swr = self.vna.swr(freq)
            z = self.vna.impedance(freq)
            rl = 20.0 * np.log10(np.absolute(gamma))
            if rl > -0.01: rl = 0.0
            row[1].set_text(metric_prefix(z.real))
            row[2].set_text(metric_prefix(z.imag))
            row[3].set_text(metric_prefix(np.absolute(z)))
            angle = np.angle(z, deg=True)
            if np.abs(angle) < 0.1: angle = 0.0
            row[4].set_text(unicode_minus('%.1f' % angle))
            row[5].set_text(unicode_minus('%.2f' % swr))
            row[6].set_text(unicode_minus('%.2f' % np.absolute(gamma)))
            angle = np.angle(gamma, deg=True)
            if np.abs(angle) < 0.1: angle = 0.0
            row[7].set_text(unicode_minus('%.1f' % angle))
            row[8].set_text(unicode_minus('%.2f' % rl))
        self.canvas.draw()

    def press_marker(self, index, event):
        if not event.inaxes: return
        if self.mode == 'smith': return
        marker = self.cursorMarkers[index]
        if marker is None: return
        contains, misc = marker.contains(event)
        if not contains: return
        self.cursorPressed[index] = True

    def move_marker(self, index, event):
        if not event.inaxes: return
        if self.mode == 'smith': return
        if not self.cursorPressed[index]: return
        self.cursorValues[index].setValue(event.xdata)

    def release_marker(self, index, event):
        self.cursorPressed[index] = False

    def xlim(self, freq):
        start = freq[0]
        stop = freq[-1]
        min = np.minimum(start, stop)
        max = np.maximum(start, stop)
        margin = (max - min) / 50
        return (min - margin, max + margin)

    def plot(self):
        getattr(self, 'plot_%s' % self.mode)()

    def update(self, mode):
        start = self.vna.dut.freq[0]
        stop = self.vna.dut.freq[-1]
        min = np.minimum(start, stop)
        max = np.maximum(start, stop)
        for i in range(len(self.cursors)):
            value = self.cursors[i]
            self.cursorValues[i].setRange(min, max)
            self.cursorValues[i].setValue(value)
            self.set_cursor(i, value)
        getattr(self, 'update_%s' % mode)()

    def plot_curves(self, freq, data1, label1, limit1, data2, label2, limit2):
        matplotlib.rcdefaults()
        matplotlib.rcParams['axes.formatter.use_mathtext'] = True
        self.figure.clf()
        bottom = len(self.cursors) * 0.04 + 0.13
        self.figure.subplots_adjust(left=0.16,
                                    bottom=bottom,
                                    right=0.84,
                                    top=0.96)
        axes1 = self.figure.add_subplot(111)
        axes1.cla()
        axes1.xaxis.grid()
        axes1.set_xlabel('kHz')
        axes1.set_ylabel(label1)
        xlim = self.xlim(freq)
        axes1.set_xlim(xlim)
        if limit1 is not None: axes1.set_ylim(limit1)
        self.curve1, = axes1.plot(freq, data1, color='blue', label=label1)
        self.add_cursors(axes1)
        if data2 is None:
            self.canvas.draw()
            return
        axes1.tick_params('y', color='blue', labelcolor='blue')
        axes1.yaxis.label.set_color('blue')
        axes2 = axes1.twinx()
        axes2.spines['left'].set_color('blue')
        axes2.spines['right'].set_color('red')
        axes2.set_ylabel(label2)
        axes2.set_xlim(xlim)
        if limit2 is not None: axes2.set_ylim(limit2)
        axes2.tick_params('y', color='red', labelcolor='red')
        axes2.yaxis.label.set_color('red')
        self.curve2, = axes2.plot(freq, data2, color='red', label=label2)
        self.canvas.draw()

    def plot_gain(self, gain):
        freq = self.vna.dut.freq
        data1 = 20.0 * np.log10(np.absolute(gain))
        data2 = np.angle(gain, deg=True)
        self.plot_curves(freq, data1, 'G, dB', (-110, 110.0), data2,
                         r'$\angle$ G, deg', (-198, 198))

    def plot_gain_short(self):
        self.mode = 'gain_short'
        self.plot_gain(self.vna.gain_short(self.vna.dut.freq))

    def plot_gain_open(self):
        self.mode = 'gain_open'
        self.plot_gain(self.vna.gain_open(self.vna.dut.freq))

    def update_gain(self, gain, mode):
        if self.mode == mode:
            self.curve1.set_xdata(self.vna.dut.freq)
            self.curve1.set_ydata(20.0 * np.log10(np.absolute(gain)))
            self.curve2.set_xdata(self.vna.dut.freq)
            self.curve2.set_ydata(np.angle(gain, deg=True))
            self.canvas.draw()
        else:
            self.mode = mode
            self.plot_gain(gain)

    def update_gain_short(self):
        self.update_gain(self.vna.gain_short(self.vna.dut.freq), 'gain_short')

    def update_gain_open(self):
        self.update_gain(self.vna.gain_open(self.vna.dut.freq), 'gain_open')

    def plot_magphase(self, freq, data, label, mode):
        self.mode = mode
        data1 = np.absolute(data)
        data2 = np.angle(data, deg=True)
        max = np.fmax(0.01, data1.max())
        label1 = r'|%s|' % label
        label2 = r'$\angle$ %s, deg' % label
        self.plot_curves(freq, data1, label1, (-0.05 * max, 1.05 * max), data2,
                         label2, (-198, 198))

    def update_magphase(self, freq, data, label, mode):
        if self.mode == mode:
            self.curve1.set_xdata(freq)
            self.curve1.set_ydata(np.absolute(data))
            self.curve2.set_xdata(freq)
            self.curve2.set_ydata(np.angle(data, deg=True))
            self.canvas.draw()
        else:
            self.plot_magphase(freq, data, label, mode)

    def plot_open(self):
        self.plot_magphase(self.vna.open.freq, self.vna.open.data, 'open',
                           'open')

    def update_open(self):
        self.update_magphase(self.vna.open.freq, self.vna.open.data, 'open',
                             'open')

    def plot_short(self):
        self.plot_magphase(self.vna.short.freq, self.vna.short.data, 'short',
                           'short')

    def update_short(self):
        self.update_magphase(self.vna.short.freq, self.vna.short.data, 'short',
                             'short')

    def plot_load(self):
        self.plot_magphase(self.vna.load.freq, self.vna.load.data, 'load',
                           'load')

    def update_load(self):
        self.update_magphase(self.vna.load.freq, self.vna.load.data, 'load',
                             'load')

    def plot_dut(self):
        self.plot_magphase(self.vna.dut.freq, self.vna.dut.data, 'dut', 'dut')

    def update_dut(self):
        self.update_magphase(self.vna.dut.freq, self.vna.dut.data, 'dut',
                             'dut')

    def plot_smith_grid(self, axes, color):
        load = 50.0
        ticks = np.array([0.0, 0.2, 0.5, 1.0, 2.0, 5.0])
        for tick in ticks * load:
            axis = np.logspace(-4, np.log10(1.0e3), 200) * load
            z = tick + 1.0j * axis
            gamma = (z - load) / (z + load)
            axes.plot(gamma.real,
                      gamma.imag,
                      color=color,
                      linewidth=0.4,
                      alpha=0.3)
            axes.plot(gamma.real,
                      -gamma.imag,
                      color=color,
                      linewidth=0.4,
                      alpha=0.3)
            z = axis + 1.0j * tick
            gamma = (z - load) / (z + load)
            axes.plot(gamma.real,
                      gamma.imag,
                      color=color,
                      linewidth=0.4,
                      alpha=0.3)
            axes.plot(gamma.real,
                      -gamma.imag,
                      color=color,
                      linewidth=0.4,
                      alpha=0.3)
            if tick == 0.0:
                axes.text(1.0,
                          0.0,
                          u'\u221E',
                          color=color,
                          ha='left',
                          va='center',
                          clip_on=True,
                          fontsize='x-large')
                axes.text(-1.0,
                          0.0,
                          u'0\u03A9',
                          color=color,
                          ha='left',
                          va='bottom',
                          clip_on=True)
                continue
            lab = u'%d\u03A9' % tick
            x = (tick - load) / (tick + load)
            axes.text(x,
                      0.0,
                      lab,
                      color=color,
                      ha='left',
                      va='bottom',
                      clip_on=True)
            lab = u'j%d\u03A9' % tick
            z = 1.0j * tick
            gamma = (z - load) / (z + load) * 1.05
            x = gamma.real
            y = gamma.imag
            angle = np.angle(gamma) * 180.0 / np.pi - 90.0
            axes.text(x,
                      y,
                      lab,
                      color=color,
                      ha='center',
                      va='center',
                      clip_on=True,
                      rotation=angle)
            lab = u'\u2212j%d\u03A9' % tick
            axes.text(x,
                      -y,
                      lab,
                      color=color,
                      ha='center',
                      va='center',
                      clip_on=True,
                      rotation=-angle)

    def plot_smith(self):
        self.mode = 'smith'
        matplotlib.rcdefaults()
        self.figure.clf()
        bottom = len(self.cursors) * 0.04 + 0.05
        self.figure.subplots_adjust(left=0.0,
                                    bottom=bottom,
                                    right=1.0,
                                    top=1.0)
        axes1 = self.figure.add_subplot(111)
        self.plot_smith_grid(axes1, 'blue')
        gamma = self.vna.gamma(self.vna.dut.freq)
        self.curve1, = axes1.plot(gamma.real, gamma.imag, color='red')
        axes1.axis('equal')
        axes1.set_xlim(-1.12, 1.12)
        axes1.set_ylim(-1.12, 1.12)
        axes1.xaxis.set_visible(False)
        axes1.yaxis.set_visible(False)
        for loc, spine in axes1.spines.items():
            spine.set_visible(False)
        self.add_cursors(axes1)
        self.canvas.draw()

    def update_smith(self):
        if self.mode == 'smith':
            gamma = self.vna.gamma(self.vna.dut.freq)
            self.curve1.set_xdata(gamma.real)
            self.curve1.set_ydata(gamma.imag)
            self.canvas.draw()
        else:
            self.plot_smith()

    def plot_imp(self):
        self.mode = 'imp'
        freq = self.vna.dut.freq
        z = self.vna.impedance(freq)
        data1 = np.fmin(9.99e4, np.absolute(z))
        data2 = np.angle(z, deg=True)
        max = np.fmax(0.01, data1.max())
        self.plot_curves(freq, data1, '|Z|, \u03A9', (-0.05 * max, 1.05 * max),
                         data2, r'$\angle$ Z, deg', (-198, 198))

    def update_imp(self):
        if self.mode == 'imp':
            freq = self.vna.dut.freq
            z = self.vna.impedance(freq)
            data1 = np.fmin(9.99e4, np.absolute(z))
            data2 = np.angle(z, deg=True)
            self.curve1.set_xdata(freq)
            self.curve1.set_ydata(data1)
            self.curve2.set_xdata(freq)
            self.curve2.set_ydata(data2)
            self.canvas.draw()
        else:
            self.plot_imp()

    def plot_swr(self):
        self.mode = 'swr'
        freq = self.vna.dut.freq
        data1 = self.vna.swr(freq)
        self.plot_curves(freq, data1, 'SWR', (0.9, 3.1), None, None, None)

    def update_swr(self):
        if self.mode == 'swr':
            self.curve1.set_xdata(self.vna.dut.freq)
            self.curve1.set_ydata(self.vna.swr(self.vna.dut.freq))
            self.canvas.draw()
        else:
            self.plot_swr()

    def plot_gamma(self):
        self.plot_magphase(self.vna.dut.freq,
                           self.vna.gamma(self.vna.dut.freq), r'$\Gamma$',
                           'gamma')

    def update_gamma(self):
        self.update_magphase(self.vna.dut.freq,
                             self.vna.gamma(self.vna.dut.freq), r'$\Gamma$',
                             'gamma')

    def plot_rl(self):
        self.mode = 'rl'
        freq = self.vna.dut.freq
        gamma = self.vna.gamma(freq)
        data1 = 20.0 * np.log10(np.absolute(gamma))
        self.plot_curves(freq, data1, 'RL, dB', (-105, 5.0), None, None, None)

    def update_rl(self):
        if self.mode == 'rl':
            freq = self.vna.dut.freq
            gamma = self.vna.gamma(freq)
            data1 = 20.0 * np.log10(np.absolute(gamma))
            self.curve1.set_xdata(freq)
            self.curve1.set_ydata(data1)
            self.canvas.draw()
        else:
            self.plot_rl()
示例#14
0
    def __init__(self, parent):
        QtWidgets.QDialog.__init__(self, parent)

        self.name = 'Create Scene List: '
        self.parent = parent
        self.indata = {}
        self.outdata = {}
        self.ifile = ''
        self.piter = self.parent.pbar.iter
        self.df = None

        self.shapefile = QtWidgets.QLineEdit('')
        self.scenefile = QtWidgets.QLineEdit('')
        self.isrecursive = QtWidgets.QCheckBox('Recursive file search')

        self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
        self.setWindowTitle("View Change Data")

        self.file_menu = QtWidgets.QMenu('&File', self)
        self.help_menu = QtWidgets.QMenu('&Help', self)

        self.help_menu.addAction('&About', self.about)
        self.file_menu.addAction('&Quit', self.fileQuit,
                                 QtCore.Qt.CTRL + QtCore.Qt.Key_Q)

        vlayout = QtWidgets.QVBoxLayout(self)
        hlayout = QtWidgets.QHBoxLayout()
        hlayout2 = QtWidgets.QHBoxLayout()

        self.canvas = MyMplCanvas(self, width=5, height=4, dpi=100)

        mpl_toolbar = NavigationToolbar(self.canvas, self)
        self.slider = QtWidgets.QScrollBar(QtCore.Qt.Horizontal)
        self.button2 = QtWidgets.QPushButton('Update Scene List File')
        self.button3 = QtWidgets.QPushButton('Next Scene')
        self.pbar = QtWidgets.QProgressBar()
        self.cb_use = QtWidgets.QCheckBox('Use Scene')
        self.cb_display = QtWidgets.QCheckBox('Only Display Scenes Flagged '
                                              'for Use')
        self.manip = QtWidgets.QComboBox()

        actions = ['RGB', 'NDVI', 'NDWI']
        self.manip.addItems(actions)

        hlayout2.addWidget(QtWidgets.QLabel('Band Manipulation:'))
        hlayout2.addWidget(self.manip)
        hlayout.addWidget(self.button3)
        hlayout.addWidget(self.button2)
        vlayout.addWidget(self.canvas)
        vlayout.addWidget(mpl_toolbar)
        vlayout.addWidget(self.slider)
        vlayout.addWidget(self.cb_display)
        vlayout.addWidget(self.cb_use)
        vlayout.addLayout(hlayout2)
        vlayout.addLayout(hlayout)
        vlayout.addWidget(self.pbar)

        self.curimage = 0

        mpl_toolbar.actions()[0].triggered.connect(self.home_callback)
        self.slider.valueChanged.connect(self.newdata)
        self.cb_use.stateChanged.connect(self.flaguse)
        self.button2.clicked.connect(self.updateanim)
        self.button3.clicked.connect(self.nextscene)
        self.manip.currentIndexChanged.connect(self.manip_change)
示例#15
0
class VNA(QMainWindow, Ui_VNA):

  max_size = 16384

  def __init__(self):
    super(VNA, self).__init__()
    self.setupUi(self)
    # IP address validator
    rx = QRegExp('^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$')
    self.addrValue.setValidator(QRegExpValidator(rx, self.addrValue))
    # state variables
    self.idle = True
    self.reading = False
    # sweep parameters
    self.sweep_start = 100
    self.sweep_stop = 60000
    self.sweep_size = 600
    self.xaxis, self.sweep_step = np.linspace(self.sweep_start, self.sweep_stop, self.sweep_size, retstep = True)
    self.xaxis *= 1000
    # buffer and offset for the incoming samples
    self.buffer = bytearray(24 * VNA.max_size)
    self.offset = 0
    self.data = np.frombuffer(self.buffer, np.complex64)
    self.adc1 = np.zeros(VNA.max_size, np.complex64)
    self.adc2 = np.zeros(VNA.max_size, np.complex64)
    self.dac1 = np.zeros(VNA.max_size, np.complex64)
    self.open = np.zeros(VNA.max_size, np.complex64)
    self.short = np.zeros(VNA.max_size, np.complex64)
    self.load = np.zeros(VNA.max_size, np.complex64)
    self.dut = np.zeros(VNA.max_size, np.complex64)
    self.mode = 'dut'
    # create figure
    self.figure = Figure()
    self.figure.set_facecolor('none')
    self.canvas = FigureCanvas(self.figure)
    self.plotLayout.addWidget(self.canvas)
    # create navigation toolbar
    self.toolbar = NavigationToolbar(self.canvas, self.plotWidget, False)
    # initialize cursor
    self.cursor = None
    # remove subplots action
    actions = self.toolbar.actions()
    self.toolbar.removeAction(actions[7])
    self.plotLayout.addWidget(self.toolbar)
    # create TCP socket
    self.socket = QTcpSocket(self)
    self.socket.connected.connect(self.connected)
    self.socket.readyRead.connect(self.read_data)
    self.socket.error.connect(self.display_error)
    # connect signals from buttons and boxes
    self.sweepFrame.setEnabled(False)
    self.dutSweep.setEnabled(False)
    self.connectButton.clicked.connect(self.start)
    self.writeButton.clicked.connect(self.write_cfg)
    self.readButton.clicked.connect(self.read_cfg)
    self.openSweep.clicked.connect(self.sweep_open)
    self.shortSweep.clicked.connect(self.sweep_short)
    self.loadSweep.clicked.connect(self.sweep_load)
    self.dutSweep.clicked.connect(self.sweep_dut)
    self.csvButton.clicked.connect(self.write_csv)
    self.s1pButton.clicked.connect(self.write_s1p)
    self.s2pButton.clicked.connect(self.write_s2p)
    self.startValue.valueChanged.connect(self.set_start)
    self.stopValue.valueChanged.connect(self.set_stop)
    self.sizeValue.valueChanged.connect(self.set_size)
    self.rateValue.addItems(['500', '100', '50', '10', '5', '1'])
    self.rateValue.lineEdit().setReadOnly(True)
    self.rateValue.lineEdit().setAlignment(Qt.AlignRight)
    for i in range(0, self.rateValue.count()):
      self.rateValue.setItemData(i, Qt.AlignRight, Qt.TextAlignmentRole)
    self.rateValue.currentIndexChanged.connect(self.set_rate)
    self.corrValue.valueChanged.connect(self.set_corr)
    self.levelValue.valueChanged.connect(self.set_level)
    self.openPlot.clicked.connect(self.plot_open)
    self.shortPlot.clicked.connect(self.plot_short)
    self.loadPlot.clicked.connect(self.plot_load)
    self.dutPlot.clicked.connect(self.plot_dut)
    self.smithPlot.clicked.connect(self.plot_smith)
    self.impPlot.clicked.connect(self.plot_imp)
    self.rcPlot.clicked.connect(self.plot_rc)
    self.swrPlot.clicked.connect(self.plot_swr)
    self.rlPlot.clicked.connect(self.plot_rl)
    self.gainPlot.clicked.connect(self.plot_gain)
    # create timer
    self.startTimer = QTimer(self)
    self.startTimer.timeout.connect(self.timeout)

  def start(self):
    if self.idle:
      self.connectButton.setEnabled(False)
      self.socket.connectToHost(self.addrValue.text(), 1001)
      self.startTimer.start(5000)
    else:
      self.stop()

  def stop(self):
    self.idle = True
    self.socket.abort()
    self.connectButton.setText('Connect')
    self.connectButton.setEnabled(True)
    self.sweepFrame.setEnabled(False)
    self.selectFrame.setEnabled(True)
    self.dutSweep.setEnabled(False)

  def timeout(self):
    self.display_error('timeout')

  def connected(self):
    self.startTimer.stop()
    self.idle = False
    self.set_start(self.startValue.value())
    self.set_stop(self.stopValue.value())
    self.set_size(self.sizeValue.value())
    self.set_rate(self.rateValue.currentIndex())
    self.set_corr(self.corrValue.value())
    self.set_level(self.levelValue.value())
    self.connectButton.setText('Disconnect')
    self.connectButton.setEnabled(True)
    self.sweepFrame.setEnabled(True)
    self.dutSweep.setEnabled(True)

  def read_data(self):
    if not self.reading:
      self.socket.readAll()
      return
    size = self.socket.bytesAvailable()
    self.progress.setValue((self.offset + size) / 24)
    limit = 24 * (self.sweep_size + 1)
    if self.offset + size < limit:
      self.buffer[self.offset:self.offset + size] = self.socket.read(size)
      self.offset += size
    else:
      self.buffer[self.offset:limit] = self.socket.read(limit - self.offset)
      self.adc1 = self.data[0::3]
      self.adc2 = self.data[1::3]
      self.dac1 = self.data[2::3]
      getattr(self, self.mode)[0:self.sweep_size] = self.adc1[1:self.sweep_size + 1] / self.dac1[1:self.sweep_size + 1]
      getattr(self, 'plot_%s' % self.mode)()
      self.reading = False
      self.sweepFrame.setEnabled(True)
      self.selectFrame.setEnabled(True)

  def display_error(self, socketError):
    self.startTimer.stop()
    if socketError == 'timeout':
      QMessageBox.information(self, 'VNA', 'Error: connection timeout.')
    else:
      QMessageBox.information(self, 'VNA', 'Error: %s.' % self.socket.errorString())
    self.stop()

  def set_start(self, value):
    self.sweep_start = value
    self.xaxis, self.sweep_step = np.linspace(self.sweep_start, self.sweep_stop, self.sweep_size, retstep = True)
    self.xaxis *= 1000
    if self.idle: return
    self.socket.write(struct.pack('<I', 0<<28 | int(value * 1000)))

  def set_stop(self, value):
    self.sweep_stop = value
    self.xaxis, self.sweep_step = np.linspace(self.sweep_start, self.sweep_stop, self.sweep_size, retstep = True)
    self.xaxis *= 1000
    if self.idle: return
    self.socket.write(struct.pack('<I', 1<<28 | int(value * 1000)))

  def set_size(self, value):
    self.sweep_size = value
    self.xaxis, self.sweep_step = np.linspace(self.sweep_start, self.sweep_stop, self.sweep_size, retstep = True)
    self.xaxis *= 1000
    if self.idle: return
    self.socket.write(struct.pack('<I', 2<<28 | int(value)))

  def set_rate(self, value):
    if self.idle: return
    rate = [1, 5, 10, 50, 100, 500][value]
    self.socket.write(struct.pack('<I', 3<<28 | int(rate)))

  def set_corr(self, value):
    if self.idle: return
    self.socket.write(struct.pack('<I', 4<<28 | int(value)))

  def set_level(self, value):
    if self.idle: return
    self.socket.write(struct.pack('<I', 5<<28 | int(32767 * np.power(10.0, value / 20.0))))

  def sweep(self):
    if self.idle: return
    self.sweepFrame.setEnabled(False)
    self.selectFrame.setEnabled(False)
    self.socket.write(struct.pack('<I', 6<<28))
    self.offset = 0
    self.reading = True
    self.progress = QProgressDialog('Sweep status', 'Cancel', 0, self.sweep_size + 1)
    self.progress.setModal(True)
    self.progress.setMinimumDuration(1000)
    self.progress.canceled.connect(self.cancel)

  def cancel(self):
    self.offset = 0
    self.reading = False
    self.socket.write(struct.pack('<I', 7<<28))
    self.sweepFrame.setEnabled(True)
    self.selectFrame.setEnabled(True)

  def sweep_open(self):
    self.mode = 'open'
    self.sweep()

  def sweep_short(self):
    self.mode = 'short'
    self.sweep()

  def sweep_load(self):
    self.mode = 'load'
    self.sweep()

  def sweep_dut(self):
    self.mode = 'dut'
    self.sweep()

  def gain(self):
    size = self.sweep_size
    return self.dut[0:size]/self.short[0:size]

  def impedance(self):
    size = self.sweep_size
    return 50.0 * (self.open[0:size] - self.load[0:size]) * (self.dut[0:size] - self.short[0:size]) / ((self.load[0:size] - self.short[0:size]) * (self.open[0:size] - self.dut[0:size]))

  def gamma(self):
    z = self.impedance()
    return (z - 50.0)/(z + 50.0)

  def plot_gain(self):
    if self.cursor is not None: self.cursor.hide().disable()
    matplotlib.rcdefaults()
    self.figure.clf()
    self.figure.subplots_adjust(left = 0.12, bottom = 0.12, right = 0.88, top = 0.98)
    axes1 = self.figure.add_subplot(111)
    axes1.cla()
    axes1.xaxis.set_major_formatter(FuncFormatter(metric_prefix))
    axes1.yaxis.set_major_formatter(FuncFormatter(metric_prefix))
    axes1.tick_params('y', color = 'blue', labelcolor = 'blue')
    axes1.yaxis.label.set_color('blue')
    gain = self.gain()
    axes1.plot(self.xaxis, 20.0 * np.log10(np.absolute(gain)), color = 'blue', label = 'Gain')
    axes2 = axes1.twinx()
    axes2.spines['left'].set_color('blue')
    axes2.spines['right'].set_color('red')
    axes1.set_xlabel('Hz')
    axes1.set_ylabel('Gain, dB')
    axes2.set_ylabel('Phase angle')
    axes2.tick_params('y', color = 'red', labelcolor = 'red')
    axes2.yaxis.label.set_color('red')
    axes2.plot(self.xaxis, np.angle(gain, deg = True), color = 'red', label = 'Phase angle')
    self.cursor = datacursor(axes = self.figure.get_axes(), formatter = LabelFormatter(), display = 'multiple')
    self.canvas.draw()

  def plot_magphase(self, data):
    if self.cursor is not None: self.cursor.hide().disable()
    matplotlib.rcdefaults()
    self.figure.clf()
    self.figure.subplots_adjust(left = 0.12, bottom = 0.12, right = 0.88, top = 0.98)
    axes1 = self.figure.add_subplot(111)
    axes1.cla()
    axes1.xaxis.set_major_formatter(FuncFormatter(metric_prefix))
    axes1.yaxis.set_major_formatter(FuncFormatter(metric_prefix))
    axes1.tick_params('y', color = 'blue', labelcolor = 'blue')
    axes1.yaxis.label.set_color('blue')
    axes1.plot(self.xaxis, np.absolute(data), color = 'blue', label = 'Magnitude')
    axes2 = axes1.twinx()
    axes2.spines['left'].set_color('blue')
    axes2.spines['right'].set_color('red')
    axes1.set_xlabel('Hz')
    axes1.set_ylabel('Magnitude')
    axes2.set_ylabel('Phase angle')
    axes2.tick_params('y', color = 'red', labelcolor = 'red')
    axes2.yaxis.label.set_color('red')
    axes2.plot(self.xaxis, np.angle(data, deg = True), color = 'red', label = 'Phase angle')
    self.cursor = datacursor(axes = self.figure.get_axes(), formatter = LabelFormatter(), display = 'multiple')
    self.canvas.draw()

  def plot_open(self):
    self.plot_magphase(self.open[0:self.sweep_size])

  def plot_short(self):
    self.plot_magphase(self.short[0:self.sweep_size])

  def plot_load(self):
    self.plot_magphase(self.load[0:self.sweep_size])

  def plot_dut(self):
    self.plot_magphase(self.dut[0:self.sweep_size])

  def plot_smith_grid(self, axes, color):
    load = 50.0
    ticks = np.array([0.0, 0.2, 0.5, 1.0, 2.0, 5.0])
    for tick in ticks * load:
      axis = np.logspace(-4, np.log10(1.0e3), 200) * load
      z = tick + 1.0j * axis
      gamma = (z - load)/(z + load)
      axes.plot(gamma.real, gamma.imag, color = color, linewidth = 0.4, alpha = 0.3)
      axes.plot(gamma.real, -gamma.imag, color = color, linewidth = 0.4, alpha = 0.3)
      z = axis + 1.0j * tick
      gamma = (z - load)/(z + load)
      axes.plot(gamma.real, gamma.imag, color = color, linewidth = 0.4, alpha = 0.3)
      axes.plot(gamma.real, -gamma.imag, color = color, linewidth = 0.4, alpha = 0.3)
      if tick == 0.0:
        axes.text(1.0, 0.0, u'\u221E', color = color, ha = 'left', va = 'center', clip_on = True, fontsize = 18.0)
        axes.text(-1.0, 0.0, u'0\u03A9', color = color, ha = 'left', va = 'bottom', clip_on = True, fontsize = 12.0)
        continue
      lab = u'%d\u03A9' % tick
      x = (tick - load) / (tick + load)
      axes.text(x, 0.0, lab, color = color, ha = 'left', va = 'bottom', clip_on = True, fontsize = 12.0)
      lab = u'j%d\u03A9' % tick
      z =  1.0j * tick
      gamma = (z - load)/(z + load) * 1.05
      x = gamma.real
      y = gamma.imag
      angle = np.angle(gamma) * 180.0 / np.pi - 90.0
      axes.text(x, y, lab, color = color, ha = 'center', va = 'center', clip_on = True, rotation = angle, fontsize = 12.0)
      lab = u'-j%d\u03A9' % tick
      axes.text(x, -y, lab, color = color, ha = 'center', va = 'center', clip_on = True, rotation = -angle, fontsize = 12.0)

  def plot_smith(self):
    if self.cursor is not None: self.cursor.hide().disable()
    matplotlib.rcdefaults()
    self.figure.clf()
    self.figure.subplots_adjust(left = 0.0, bottom = 0.0, right = 1.0, top = 1.0)
    axes1 = self.figure.add_subplot(111)
    self.plot_smith_grid(axes1, 'blue')
    gamma = self.gamma()
    plot, = axes1.plot(gamma.real, gamma.imag, color = 'red')
    axes1.axis('equal')
    axes1.set_xlim(-1.12, 1.12)
    axes1.set_ylim(-1.12, 1.12)
    axes1.xaxis.set_visible(False)
    axes1.yaxis.set_visible(False)
    for loc, spine in axes1.spines.items():
      spine.set_visible(False)
    self.cursor = datacursor(plot, formatter = SmithFormatter(self.xaxis), display = 'multiple')
    self.canvas.draw()

  def plot_imp(self):
    self.plot_magphase(self.impedance())

  def plot_rc(self):
    self.plot_magphase(self.gamma())

  def plot_swr(self):
    if self.cursor is not None: self.cursor.hide().disable()
    matplotlib.rcdefaults()
    self.figure.clf()
    self.figure.subplots_adjust(left = 0.12, bottom = 0.12, right = 0.88, top = 0.98)
    axes1 = self.figure.add_subplot(111)
    axes1.cla()
    axes1.xaxis.set_major_formatter(FuncFormatter(metric_prefix))
    axes1.yaxis.set_major_formatter(FuncFormatter(metric_prefix))
    axes1.set_xlabel('Hz')
    axes1.set_ylabel('SWR')
    magnitude = np.absolute(self.gamma())
    swr = np.maximum(1.0, np.minimum(100.0, (1.0 + magnitude) / np.maximum(1.0e-20, 1.0 - magnitude)))
    axes1.plot(self.xaxis, swr, color = 'blue', label = 'SWR')
    self.cursor = datacursor(axes = self.figure.get_axes(), formatter = LabelFormatter(), display = 'multiple')
    self.canvas.draw()

  def plot_rl(self):
    if self.cursor is not None: self.cursor.hide().disable()
    matplotlib.rcdefaults()
    self.figure.clf()
    self.figure.subplots_adjust(left = 0.12, bottom = 0.12, right = 0.88, top = 0.98)
    axes1 = self.figure.add_subplot(111)
    axes1.cla()
    axes1.xaxis.set_major_formatter(FuncFormatter(metric_prefix))
    axes1.set_xlabel('Hz')
    axes1.set_ylabel('Return loss, dB')
    magnitude = np.absolute(self.gamma())
    axes1.plot(self.xaxis, 20.0 * np.log10(magnitude), color = 'blue', label = 'Return loss')
    self.cursor = datacursor(axes = self.figure.get_axes(), formatter = LabelFormatter(), display = 'multiple')
    self.canvas.draw()

  def write_cfg(self):
    dialog = QFileDialog(self, 'Write configuration settings', '.', '*.ini')
    dialog.setDefaultSuffix('ini')
    dialog.setAcceptMode(QFileDialog.AcceptSave)
    dialog.setOptions(QFileDialog.DontConfirmOverwrite)
    if dialog.exec() == QDialog.Accepted:
      name = dialog.selectedFiles()
      settings = QSettings(name[0], QSettings.IniFormat)
      self.write_cfg_settings(settings)

  def read_cfg(self):
    dialog = QFileDialog(self, 'Read configuration settings', '.', '*.ini')
    dialog.setDefaultSuffix('ini')
    dialog.setAcceptMode(QFileDialog.AcceptOpen)
    if dialog.exec() == QDialog.Accepted:
      name = dialog.selectedFiles()
      settings = QSettings(name[0], QSettings.IniFormat)
      self.read_cfg_settings(settings)

  def write_cfg_settings(self, settings):
    settings.setValue('addr', self.addrValue.text())
    settings.setValue('start', self.startValue.value())
    settings.setValue('stop', self.stopValue.value())
    settings.setValue('rate', self.rateValue.currentIndex())
    settings.setValue('corr', self.corrValue.value())
    size = self.sizeValue.value()
    settings.setValue('size', size)
    for i in range(0, size):
      settings.setValue('open_real_%d' % i, float(self.open.real[i]))
      settings.setValue('open_imag_%d' % i, float(self.open.imag[i]))
    for i in range(0, size):
      settings.setValue('short_real_%d' % i, float(self.short.real[i]))
      settings.setValue('short_imag_%d' % i, float(self.short.imag[i]))
    for i in range(0, size):
      settings.setValue('load_real_%d' % i, float(self.load.real[i]))
      settings.setValue('load_imag_%d' % i, float(self.load.imag[i]))
    for i in range(0, size):
      settings.setValue('dut_real_%d' % i, float(self.dut.real[i]))
      settings.setValue('dut_imag_%d' % i, float(self.dut.imag[i]))

  def read_cfg_settings(self, settings):
    self.addrValue.setText(settings.value('addr', '192.168.1.100'))
    self.startValue.setValue(settings.value('start', 100, type = int))
    self.stopValue.setValue(settings.value('stop', 60000, type = int))
    self.rateValue.setCurrentIndex(settings.value('rate', 0, type = int))
    self.corrValue.setValue(settings.value('corr', 0, type = int))
    size = settings.value('size', 600, type = int)
    self.sizeValue.setValue(size)
    for i in range(0, size):
      real = settings.value('open_real_%d' % i, 0.0, type = float)
      imag = settings.value('open_imag_%d' % i, 0.0, type = float)
      self.open[i] = real + 1.0j * imag
    for i in range(0, size):
      real = settings.value('short_real_%d' % i, 0.0, type = float)
      imag = settings.value('short_imag_%d' % i, 0.0, type = float)
      self.short[i] = real + 1.0j * imag
    for i in range(0, size):
      real = settings.value('load_real_%d' % i, 0.0, type = float)
      imag = settings.value('load_imag_%d' % i, 0.0, type = float)
      self.load[i] = real + 1.0j * imag
    for i in range(0, size):
      real = settings.value('dut_real_%d' % i, 0.0, type = float)
      imag = settings.value('dut_imag_%d' % i, 0.0, type = float)
      self.dut[i] = real + 1.0j * imag

  def write_csv(self):
    dialog = QFileDialog(self, 'Write csv file', '.', '*.csv')
    dialog.setDefaultSuffix('csv')
    dialog.setAcceptMode(QFileDialog.AcceptSave)
    dialog.setOptions(QFileDialog.DontConfirmOverwrite)
    if dialog.exec() == QDialog.Accepted:
      name = dialog.selectedFiles()
      fh = open(name[0], 'w')
      gamma = self.gamma()
      size = self.sizeValue.value()
      fh.write('frequency;open.real;open.imag;short.real;short.imag;load.real;load.imag;dut.real;dut.imag\n')
      for i in range(0, size):
        fh.write('0.0%.8d;%12.9f;%12.9f;%12.9f;%12.9f;%12.9f;%12.9f;%12.9f;%12.9f\n' % (self.xaxis[i], self.open.real[i], self.open.imag[i], self.short.real[i], self.short.imag[i], self.load.real[i], self.load.imag[i], self.dut.real[i], self.dut.imag[i]))
      fh.close()

  def write_s1p(self):
    dialog = QFileDialog(self, 'Write s1p file', '.', '*.s1p')
    dialog.setDefaultSuffix('s1p')
    dialog.setAcceptMode(QFileDialog.AcceptSave)
    dialog.setOptions(QFileDialog.DontConfirmOverwrite)
    if dialog.exec() == QDialog.Accepted:
      name = dialog.selectedFiles()
      fh = open(name[0], 'w')
      gamma = self.gamma()
      size = self.sizeValue.value()
      fh.write('# GHz S MA R 50\n')
      for i in range(0, size):
        fh.write('0.0%.8d   %8.6f %7.2f\n' % (self.xaxis[i], np.absolute(gamma[i]), np.angle(gamma[i], deg = True)))
      fh.close()

  def write_s2p(self):
    dialog = QFileDialog(self, 'Write s2p file', '.', '*.s2p')
    dialog.setDefaultSuffix('s2p')
    dialog.setAcceptMode(QFileDialog.AcceptSave)
    dialog.setOptions(QFileDialog.DontConfirmOverwrite)
    if dialog.exec() == QDialog.Accepted:
      name = dialog.selectedFiles()
      fh = open(name[0], 'w')
      gain = self.gain()
      gamma = self.gamma()
      size = self.sizeValue.value()
      fh.write('# GHz S MA R 50\n')
      for i in range(0, size):
        fh.write('0.0%.8d   %8.6f %7.2f   %8.6f %7.2f   0.000000    0.00   0.000000    0.00\n' % (self.xaxis[i], np.absolute(gamma[i]), np.angle(gamma[i], deg = True), np.absolute(gain[i]), np.angle(gain[i], deg = True)))
      fh.close()
示例#16
0
class VNA(QMainWindow, Ui_VNA):

  max_size = 16383

  formatter = matplotlib.ticker.FuncFormatter(lambda x, pos: '%1.1fM' % (x * 1e-6) if abs(x) >= 1e6 else '%1.1fk' % (x * 1e-3) if abs(x) >= 1e3 else '%1.1f' % x if abs(x) >= 1e0 else '%1.1fm' % (x * 1e+3) if abs(x) >= 1e-3 else '%1.1fu' % (x * 1e+6) if abs(x) >= 1e-6 else '%1.1f' % x)

  def __init__(self):
    super(VNA, self).__init__()
    self.setupUi(self)
    # IP address validator
    rx = QRegExp('^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$')
    self.addrValue.setValidator(QRegExpValidator(rx, self.addrValue))
    # state variable
    self.idle = True
    # sweep parameters
    self.sweep_start = 100
    self.sweep_stop = 60000
    self.sweep_size = 600
    self.xaxis, self.sweep_step = np.linspace(self.sweep_start, self.sweep_stop, self.sweep_size, retstep = True)
    self.xaxis *= 1000
    # buffer and offset for the incoming samples
    self.buffer = bytearray(32 * VNA.max_size)
    self.offset = 0
    self.data = np.frombuffer(self.buffer, np.complex64)
    self.adc1 = np.zeros(VNA.max_size, np.complex64)
    self.adc2 = np.zeros(VNA.max_size, np.complex64)
    self.dac1 = np.zeros(VNA.max_size, np.complex64)
    self.open = np.zeros(VNA.max_size, np.complex64)
    self.short = np.zeros(VNA.max_size, np.complex64)
    self.load = np.zeros(VNA.max_size, np.complex64)
    self.dut = np.zeros(VNA.max_size, np.complex64)
    self.mode = 'dut'
    # create figure
    self.figure = Figure()
    self.figure.set_facecolor('none')
    self.canvas = FigureCanvas(self.figure)
    self.plotLayout.addWidget(self.canvas)
    # create navigation toolbar
    self.toolbar = NavigationToolbar(self.canvas, self.plotWidget, False)
    # remove subplots action
    actions = self.toolbar.actions()
    self.toolbar.removeAction(actions[7])
    self.plotLayout.addWidget(self.toolbar)
    # create TCP socket
    self.socket = QTcpSocket(self)
    self.socket.connected.connect(self.connected)
    self.socket.readyRead.connect(self.read_data)
    self.socket.error.connect(self.display_error)
    # connect signals from buttons and boxes
    self.sweepFrame.setEnabled(False)
    self.dutSweep.setEnabled(False)
    self.connectButton.clicked.connect(self.start)
    self.writeButton.clicked.connect(self.write_cfg)
    self.readButton.clicked.connect(self.read_cfg)
    self.openSweep.clicked.connect(self.sweep_open)
    self.shortSweep.clicked.connect(self.sweep_short)
    self.loadSweep.clicked.connect(self.sweep_load)
    self.dutSweep.clicked.connect(self.sweep_dut)
    self.s1pButton.clicked.connect(self.write_s1p)
    self.startValue.valueChanged.connect(self.set_start)
    self.stopValue.valueChanged.connect(self.set_stop)
    self.sizeValue.valueChanged.connect(self.set_size)
    self.openPlot.clicked.connect(self.plot_open)
    self.shortPlot.clicked.connect(self.plot_short)
    self.loadPlot.clicked.connect(self.plot_load)
    self.dutPlot.clicked.connect(self.plot_dut)
    self.smithPlot.clicked.connect(self.plot_smith)
    self.impPlot.clicked.connect(self.plot_imp)
    self.rcPlot.clicked.connect(self.plot_rc)
    self.swrPlot.clicked.connect(self.plot_swr)
    self.rlPlot.clicked.connect(self.plot_rl)
    # create timer
    self.startTimer = QTimer(self)
    self.startTimer.timeout.connect(self.timeout)

  def start(self):
    if self.idle:
      self.connectButton.setEnabled(False)
      self.socket.connectToHost(self.addrValue.text(), 1001)
      self.startTimer.start(5000)
    else:
      self.stop()

  def stop(self):
    self.idle = True
    self.socket.abort()
    self.offset = 0
    self.connectButton.setText('Connect')
    self.connectButton.setEnabled(True)
    self.sweepFrame.setEnabled(False)
    self.selectFrame.setEnabled(True)
    self.dutSweep.setEnabled(False)

  def timeout(self):
    self.display_error('timeout')

  def connected(self):
    self.startTimer.stop()
    self.idle = False
    self.set_start(self.startValue.value())
    self.set_stop(self.stopValue.value())
    self.set_size(self.sizeValue.value())
    self.connectButton.setText('Disconnect')
    self.connectButton.setEnabled(True)
    self.sweepFrame.setEnabled(True)
    self.dutSweep.setEnabled(True)

  def read_data(self):
    size = self.socket.bytesAvailable()
    if self.offset + size < 32 * self.sweep_size:
      self.buffer[self.offset:self.offset + size] = self.socket.read(size)
      self.offset += size
    else:
      self.buffer[self.offset:32 * self.sweep_size] = self.socket.read(32 * self.sweep_size - self.offset)
      self.offset = 0
      self.adc1 = self.data[0::4]
      self.adc2 = self.data[1::4]
      self.dac1 = self.data[2::4]
      getattr(self, self.mode)[0:self.sweep_size] = self.adc1[0:self.sweep_size] / self.dac1[0:self.sweep_size]
      self.sweepFrame.setEnabled(True)
      self.selectFrame.setEnabled(True)
      getattr(self, 'plot_%s' % self.mode)()

  def display_error(self, socketError):
    self.startTimer.stop()
    if socketError == 'timeout':
      QMessageBox.information(self, 'VNA', 'Error: connection timeout.')
    else:
      QMessageBox.information(self, 'VNA', 'Error: %s.' % self.socket.errorString())
    self.stop()

  def set_start(self, value):
    self.sweep_start = value
    self.xaxis, self.sweep_step = np.linspace(self.sweep_start, self.sweep_stop, self.sweep_size, retstep = True)
    self.xaxis *= 1000
    if self.idle: return
    self.socket.write(struct.pack('<I', 0<<28 | int(value * 1000)))

  def set_stop(self, value):
    self.sweep_stop = value
    self.xaxis, self.sweep_step = np.linspace(self.sweep_start, self.sweep_stop, self.sweep_size, retstep = True)
    self.xaxis *= 1000
    if self.idle: return
    self.socket.write(struct.pack('<I', 1<<28 | int(value * 1000)))

  def set_size(self, value):
    self.sweep_size = value
    self.xaxis, self.sweep_step = np.linspace(self.sweep_start, self.sweep_stop, self.sweep_size, retstep = True)
    self.xaxis *= 1000
    if self.idle: return
    self.socket.write(struct.pack('<I', 2<<28 | int(value)))

  def sweep(self):
    if self.idle: return
    self.sweepFrame.setEnabled(False)
    self.selectFrame.setEnabled(False)
    self.socket.write(struct.pack('<I', 3<<28))

  def sweep_open(self):
    self.mode = 'open'
    self.sweep()

  def sweep_short(self):
    self.mode = 'short'
    self.sweep()

  def sweep_load(self):
    self.mode = 'load'
    self.sweep()

  def sweep_dut(self):
    self.mode = 'dut'
    self.sweep()

  def impedance(self):
    return 50.0 * (self.open[0:self.sweep_size] - self.load[0:self.sweep_size]) * (self.dut[0:self.sweep_size] - self.short[0:self.sweep_size]) / ((self.load[0:self.sweep_size] - self.short[0:self.sweep_size]) * (self.open[0:self.sweep_size] - self.dut[0:self.sweep_size]))

  def gamma(self):
    z = self.impedance()
    return (z - 50.0)/(z + 50.0)

  def plot_magphase(self, data):
    matplotlib.rcdefaults()
    self.figure.clf()
    self.figure.subplots_adjust(top = 0.98, right = 0.88)
    axes1 = self.figure.add_subplot(111)
    axes1.cla()
    axes1.xaxis.set_major_formatter(VNA.formatter)
    axes1.yaxis.set_major_formatter(VNA.formatter)
    axes1.tick_params('y', color = 'blue', labelcolor = 'blue')
    axes1.yaxis.label.set_color('blue')
    axes1.plot(self.xaxis, np.absolute(data), color = 'blue')
    axes2 = axes1.twinx()
    axes2.spines['left'].set_color('blue')
    axes2.spines['right'].set_color('red')
    axes1.set_xlabel('Hz')
    axes1.set_ylabel('Magnitude')
    axes2.set_ylabel('Phase angle')
    axes2.tick_params('y', color = 'red', labelcolor = 'red')
    axes2.yaxis.label.set_color('red')
    axes2.plot(self.xaxis, np.angle(data, deg = True), color = 'red')
    self.canvas.draw()

  def plot_open(self):
    self.plot_magphase(self.open[0:self.sweep_size])

  def plot_short(self):
    self.plot_magphase(self.short[0:self.sweep_size])

  def plot_load(self):
    self.plot_magphase(self.load[0:self.sweep_size])

  def plot_dut(self):
    self.plot_magphase(self.dut[0:self.sweep_size])

  def plot_smith(self):
    matplotlib.rcdefaults()
    self.figure.clf()
    self.figure.subplots_adjust(top = 0.90, right = 0.90)
    axes = self.figure.add_subplot(111, projection = 'smith', axes_radius = 0.55, axes_scale = 50.0)
    axes.cla()
    axes.plot(self.impedance())
    self.canvas.draw()

  def plot_imp(self):
    self.plot_magphase(self.impedance())

  def plot_rc(self):
    self.plot_magphase(self.gamma())

  def plot_swr(self):
    matplotlib.rcdefaults()
    self.figure.clf()
    self.figure.subplots_adjust(top = 0.98, right = 0.88)
    axes1 = self.figure.add_subplot(111)
    axes1.cla()
    axes1.xaxis.set_major_formatter(VNA.formatter)
    axes1.yaxis.set_major_formatter(VNA.formatter)
    axes1.set_xlabel('Hz')
    axes1.set_ylabel('SWR')
    magnitude = np.absolute(self.gamma())
    swr = np.maximum(1.0, np.minimum(100.0, (1.0 + magnitude) / np.maximum(1.0e-20, 1.0 - magnitude)))
    axes1.plot(self.xaxis, swr, color = 'blue')
    self.canvas.draw()

  def plot_rl(self):
    matplotlib.rcdefaults()
    self.figure.clf()
    self.figure.subplots_adjust(top = 0.98, right = 0.88)
    axes1 = self.figure.add_subplot(111)
    axes1.cla()
    axes1.xaxis.set_major_formatter(VNA.formatter)
    axes1.set_xlabel('Hz')
    axes1.set_ylabel('Return loss, dB')
    magnitude = np.absolute(self.gamma())
    axes1.plot(self.xaxis, 20.0 * np.log10(magnitude), color = 'blue')
    self.canvas.draw()

  def write_cfg(self):
    name = QFileDialog.getSaveFileName(self, 'Write configuration settings', '.', '*.ini')
    settings = QSettings(name[0], QSettings.IniFormat)
    self.write_cfg_settings(settings)

  def read_cfg(self):
    name = QFileDialog.getOpenFileName(self, 'Read configuration settings', '.', '*.ini')
    settings = QSettings(name[0], QSettings.IniFormat)
    self.read_cfg_settings(settings)

  def write_cfg_settings(self, settings):
    settings.setValue('start', self.startValue.value())
    settings.setValue('stop', self.stopValue.value())
    size = self.sizeValue.value()
    settings.setValue('size', size)
    for i in range(0, size):
      settings.setValue('open_real_%d' % i, float(self.open.real[i]))
      settings.setValue('open_imag_%d' % i, float(self.open.imag[i]))
    for i in range(0, size):
      settings.setValue('short_real_%d' % i, float(self.short.real[i]))
      settings.setValue('short_imag_%d' % i, float(self.short.imag[i]))
    for i in range(0, size):
      settings.setValue('load_real_%d' % i, float(self.load.real[i]))
      settings.setValue('load_imag_%d' % i, float(self.load.imag[i]))
    for i in range(0, size):
      settings.setValue('dut_real_%d' % i, float(self.dut.real[i]))
      settings.setValue('dut_imag_%d' % i, float(self.dut.imag[i]))

  def read_cfg_settings(self, settings):
    self.startValue.setValue(settings.value('start', 100, type = int))
    self.stopValue.setValue(settings.value('stop', 60000, type = int))
    size = settings.value('size', 600, type = int)
    self.sizeValue.setValue(size)
    for i in range(0, size):
      real = settings.value('open_real_%d' % i, 0.0, type = float)
      imag = settings.value('open_imag_%d' % i, 0.0, type = float)
      self.open[i] = real + 1.0j * imag
    for i in range(0, size):
      real = settings.value('short_real_%d' % i, 0.0, type = float)
      imag = settings.value('short_imag_%d' % i, 0.0, type = float)
      self.short[i] = real + 1.0j * imag
    for i in range(0, size):
      real = settings.value('load_real_%d' % i, 0.0, type = float)
      imag = settings.value('load_imag_%d' % i, 0.0, type = float)
      self.load[i] = real + 1.0j * imag
    for i in range(0, size):
      real = settings.value('dut_real_%d' % i, 0.0, type = float)
      imag = settings.value('dut_imag_%d' % i, 0.0, type = float)
      self.dut[i] = real + 1.0j * imag

  def write_s1p(self):
    name = QFileDialog.getSaveFileName(self, 'Write s1p file', '.', '*.s1p')
    fh = open(name[0], 'w')
    gamma = self.gamma()
    size = self.sizeValue.value()
    fh.write('# GHz S MA R 50\n')
    for i in range(0, size):
      fh.write('0.0%.8d   %8.6f %7.2f\n' % (self.xaxis[i], np.absolute(gamma[i]), np.angle(gamma[i], deg = True)))
    fh.close()
示例#17
0
class QmyMainWindow(QMainWindow):
    def __init__(self, parent=None):
        super().__init__(parent)  #调用父类构造函数,创建窗体
        self.ui = Ui_MainWindow()  #创建UI对象
        self.ui.setupUi(self)  #构造UI界面

        self.setWindowTitle("Demo14_3, 交互操作")
        self.__labMove = QLabel("Mouse Move:")
        self.__labMove.setMinimumWidth(200)
        self.ui.statusBar.addWidget(self.__labMove)

        self.__labPick = QLabel("Mouse Pick:")
        self.__labPick.setMinimumWidth(200)
        self.ui.statusBar.addWidget(self.__labPick)

        mpl.rcParams['font.sans-serif'] = ['SimHei']  #显示汉字为 楷体, 汉字不支持 粗体,斜体等设置
        mpl.rcParams['font.size'] = 11
        ##  Windows自带的一些字体
        ##  黑体:SimHei 宋体:SimSun 新宋体:NSimSun 仿宋:FangSong  楷体:KaiTi
        mpl.rcParams['axes.unicode_minus'] = False  #减号unicode编码

        self.__fig = None  #Figue对象
        self.__createFigure()  #创建Figure和FigureCanvas对象,初始化界面
        self.__drawFig1X2()

##  ==============自定义功能函数========================

    def __createFigure(self):  ##创建绘图系统
        self.__fig = mpl.figure.Figure(figsize=(8, 5))  #单位英寸
        figCanvas = FigureCanvas(self.__fig)  #创建FigureCanvas对象,必须传递一个Figure对象
        self.__naviBar = NavigationToolbar(figCanvas,
                                           self)  #创建NavigationToolbar工具栏

        actList = self.__naviBar.actions()  #关联的Action列表
        for act in actList:  #获得每个Action的标题和tooltip,可注释掉
            print("text=%s,\ttoolTip=%s" % (act.text(), act.toolTip()))
        self.__changeActionLanguage()  #改工具栏的语言为汉语
        ##工具栏改造
        actList[6].setVisible(False)  #隐藏Subplots 按钮
        actList[7].setVisible(False)  #隐藏Customize按钮
        act8 = actList[8]  #分隔条
        self.__naviBar.insertAction(act8, self.ui.actTightLayout)  #"紧凑布局"按钮
        self.__naviBar.insertAction(act8, self.ui.actSetCursor)  #"十字光标"按钮

        count = len(actList)  #Action的个数
        lastAction = actList[count - 1]  #最后一个Action
        self.__naviBar.insertAction(lastAction,
                                    self.ui.actScatterAgain)  #"重绘散点"按钮

        lastAction.setVisible(False)  #隐藏其原有的坐标提示
        self.__naviBar.addSeparator()
        self.__naviBar.addAction(self.ui.actQuit)  #"退出"按钮
        self.__naviBar.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)  #显示方式

        self.addToolBar(self.__naviBar)  #添加作为主窗口工具栏
        self.setCentralWidget(figCanvas)

        figCanvas.setCursor(Qt.CrossCursor)
        ## 必须保留变量cid,否则可能被垃圾回收
        self._cid1 = figCanvas.mpl_connect("motion_notify_event",
                                           self.do_canvas_mouseMove)
        self._cid2 = figCanvas.mpl_connect("axes_enter_event",
                                           self.do_axes_mouseEnter)
        self._cid3 = figCanvas.mpl_connect("axes_leave_event",
                                           self.do_axes_mouseLeave)
        self._cid4 = figCanvas.mpl_connect("pick_event", self.do_series_pick)
        self._cid5 = figCanvas.mpl_connect("scroll_event", self.do_scrollZoom)

    def __changeActionLanguage(self):
        actList = self.__naviBar.actions()  #关联的Action列表
        actList[0].setText("复位")  #Home
        actList[0].setToolTip("复位到原始视图")  #Reset original view

        actList[1].setText("回退")  #Back
        actList[1].setToolTip("回到前一视图")  #Back to previous view

        actList[2].setText("前进")  #Forward
        actList[2].setToolTip("前进到下一视图")  #Forward to next view

        actList[4].setText("平动")  #Pan
        actList[4].setToolTip(
            "左键平移坐标轴,右键缩放坐标轴")  #Pan axes with left mouse, zoom with right

        actList[5].setText("缩放")  #Zoom
        actList[5].setToolTip("框选矩形框缩放")  #Zoom to rectangle

        actList[6].setText("子图")  #Subplots
        actList[6].setToolTip("设置子图")  #Configure subplots

        actList[7].setText("定制")  #Customize
        actList[7].setToolTip("定制图表参数")  #Edit axis, curve and image parameters

        actList[9].setText("保存")  #Save
        actList[9].setToolTip("保存图表")  #Save the figure

    def __drawScatters(self, N=15):
        x = range(N)  #序列0,1,....N-1
        ##      x=np.random.rand(N)
        y = np.random.rand(N)
        colors = np.random.rand(N)  #0~1之间随机数
        self.__markerSize = (
            40 * (0.2 + np.random.rand(N)))**2  #0 to 15 point radius
        self.__axScatter.scatter(x,
                                 y,
                                 s=self.__markerSize,
                                 c=colors,
                                 marker='*',
                                 alpha=0.5,
                                 label="scatter series",
                                 picker=True)  #允许被拾取pick
        #s=The marker size in points**2
        #c=color, sequence, or sequence of color, optional, default: 'b'
        ## marker : `~matplotlib.markers.MarkerStyle`, optional, default: 'o'
        self.__axScatter.set_title("散点图")
        self.__axScatter.set_xlabel('序号')  # X轴标题

    def __drawFig1X2(self):  #初始化绘图
        gs = self.__fig.add_gridspec(1, 2)  #1行,2列
        ##      ax1=self.__fig.add_subplot(1,1,1) #添加一个Axes对象,并返回此对象,不支持constrained_layout
        ax1 = self.__fig.add_subplot(gs[0, 0], label="Line2D plot")

        t = np.linspace(0, 10, 40)
        y1 = np.sin(t)
        y2 = np.cos(2 * t)
        ax1.plot(t,
                 y1,
                 'r-o',
                 label="sin series",
                 linewidth=1,
                 markersize=5,
                 picker=True)  #绘制一条曲线
        ax1.plot(t, y2, 'b:', label="cos series", linewidth=2)  #绘制一条曲线
        ax1.set_xlabel('X 轴')
        ax1.set_ylabel('Y 轴')
        ax1.set_xlim([0, 10])
        ax1.set_ylim([-1.5, 1.5])
        ax1.set_title("曲线")
        ax1.legend()  #自动创建Axes的图例

        self.__axScatter = self.__fig.add_subplot(gs[0, 1],
                                                  label="scatter plot")  #创建子图
        self.__drawScatters(N=15)  #绘制散点图

##  ==============event处理函数==========================

##  ==========由connectSlotsByName()自动连接的槽函数============

    @pyqtSlot()  ## 紧凑布局
    def on_actTightLayout_triggered(self):
        self.__fig.tight_layout()  # 对所有子图 进行一次tight_layout
        self.__fig.canvas.draw()

    @pyqtSlot()  ## 设置鼠标光标
    def on_actSetCursor_triggered(self):
        self.__fig.canvas.setCursor(Qt.CrossCursor)

    @pyqtSlot()  ## 重新绘制散点图
    def on_actScatterAgain_triggered(self):
        self.__axScatter.clear()  #清除子图
        self.__drawScatters(N=15)
        self.__fig.canvas.draw()  #刷新

##  =================自定义槽函数==========
#event类型 matplotlib.backend_bases.MouseEvent

    def do_canvas_mouseMove(self, event):
        if event.inaxes == None:
            return
        info = "%s: xdata=%.2f,ydata=%.2f  " % (event.inaxes.get_label(),
                                                event.xdata, event.ydata)
        self.__labMove.setText(info)

## event类型:matplotlib.backend_bases.LocationEvent

    def do_axes_mouseEnter(self, event):
        event.inaxes.patch.set_facecolor('g')  #设置背景颜色
        event.inaxes.patch.set_alpha(0.2)  #透明度
        event.canvas.draw()

    def do_axes_mouseLeave(self, event):
        event.inaxes.patch.set_facecolor('w')  #设置背景颜色
        event.canvas.draw()

##event 类型: matplotlib.backend_bases.PickEvent

    def do_series_pick(self, event):
        series = event.artist  # 产生事件的对象
        index = event.ind[0]  #索引号,是array([int32])类型,可能有多个对象被pick,只取第1个
        #是否有ind属性与具体的对象有关

        if isinstance(series, mpl.collections.PathCollection):  #scatter()生成的序列
            markerSize = self.__markerSize[index]
            info = "%s: index=%d, marker size=%d " % (
                event.mouseevent.inaxes.get_label(), index, markerSize)
        elif isinstance(series, mpl.lines.Line2D):  #plot()生成的序列
            ##         xdata=series.get_xdata() #两种方法都可以
            ##         x=xdata[index]
            ##         ydata=series.get_ydata()
            ##         y=ydata[index]
            x = event.mouseevent.xdata  #标量数据点
            y = event.mouseevent.ydata  #标量数据点
            info = "%s: index=%d, data_xy=(%.2f, %.2f) " % (series.get_label(),
                                                            index, x, y)

        self.__labPick.setText(info)

#event类型 matplotlib.backend_bases.MouseEvent

    def do_scrollZoom(self, event):  #通过鼠标滚轮缩放
        ax = event.inaxes  # 产生事件的axes对象
        if ax == None:
            return

        self.__naviBar.push_current(
        )  #Push the current view limits and position onto the stack,这样才可以还原
        xmin, xmax = ax.get_xbound()  #获取范围
        xlen = xmax - xmin

        ymin, ymax = ax.get_ybound()  #获取范围
        ylen = ymax - ymin

        xchg = event.step * xlen / 20  #step [scalar],positive = ’up’, negative ='down'
        xmin = xmin + xchg
        xmax = xmax - xchg

        ychg = event.step * ylen / 20
        ymin = ymin + ychg
        ymax = ymax - ychg

        ax.set_xbound(xmin, xmax)
        ax.set_ybound(ymin, ymax)

        event.canvas.draw()
示例#18
0
class PulsedNMR(QMainWindow, Ui_PulsedNMR):
  rates = {0:25.0e3, 1:50.0e3, 2:125.0e3, 3:250.0e3, 4:500.0e3, 5:1250.0e3}
  def __init__(self):
    super(PulsedNMR, self).__init__()
    self.setupUi(self)
    self.rateValue.addItems(['25', '50', '125', '250', '500', '1250'])
    # IP address validator
    rx = QRegExp('^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])|rp-[0-9A-Fa-f]{6}\.local$')
    self.addrValue.setValidator(QRegExpValidator(rx, self.addrValue))
    # state variable
    self.idle = True
    # number of samples to show on the plot
    self.size = 50000
    # buffer and offset for the incoming samples
    self.buffer = bytearray(16 * self.size)
    self.offset = 0
    self.data = np.frombuffer(self.buffer, np.int32)
    # create figure
    figure = Figure()
    figure.set_facecolor('none')
    self.axes = figure.add_subplot(111)
    self.canvas = FigureCanvas(figure)
    self.plotLayout.addWidget(self.canvas)
    # create navigation toolbar
    self.toolbar = NavigationToolbar(self.canvas, self.plotWidget, False)
    # remove subplots action
    actions = self.toolbar.actions()
    if int(matplotlib.__version__[0]) < 2:
      self.toolbar.removeAction(actions[7])
    else:
      self.toolbar.removeAction(actions[6])
    self.plotLayout.addWidget(self.toolbar)
    # create TCP socket
    self.socket = QTcpSocket(self)
    self.socket.connected.connect(self.connected)
    self.socket.readyRead.connect(self.read_data)
    self.socket.error.connect(self.display_error)
    # connect signals from buttons and boxes
    self.startButton.clicked.connect(self.start)
    self.freqValue.valueChanged.connect(self.set_freq)
    self.deltaValue.valueChanged.connect(self.set_delta)
    self.rateValue.currentIndexChanged.connect(self.set_rate)
    # set rate
    self.rateValue.setCurrentIndex(3)
    # create timer for the repetitions
    self.startTimer = QTimer(self)
    self.startTimer.timeout.connect(self.timeout)
    self.timer = QTimer(self)
    self.timer.timeout.connect(self.start_sequence)

  def start(self):
    if self.idle:
      self.startButton.setEnabled(False)
      self.socket.connectToHost(self.addrValue.text(), 1001)
      self.startTimer.start(5000)
    else:
      self.stop()

  def stop(self):
    self.idle = True
    self.timer.stop()
    self.socket.abort()
    self.offset = 0
    self.startButton.setText('Start')
    self.startButton.setEnabled(True)

  def timeout(self):
    self.display_error('timeout')

  def connected(self):
    self.startTimer.stop()
    self.idle = False
    self.set_freq(self.freqValue.value())
    self.set_rate(self.rateValue.currentIndex())
    self.start_sequence()
    self.timer.start(self.deltaValue.value())
    self.startButton.setText('Stop')
    self.startButton.setEnabled(True)

  def read_data(self):
    size = self.socket.bytesAvailable()
    if self.offset + size < 16 * self.size:
      self.buffer[self.offset:self.offset + size] = self.socket.read(size)
      self.offset += size
    else:
      self.buffer[self.offset:16 * self.size] = self.socket.read(16 * self.size - self.offset)
      self.offset = 0
      # plot the signal envelope
      self.curve.set_ydata(np.abs(self.data.astype(np.float32).view(np.complex64)[0::2] / (1 << 30)))
      self.canvas.draw()

  def display_error(self, socketError):
    self.startTimer.stop()
    if socketError == 'timeout':
      QMessageBox.information(self, 'PulsedNMR', 'Error: connection timeout.')
    else:
      QMessageBox.information(self, 'PulsedNMR', 'Error: %s.' % self.socket.errorString())
    self.stop()

  def set_freq(self, value):
    if self.idle: return
    self.socket.write(struct.pack('<Q', 0<<60 | int(1.0e6 * value)))
    self.socket.write(struct.pack('<Q', 1<<60 | int(1.0e6 * value)))

  def set_rate(self, index):
    # time axis
    rate = float(PulsedNMR.rates[index])
    time = np.linspace(0.0, (self.size - 1) * 1000.0 / rate, self.size)
    # reset toolbar
    self.toolbar.home()
    self.toolbar.update()
    # reset plot
    self.axes.clear()
    self.axes.grid()
    # plot zeros and get store the returned Line2D object
    self.curve, = self.axes.plot(time, np.zeros(self.size))
    x1, x2, y1, y2 = self.axes.axis()
    # set y axis limits
    self.axes.axis((x1, x2, -0.1, 1.1))
    self.axes.set_xlabel('time, ms')
    self.canvas.draw()
    if self.idle: return
    self.socket.write(struct.pack('<Q', 2<<60 | int(125.0e6 / rate / 2)))

  def set_delta(self, value):
    if self.idle: return
    self.timer.stop()
    self.timer.start(value)

  def clear_pulses(self):
    if self.idle: return
    self.socket.write(struct.pack('<Q', 7<<60))

  def add_delay(self, width):
    if self.idle: return
    self.socket.write(struct.pack('<Q', 8<<60 | int(width - 4)))

  def add_pulse(self, level, phase, width):
    if self.idle: return
    self.socket.write(struct.pack('<Q', 8<<60 | int(width)))
    self.socket.write(struct.pack('<Q', 9<<60 | int(phase << 16 | level)))

  def start_sequence(self):
    if self.idle: return
    awidth = 125 * self.awidthValue.value()
    bwidth = 125 * self.bwidthValue.value()
    delay = 125 * self.delayValue.value()
    size = self.size
    self.clear_pulses()
    self.add_pulse(32766, 0, awidth)
    self.add_delay(delay)
    self.add_pulse(32766, 0, bwidth)
    self.socket.write(struct.pack('<Q', 10<<60 | int(size)))
示例#19
0
class Scanner(QMainWindow, Ui_Scanner):
  def __init__(self):
    super(Scanner, self).__init__()
    self.setupUi(self)
    # IP address validator
    rx = QRegExp('^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$')
    self.addrValue.setValidator(QRegExpValidator(rx, self.addrValue))
    # state variable
    self.idle = True
    # number of samples to show on the plot
    self.size = 512 * 512
    self.freq = 143.0
    # buffer and offset for the incoming samples
    self.buffer = bytearray(8 * self.size)
    self.offset = 0
    self.data = np.frombuffer(self.buffer, np.int32)
    # create figure
    figure = Figure()
    figure.set_facecolor('none')
    self.axes = figure.add_subplot(111)
    self.canvas = FigureCanvas(figure)
    self.plotLayout.addWidget(self.canvas)
    self.axes.axis((0.0, 512.0, 0.0, 512.0))
    x, y = np.meshgrid(np.linspace(0.0, 512.0, 513), np.linspace(0.0, 512.0, 513))
    z = x / 512.0 + y * 0.0
    self.mesh = self.axes.pcolormesh(x, y, z, cmap = cm.plasma)
    # create navigation toolbar
    self.toolbar = NavigationToolbar(self.canvas, self.plotWidget, False)
    # remove subplots action
    actions = self.toolbar.actions()
    if int(matplotlib.__version__[0]) < 2:
      self.toolbar.removeAction(actions[7])
    else:
      self.toolbar.removeAction(actions[6])
    self.plotLayout.addWidget(self.toolbar)
    # create TCP socket
    self.socket = QTcpSocket(self)
    self.socket.connected.connect(self.connected)
    self.socket.readyRead.connect(self.read_data)
    self.socket.error.connect(self.display_error)
    # connect signals from buttons and boxes
    self.connectButton.clicked.connect(self.start)
    self.scanButton.clicked.connect(self.scan)
    self.periodValue.valueChanged.connect(self.set_period)
    self.trgtimeValue.valueChanged.connect(self.set_trgtime)
    self.trginvCheck.stateChanged.connect(self.set_trginv)
    self.shdelayValue.valueChanged.connect(self.set_shdelay)
    self.shtimeValue.valueChanged.connect(self.set_shtime)
    self.shinvCheck.stateChanged.connect(self.set_shinv)
    self.acqdelayValue.valueChanged.connect(self.set_acqdelay)
    self.samplesValue.valueChanged.connect(self.set_samples)
    self.pulsesValue.valueChanged.connect(self.set_pulses)
    # create timers
    self.startTimer = QTimer(self)
    self.startTimer.timeout.connect(self.timeout)
    self.meshTimer = QTimer(self)
    self.meshTimer.timeout.connect(self.update_mesh)
    # set default values
    self.periodValue.setValue(200.0)

  def start(self):
    if self.idle:
      self.connectButton.setEnabled(False)
      self.socket.connectToHost(self.addrValue.text(), 1001)
      self.startTimer.start(5000)
    else:
      self.stop()

  def stop(self):
    self.idle = True
    self.socket.abort()
    self.offset = 0
    self.connectButton.setText('Connect')
    self.connectButton.setEnabled(True)
    self.scanButton.setEnabled(True)

  def timeout(self):
    self.display_error('timeout')

  def connected(self):
    self.startTimer.stop()
    self.idle = False
    self.set_period(self.periodValue.value())
    self.set_trgtime(self.trgtimeValue.value())
    self.set_trginv(self.trginvCheck.checkState())
    self.set_shdelay(self.shdelayValue.value())
    self.set_shtime(self.shtimeValue.value())
    self.set_shinv(self.shinvCheck.checkState())
    self.set_acqdelay(self.acqdelayValue.value())
    self.set_samples(self.samplesValue.value())
    self.set_pulses(self.pulsesValue.value())
    # start pulse generators
    self.socket.write(struct.pack('<I', 9<<28))
    self.connectButton.setText('Disconnect')
    self.connectButton.setEnabled(True)
    self.scanButton.setEnabled(True)

  def read_data(self):
    size = self.socket.bytesAvailable()
    if self.offset + size < 8 * self.size:
      self.buffer[self.offset:self.offset + size] = self.socket.read(size)
      self.offset += size
    else:
      self.meshTimer.stop()
      self.buffer[self.offset:8 * self.size] = self.socket.read(8 * self.size - self.offset)
      self.offset = 0
      self.update_mesh()
      self.scanButton.setEnabled(True)

  def display_error(self, socketError):
    self.startTimer.stop()
    if socketError == 'timeout':
      QMessageBox.information(self, 'Scanner', 'Error: connection timeout.')
    else:
      QMessageBox.information(self, 'Scanner', 'Error: %s.' % self.socket.errorString())
    self.stop()

  def set_period(self, value):
    # set maximum delays and times to half period
    maximum = int(value * 5.0 + 0.5) / 10.0
    self.trgtimeValue.setMaximum(maximum)
    self.shdelayValue.setMaximum(maximum)
    self.shtimeValue.setMaximum(maximum)
    self.acqdelayValue.setMaximum(maximum)
    # set maximum number of samples per pulse
    maximum = int(value * 500.0 + 0.5) / 10.0
    if maximum > 256.0: maximum = 256.0
    self.samplesValue.setMaximum(maximum)
    shdelay = value * 0.25
    samples = value * 0.5
    if self.idle: return
    self.socket.write(struct.pack('<I', 0<<28 | int(value * self.freq)))

  def set_trgtime(self, value):
    if self.idle: return
    self.socket.write(struct.pack('<I', 1<<28 | int(value * self.freq)))

  def set_trginv(self, checked):
    if self.idle: return
    self.socket.write(struct.pack('<I', 2<<28 | int(checked == Qt.Checked)))

  def set_shdelay(self, value):
    if self.idle: return
    self.socket.write(struct.pack('<I', 3<<28 | int(value * self.freq)))

  def set_shtime(self, value):
    if self.idle: return
    self.socket.write(struct.pack('<I', 4<<28 | int(value * self.freq)))

  def set_shinv(self, checked):
    if self.idle: return
    self.socket.write(struct.pack('<I', 5<<28 | int(checked == Qt.Checked)))

  def set_acqdelay(self, value):
    if self.idle: return
    self.socket.write(struct.pack('<I', 6<<28 | int(value * self.freq)))

  def set_samples(self, value):
    if self.idle: return
    self.socket.write(struct.pack('<I', 7<<28 | int(value)))

  def set_pulses(self, value):
    if self.idle: return
    self.socket.write(struct.pack('<I', 8<<28 | int(value)))

  def scan(self):
    if self.idle: return
    self.scanButton.setEnabled(False)
    self.data[:] = np.zeros(2 * 512 * 512, np.int32)
    self.update_mesh()
    self.socket.write(struct.pack('<I', 10<<28))
    self.meshTimer.start(1000)

  def update_mesh(self):
    self.mesh.set_array(self.data[0::2]/(self.samplesValue.value() * self.pulsesValue.value() * 8192.0))
    self.canvas.draw()
示例#20
0
class PulsedNMR(QMainWindow, Ui_PulsedNMR):
    rates = {0: 25.0e3, 1: 50.0e3, 2: 250.0e3, 3: 500.0e3, 4: 2500.0e3}

    def __init__(self):
        super(PulsedNMR, self).__init__()
        self.setupUi(self)
        self.rateValue.addItems(['25', '50', '250', '500', '2500'])
        # IP address validator
        rx = QRegExp(
            '^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$'
        )
        self.addrValue.setValidator(QRegExpValidator(rx, self.addrValue))
        # state variable
        self.idle = True
        # number of samples to show on the plot
        self.size = 50000
        # buffer and offset for the incoming samples
        self.buffer = bytearray(8 * self.size)
        self.offset = 0
        self.data = np.frombuffer(self.buffer, np.complex64)
        # create figure
        figure = Figure()
        figure.set_facecolor('none')
        self.axes = figure.add_subplot(111)
        self.canvas = FigureCanvas(figure)
        self.plotLayout.addWidget(self.canvas)
        # create navigation toolbar
        self.toolbar = NavigationToolbar(self.canvas, self.plotWidget, False)
        # remove subplots action
        actions = self.toolbar.actions()
        self.toolbar.removeAction(actions[7])
        self.plotLayout.addWidget(self.toolbar)
        # create TCP socket
        self.socket = QTcpSocket(self)
        self.socket.connected.connect(self.connected)
        self.socket.readyRead.connect(self.read_data)
        self.socket.error.connect(self.display_error)
        # connect signals from buttons and boxes
        self.startButton.clicked.connect(self.start)
        self.freqValue.valueChanged.connect(self.set_freq)
        self.awidthValue.valueChanged.connect(self.set_awidth)
        self.deltaValue.valueChanged.connect(self.set_delta)
        self.rateValue.currentIndexChanged.connect(self.set_rate)
        # set rate
        self.rateValue.setCurrentIndex(2)
        # create timer for the repetitions
        self.timer = QTimer(self)
        self.timer.timeout.connect(self.fire)

    def start(self):
        if self.idle:
            self.startButton.setEnabled(False)
            self.socket.connectToHost(self.addrValue.text(), 1001)
        else:
            self.idle = True
            self.timer.stop()
            self.socket.close()
            self.offset = 0
            self.startButton.setText('Start')
            self.startButton.setEnabled(True)

    def connected(self):
        self.idle = False
        self.set_freq(self.freqValue.value())
        self.set_rate(self.rateValue.currentIndex())
        self.set_awidth(self.awidthValue.value())
        self.fire()
        self.timer.start(self.deltaValue.value())
        self.startButton.setText('Stop')
        self.startButton.setEnabled(True)

    def read_data(self):
        size = self.socket.bytesAvailable()
        if self.offset + size < 8 * self.size:
            self.buffer[self.offset:self.offset +
                        size] = self.socket.read(size)
            self.offset += size
        else:
            self.buffer[self.offset:8 *
                        self.size] = self.socket.read(8 * self.size -
                                                      self.offset)
            self.offset = 0
            # plot the signal envelope
            self.curve.set_ydata(np.real(self.data))
            self.canvas.draw()

    def display_error(self, socketError):
        if socketError == QAbstractSocket.RemoteHostClosedError:
            pass
        else:
            QMessageBox.information(self, 'PulsedNMR',
                                    'Error: %s.' % self.socket.errorString())
        self.startButton.setText('Start')
        self.startButton.setEnabled(True)

    def set_freq(self, value):
        if self.idle: return
        self.socket.write(struct.pack('<I', 0 << 28 | int(1.0e6 * value)))

    def set_rate(self, index):
        # time axis
        rate = float(PulsedNMR.rates[index])
        time = np.linspace(0.0, (self.size - 1) * 1000.0 / rate, self.size)
        # reset toolbar
        self.toolbar.home()
        self.toolbar._views.clear()
        self.toolbar._positions.clear()
        # reset plot
        self.axes.clear()
        self.axes.grid()
        # plot zeros and get store the returned Line2D object
        self.curve, = self.axes.plot(time, np.zeros(self.size))
        x1, x2, y1, y2 = self.axes.axis()
        # set y axis limits
        self.axes.axis((x1, x2, -0.1, 0.4))
        self.axes.set_xlabel('time, ms')
        self.canvas.draw()
        # set repetition time
        minimum = self.size / rate * 2000.0
        if minimum < 100.0: minimum = 100.0
        self.deltaValue.setMinimum(minimum)
        self.deltaValue.setValue(minimum)
        if self.idle: return
        self.socket.write(struct.pack('<I', 1 << 28 | index))

    def set_awidth(self, value):
        if self.idle: return
        self.socket.write(struct.pack('<I', 2 << 28 | int(1.0e1 * value)))

    def set_delta(self, value):
        if self.idle: return
        self.timer.stop()
        self.timer.start(value)

    def fire(self):
        if self.idle: return
        self.socket.write(struct.pack('<I', 3 << 28))
示例#21
0
class PulsedNMR(QMainWindow, Ui_PulsedNMR):
  rates = {0:25.0e3, 1:50.0e3, 2:250.0e3, 3:500.0e3, 4:2500.0e3}
  def __init__(self):
    super(PulsedNMR, self).__init__()
    self.setupUi(self)
    self.rateValue.addItems(['25', '50', '250', '500', '2500'])
    # IP address validator
    rx = QRegExp('^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$')
    self.addrValue.setValidator(QRegExpValidator(rx, self.addrValue))
    # state variable
    self.idle = True
    # number of samples to show on the plot
    self.size = 50000
    # buffer and offset for the incoming samples
    self.buffer = bytearray(8 * self.size)
    self.offset = 0
    # create figure
    figure = Figure()
    figure.set_facecolor('none')
    self.axes = figure.add_subplot(111)
    self.canvas = FigureCanvas(figure)
    self.plotLayout.addWidget(self.canvas)
    # create navigation toolbar
    self.toolbar = NavigationToolbar(self.canvas, self.plotWidget, False)
    # remove subplots action
    actions = self.toolbar.actions()
    self.toolbar.removeAction(actions[7])
    self.plotLayout.addWidget(self.toolbar)
    # create TCP socket
    self.socket = QTcpSocket(self)
    self.socket.connected.connect(self.connected)
    self.socket.readyRead.connect(self.read_data)
    self.socket.error.connect(self.display_error)
    # connect signals from buttons and boxes
    self.startButton.clicked.connect(self.start)
    self.freqValue.valueChanged.connect(self.set_freq)
    self.awidthValue.valueChanged.connect(self.set_awidth)
    self.deltaValue.valueChanged.connect(self.set_delta)
    self.rateValue.currentIndexChanged.connect(self.set_rate)
    # set rate
    self.rateValue.setCurrentIndex(2)
    # create timer for the repetitions
    self.timer = QTimer(self)
    self.timer.timeout.connect(self.fire)

  def start(self):
    if self.idle:
      self.startButton.setEnabled(False)
      self.socket.connectToHost(self.addrValue.text(), 1001)
    else:
      self.idle = True
      self.timer.stop()
      self.socket.close()
      self.offset = 0
      self.startButton.setText('Start')
      self.startButton.setEnabled(True)

  def connected(self):
    self.idle = False
    self.set_freq(self.freqValue.value())
    self.set_rate(self.rateValue.currentIndex())
    self.set_awidth(self.awidthValue.value())
    self.fire()
    self.timer.start(self.deltaValue.value())
    self.startButton.setText('Stop')
    self.startButton.setEnabled(True)

  def read_data(self):
    size = self.socket.bytesAvailable()
    if self.offset + size < 8 * self.size:
      self.buffer[self.offset:self.offset + size] = self.socket.read(size)
      self.offset += size
    else:
      self.buffer[self.offset:8 * self.size] = self.socket.read(8 * self.size - self.offset)
      self.offset = 0
      # plot the signal envelope
      data = np.frombuffer(self.buffer, np.complex64)
      self.curve.set_ydata(np.abs(data))
      self.canvas.draw()

  def display_error(self, socketError):
    if socketError == QAbstractSocket.RemoteHostClosedError:
      pass
    else:
      QMessageBox.information(self, 'PulsedNMR', 'Error: %s.' % self.socket.errorString())
    self.startButton.setText('Start')
    self.startButton.setEnabled(True)

  def set_freq(self, value):
    if self.idle: return
    self.socket.write(struct.pack('<I', 0<<28 | int(1.0e6 * value)))

  def set_rate(self, index):
    # time axis
    rate = float(PulsedNMR.rates[index])
    time = np.linspace(0.0, (self.size - 1) * 1000.0 / rate, self.size)
    # reset toolbar
    self.toolbar.home()
    self.toolbar._views.clear()
    self.toolbar._positions.clear()
    # reset plot
    self.axes.clear()
    self.axes.grid()
    # plot zeros and get store the returned Line2D object
    self.curve, = self.axes.plot(time, np.zeros(self.size))
    x1, x2, y1, y2 = self.axes.axis()
    # set y axis limits
    self.axes.axis((x1, x2, -0.1, 0.4))
    self.axes.set_xlabel('time, ms')
    self.canvas.draw()
    # set repetition time
    minimum = self.size / rate * 2000.0
    if minimum < 100.0: minimum = 100.0
    self.deltaValue.setMinimum(minimum)
    self.deltaValue.setValue(minimum)
    if self.idle: return
    self.socket.write(struct.pack('<I', 1<<28 | index))

  def set_awidth(self, value):
    if self.idle: return
    self.socket.write(struct.pack('<I', 2<<28 | int(1.0e1 * value)))

  def set_delta(self, value):
    if self.idle: return
    self.timer.stop()
    self.timer.start(value)

  def fire(self):
    if self.idle: return
    self.socket.write(struct.pack('<I', 3<<28))
示例#22
0
class QmyFigureCanvas(QWidget):
    def __init__(self, parent=None, toolbarVisible=True, showHint=False):
        super().__init__(parent)

        self.figure = Figure()  #公共的figure属性
        figCanvas = FigureCanvas(self.figure)  #创建FigureCanvas对象,必须传递一个Figure对象

        self.naviBar = NavigationToolbar(figCanvas, self)  #公共属性naviBar
        self.__changeActionLanguage()  #改为汉语

        actList = self.naviBar.actions()  #关联的Action列表
        count = len(actList)  #Action的个数
        self.__lastActtionHint = actList[count - 1]  #最后一个Action,坐标提示标签
        self.__showHint = showHint  #是否在工具栏上显示坐标提示
        self.__lastActtionHint.setVisible(self.__showHint)  #隐藏其原有的坐标提示

        self.__showToolbar = toolbarVisible  #是否显示工具栏
        self.naviBar.setVisible(self.__showToolbar)

        layout = QVBoxLayout(self)
        layout.addWidget(self.naviBar)  #添加工具栏
        layout.addWidget(figCanvas)  #添加FigureCanvas对象
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)

        #鼠标滚轮缩放
        self.__cid = figCanvas.mpl_connect("scroll_event", self.do_scrollZoom)


##=====公共接口函数

    def setToolbarVisible(self, isVisible=True):  ##是否显示工具栏
        self.__showToolbar = isVisible
        self.naviBar.setVisible(isVisible)

    def setDataHintVisible(self, isVisible=True):  ##是否显示工具栏最后的坐标提示标签
        self.__showHint = isVisible
        self.__lastActtionHint.setVisible(isVisible)

    def redraw(self):  ##重绘曲线,快捷调用
        self.figure.canvas.draw()

    def __changeActionLanguage(self):  ##汉化工具栏
        actList = self.naviBar.actions()  #关联的Action列表
        actList[0].setText("复位")  #Home
        actList[0].setToolTip("复位到原始视图")  #Reset original view

        actList[1].setText("回退")  #Back
        actList[1].setToolTip("回退前一视图")  #Back to previous view

        actList[2].setText("前进")  #Forward
        actList[2].setToolTip("前进到下一视图")  #Forward to next view

        actList[4].setText("平动")  #Pan
        actList[4].setToolTip(
            "左键平移坐标轴,右键缩放坐标轴")  #Pan axes with left mouse, zoom with right

        actList[5].setText("缩放")  #Zoom
        actList[5].setToolTip("框选矩形框缩放")  #Zoom to rectangle

        actList[6].setText("子图")  #Subplots
        actList[6].setToolTip("设置子图")  #Configure subplots

        actList[7].setText("定制")  #Customize
        actList[7].setToolTip("定制图表参数")  #Edit axis, curve and image parameters

        actList[9].setText("保存")  #Save
        actList[9].setToolTip("保存图表")  #Save the figure

    def do_scrollZoom(self, event):  #通过鼠标滚轮缩放
        ax = event.inaxes  # 产生事件axes对象
        if ax == None:
            return

        self.naviBar.push_current(
        )  #Push the current view limits and position onto the stack,这样才可以还原
        xmin, xmax = ax.get_xbound()
        xlen = xmax - xmin
        ymin, ymax = ax.get_ybound()
        ylen = ymax - ymin

        xchg = event.step * xlen / 20  #step [scalar],positive = ’up’, negative ='down'
        xmin = xmin + xchg
        xmax = xmax - xchg
        ychg = event.step * ylen / 20
        ymin = ymin + ychg
        ymax = ymax - ychg

        ax.set_xbound(xmin, xmax)
        ax.set_ybound(ymin, ymax)
        event.canvas.draw()
示例#23
0
class QmyFigureCanvas(QWidget):

    # self.widget = QWidget()

    def __init__(self, parent=None, toolbarVisible=True, showHint=False):
        super().__init__(parent)

        self.figure = mpl.figure.Figure(figsize=(50, 50))
        figCanvas = FigureCanvas(self.figure)
        # scroll = QScrollArea(self.widget)
        # self.scroll.setWidget(figCanvas)

        self.naviBar = NavigationToolbar(figCanvas, self)

        actList = self.naviBar.actions()
        count = len(actList)
        self.__lastActtionHint = actList[count - 1]
        self.__showHint = showHint
        self.__lastActtionHint.setVisible(self.__showHint)
        self.__showToolbar = toolbarVisible
        self.naviBar.setVisible(self.__showToolbar)

        layout = QVBoxLayout(self)
        layout.addWidget(self.naviBar)
        layout.addWidget(figCanvas)
        # layout.addWidget(scroll)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setAlignment(Qt.AlignTop)
        layout.setSpacing(0)

        self.__cid = figCanvas.mpl_connect("scroll_event", self.do_scrollZoom)

# =====Public interface

    def setToolbarVisible(self, isVisible=True):
        self.__showToolbar = isVisible
        self.naviBar.setVisible(isVisible)

    def setDataHintVisible(self, isVisible=True):
        self.__showHint = isVisible
        self.__lastActtionHint.setVisible(isVisible)

    def redraw(self):
        self.figure.canvas.draw()

    def do_scrollZoom(self, event):
        ax = event.inaxes
        if ax is None:
            return

        # Push the current view limits and position onto the stack,这样才可以还原
        self.naviBar.push_current()
        xmin, xmax = ax.get_xbound()
        xlen = xmax - xmin
        ymin, ymax = ax.get_ybound()
        ylen = ymax - ymin

        # step [scalar],positive = ’up’, negative ='down'
        xchg = event.step * xlen / 20
        xmin = xmin + xchg
        xmax = xmax - xchg
        ychg = event.step * ylen / 20
        ymin = ymin + ychg
        ymax = ymax - ychg

        ax.set_xbound(xmin, xmax)
        ax.set_ybound(ymin, ymax)
        event.canvas.draw()