예제 #1
0
class CharPlotWidget(QChartView):

    def __init__(self, parent=None):
        super().__init__(parent=parent)

        self.setRenderHint(QPainter.Antialiasing)

        self._chart = self.chart()
        self._axis_x = QValueAxis()
        self._axis_y = QValueAxis()

        self.series = QLineSeries(self)

        self._chart.addSeries(self.series)
        self._chart.addAxis(self._axis_x, Qt.AlignBottom)
        self._chart.addAxis(self._axis_y, Qt.AlignLeft)

        self.series.attachAxis(self._axis_x)
        self.series.attachAxis(self._axis_y)

        self._axis_x.setTickCount(5)
        self._axis_x.setRange(0, 10)

        self._axis_y.setTickCount(5)
        self._axis_y.setRange(0, 10)

        self._chart.legend().hide()

    def plot(self, xs, ys):
        self.series.replace([QPointF(x, y) for x, y in zip(xs, ys)])

    @property
    def axes_titles(self):
        return self._axis_x.titleText(), self._axis_y.titleText()

    @axes_titles.setter
    def axes_titles(self, value):
        x, y = value
        self._axis_x.setTitleText(x)
        self._axis_y.setTitleText(y)

    @property
    def title(self):
        return self._chart.title()

    @title.setter
    def title(self, value):
        self._chart.setTitle(value)

    @property
    def legend(self):
        return self._chart.legend()
예제 #2
0
    def add_data(self, xdata, ydata, color=None, legend_text=None):
        curve = QLineSeries()
        pen = curve.pen()
        if color is not None:
            pen.setColor(color)
        pen.setWidthF(1.5)

        curve.setPen(pen)
        # curve.setPointsVisible(True)

        # curve.setUseOpenGL(True)

        self.total_samples = max(self.total_samples, len(xdata))

        # Decimate
        xdecimated, ydecimated = self.decimate(xdata, ydata)

        # Data must be in ms since epoch
        # curve.append(self.series_to_polyline(xdecimated * 1000.0, ydecimated))
        # self.reftime = datetime.datetime.fromtimestamp(xdecimated[0])

        # if len(xdecimated) > 0:
        #    xdecimated = xdecimated - xdecimated[0]

        xdecimated *= 1000  # No decimal expected
        points = []
        for i, _ in enumerate(xdecimated):
            # TODO hack
            # curve.append(QPointF(xdecimated[i], ydecimated[i]))
            points.append(QPointF(xdecimated[i], ydecimated[i]))

        curve.replace(points)
        points.clear()

        if legend_text is not None:
            curve.setName(legend_text)

        # Needed for mouse events on series
        self.chart.setAcceptHoverEvents(True)
        self.xvalues[self.ncurves] = np.array(xdecimated)

        # connect signals / slots
        # curve.clicked.connect(self.lineseries_clicked)
        # curve.hovered.connect(self.lineseries_hovered)

        # Add series
        self.chart.addSeries(curve)
        self.ncurves += 1
        self.update_axes()
예제 #3
0
class DemoWindow(QMainWindow):
    def __init__(self, parent=None):
        super(DemoWindow, self).__init__(parent=parent)

        self.plotChart = QChart()
        self.plotChart.legend().hide()

        self.plotView = QChartView(self.plotChart)
        self.setCentralWidget(self.plotView)

        self.plotCurve = QLineSeries()
        self.plotCurve.setUseOpenGL(True)
        self.plotCurve.pen().setColor(Qt.red)
        self.plotChart.addSeries(self.plotCurve)

        self.plotChart.createDefaultAxes()
        self.plotChart.axisX().setLabelFormat('%d')

        self.RecvData = array.array('f')  # 存储接收到的传感器数据
        self.RecvIndx = 0

        self.tmrData = QTimer()  # 模拟传感器传送过来数据
        self.tmrData.setInterval(3)
        self.tmrData.timeout.connect(self.on_tmrData_timeout)
        self.tmrData.start()

        self.tmrPlot = QTimer()
        self.tmrPlot.setInterval(100)
        self.tmrPlot.timeout.connect(self.on_tmrPlot_timeout)
        self.tmrPlot.start()

    def on_tmrData_timeout(self):
        val = math.sin(2 * 3.14 / 500 * self.RecvIndx)
        self.RecvData.append(val)

        self.RecvIndx += 1

    def on_tmrPlot_timeout(self):
        self.RecvData = self.RecvData[-1000:]

        plotData = []
        for i, val in enumerate(self.RecvData):
            plotData.append(QPointF(i, val))

        self.plotCurve.replace(plotData)
        self.plotChart.axisX().setMax(len(plotData))
        self.plotChart.axisY().setRange(min(self.RecvData), max(self.RecvData))
예제 #4
0
    def createLineChart(self, dataTable):
        self.chart.setTitle("Sensor1")
        series = QLineSeries(self.chart)
        series2 = QLineSeries(self.chart)
        series3 = QLineSeries(self.chart)
        # series2 = QLineSeries(self.chart)
        # series3 = QLineSeries(self.chart)
        series.setUseOpenGL(True)
        series2.setUseOpenGL(True)
        series3.setUseOpenGL(True)
        # series2.setUseOpenGL(True)
        # series3.setUseOpenGL(True)

        series.replace(self.series.pointsVector())
        series2.replace(self.series2.pointsVector())
        series3.replace(self.series3.pointsVector())
        # series2.replace(self.series2.pointsVector())
        # series3.replace(self.series2.pointsVector())
        self.chart.removeAllSeries()
        self.chart.addSeries(series2)
        self.chart.addSeries(series)
        self.chart.addSeries(series3)
예제 #5
0
class PulseGen(QtWidgets.QMainWindow, Ui_MainWindow):

    GENERATOR_PORT = 5000

    def __init__(self, parent=None):

        super(PulseGen, self).__init__(parent)
        self.setupUi(self)
        self.pulse_gen_display = PulseGenDisplay()
        self.display_data = [0] * 500

        self.pulse_height_max = self.pulse_height_dial.maximum()
        self.pulse_height_min = self.pulse_height_dial.minimum()

        self.pulse_gen_display.pulse_height = self.pulse_height_max
        # set pulse height
        self.pulse_gen_display.pulse_height = self.pulse_height_max
        self.pulse_height_dial.setValue(self.pulse_gen_display.pulse_height)
        self.pulse_height_dial.actionTriggered.connect(self.avoid_wrapping)
        self.pulse_height_dial.valueChanged.connect(self.pulse_height_changed)

        self.pulse_height_text.setText(str(
            self.pulse_gen_display.pulse_height))

        # don't allow editing
        self.pulse_height_text.textChanged.connect(self.no_editing)

        # pulse shape
        for pulse_form in self.pulse_gen_display.pulse_shape.keys():
            self.pulse_shape_combo.addItem(pulse_form)
        self.pulse_shape_combo.currentIndexChanged.connect(
            self.pulse_shape_changed)

        current_pulse_form = self.pulse_shape_combo.currentText()
        self.pulse_gen_display.pulse_form = self.pulse_gen_display.pulse_shape[
            current_pulse_form]
        print("Current pulse form: " + current_pulse_form + " code: " +
              str(self.pulse_gen_display.pulse_form))

        for pulse_freq in self.pulse_gen_display.frequencies.keys():
            self.gen_freq_combo.addItem(pulse_freq)

        current_pulse_freq = self.gen_freq_combo.currentText()
        self.pulse_gen_display.pulse_T = self.pulse_gen_display.frequencies[
            current_pulse_freq]
        print("Current pulse T: " + str(self.pulse_gen_display.pulse_T))
        self.gen_freq_combo.currentIndexChanged.connect(
            self.pulse_freq_changed)

        for display_freq in self.pulse_gen_display.frequencies.keys():
            self.display_freq_combo.addItem(display_freq)
        self.display_freq_combo.currentIndexChanged.connect(
            self.display_freq_changed)

        current_display_freq = self.display_freq_combo.currentText()
        self.pulse_gen_display.display_T = self.pulse_gen_display.frequencies[
            current_display_freq]
        print("Current display T: " + str(self.pulse_gen_display.display_T))

        self.start_stop_pb.clicked.connect(self.start_stop_meas)
        self.connect_pb.clicked.connect(self.connect)

        self.gen_chart = QChart()
        self.gen_chart.legend().hide()
        self.x_axis = QValueAxis()
        self.x_axis.setMax(500 * self.pulse_gen_display.display_T)
        self.x_axis.setMin(0)
        self.y_axis = QValueAxis()
        self.y_axis.setMax(3.3)
        self.y_axis.setMin(0)
        self.gen_chart.addAxis(self.x_axis, Qt.AlignBottom)
        self.gen_chart.addAxis(self.y_axis, Qt.AlignLeft)
        self.generator_screen.setChart(self.gen_chart)
        # display the initial pulse
        self.pulse_gen_display.calc_pulse()
        self.pulse_gen_display.get_display_data()

        self.series = QLineSeries()

        for i in range(500):
            self.series.append(
                i * self.pulse_gen_display.display_T,
                self.pulse_gen_display.display_data[i] *
                self.pulse_gen_display.calib)
        self.gen_chart.addSeries(self.series)
        self.series.attachAxis(self.x_axis)
        self.series.attachAxis(self.y_axis)
        self.display_pulse()

        self.pulse_height_timer = QTimer()
        self.pulse_height_timer.setSingleShot(True)
        self.pulse_height_timer.timeout.connect(self.pulse_height_ready)

        self.genRunning = False
        self.actionQuit.triggered.connect(self.quit)

        self.client_socket = QTcpSocket(self)
        self.connected = False
        self.show()

    def no_editing(self):
        self.pulse_height_text.setText(str(
            self.pulse_gen_display.pulse_height))

    def avoid_wrapping(self, val):
        if val == QtWidgets.QAbstractSlider.SliderMove:
            minDistance = 1
            if self.pulse_height_dial.value() == self.pulse_height_max \
               and self.pulse_height_dial.sliderPosition()<self.pulse_height_max-minDistance:
                self.pulse_height_dial.setSliderPosition(self.pulse_height_max)
            elif self.pulse_height_dial.value() == self.pulse_height_min \
               and self.pulse_height_dial.sliderPosition()>self.pulse_height_min+minDistance:
                self.pulse_height_dial.setSliderPosition(self.pulse_height_min)

    def pulse_shape_changed(self):
        '''
        if self.genRunning:
            print("Current shape index: ",self.pulse_shape_combo.currentIndex())
            print("current pulse form: ",self.pulse_gen_display.pulse_form)
            if self.pulse_shape_combo.currentIndex() == self.pulse_gen_display.pulse_form:
                return
            QMessageBox.warning(self,
                                'Pulse generation is active',
                                'Pulse generator is running\nPlease stop pulse generation before changing parameters')
            self.pulse_shape_combo.setCurrentIndex(self.pulse_gen_display.pulse_form)
            return
        '''
        print("pulse shape changed")
        current_pulse_form = self.pulse_shape_combo.currentText()
        self.pulse_gen_display.pulse_form = self.pulse_gen_display.pulse_shape[
            current_pulse_form]
        print("Current pulse form: " + current_pulse_form + " code: " +
              str(self.pulse_gen_display.pulse_form))
        self.display_pulse()
        if not self.connected:
            return
        else:
            pulse_form_msg = "pulse_shape=" + str(
                self.pulse_gen_display.pulse_form) + "\n"
            print("Sending: " + pulse_form_msg)
            self.client_socket.write(bytes(pulse_form_msg, encoding="ascii"))
            self.client_socket.waitForReadyRead()
            responseMsg = self.client_socket.readAll()
            print("reponse msg: ", bytes(responseMsg).decode())

    def pulse_freq_changed(self):

        new_freq = self.gen_freq_combo.currentText()
        self.pulse_gen_display.pulse_T = self.pulse_gen_display.frequencies[
            new_freq]
        print("Pulse frequency changed to " + new_freq + "T: " +
              str(self.pulse_gen_display.pulse_T))
        self.display_pulse()
        '''
        if self.genRunning:
            if self.pulse_gen_display.frequencies[self.gen_freq_combo.currentText()] == self.pulse_gen_display.pulse_T:
                return

            QMessageBox.warning(self,
                                'Pulse generation is active',
                                'Pulse generator is running\nPlease stop pulse generation before changing parameters')
            index = 0
            for freq in self.pulse_gen_display.frequencies.keys():
                print("freq: ",freq)
                print("val: ",self.pulse_gen_display.frequencies[freq])
                if self.pulse_gen_display.frequencies[freq] == self.pulse_gen_display.pulse_T:
                    self.gen_freq_combo.setCurrentIndex(index)
                    break                     
                index += 1
            return
        '''
        if not self.connected:
            return
        else:
            pulse_T_msg = "pulse_T=" + str(
                self.pulse_gen_display.pulse_T) + "\n"
            print("Sending: " + pulse_T_msg)
            self.client_socket.write(bytes(pulse_T_msg, encoding="ascii"))
            self.client_socket.waitForReadyRead()
            responseMsg = self.client_socket.readAll()
            print("reponse msg: ", bytes(responseMsg).decode())

    def display_freq_changed(self):
        new_freq = self.display_freq_combo.currentText()
        self.pulse_gen_display.display_T = self.pulse_gen_display.frequencies[
            new_freq]
        self.display_pulse()

    def pulse_height_changed(self):
        self.pulse_gen_display.pulse_height = self.pulse_height_dial.value()
        self.pulse_height_text.setText(str(
            self.pulse_gen_display.pulse_height))
        self.display_pulse()
        self.pulse_height_timer.start(500)

    def pulse_height_ready(self):
        print("Timeout")
        if not self.connected:
            return
        else:
            pulse_height_msg = "pulse_height=" + str(
                self.pulse_gen_display.pulse_height) + "\n"
            print("Sending: " + pulse_height_msg)
            self.client_socket.write(bytes(pulse_height_msg, encoding="ascii"))
            self.client_socket.waitForReadyRead()
            responseMsg = self.client_socket.readAll()
            print("reponse msg: ", bytes(responseMsg).decode())

    def connect(self):
        if self.connected:
            self.client_socket.close()
            self.connected = False
            self.connect_pb.setChecked(False)
            self.connect_pb.setText("Connect to Pulse Generator")
            return
        server_ip = str(self.server_ip_text.text())
        port = self.GENERATOR_PORT
        print("Server IP: ", server_ip)
        if server_ip.find('xxx') != -1:
            print("bad IP")
            QMessageBox.about(
                self, 'Bad Server IP', 'Please give a correct Server IP\n'
                'IP is ' + server_ip)
            self.connect_pb.setChecked(False)
            return
        else:
            print("Connecting to " + server_ip + ":", port)
            self.client_socket.connectToHost(server_ip, port)
            self.client_socket.waitForConnected(1000)

        if self.client_socket.state() != QTcpSocket.ConnectedState:
            QMessageBox.warning(
                self, 'Connection failed',
                'Please check IP address and port number\nIs the server running?'
            )
            self.connect_pb.setChecked(False)
            return

        print("Connection established")
        self.connect_pb.setText("Connected")

        self.client_socket.waitForReadyRead()
        connectMsg = self.client_socket.readAll()
        msgstring = bytes(connectMsg).decode()
        print("Connection message:" + msgstring)

        print("Send generator settings")
        pulse_form_msg = "pulse_shape=" + str(
            self.pulse_gen_display.pulse_form) + "\n"
        print("Sending: " + pulse_form_msg)
        self.client_socket.write(bytes(pulse_form_msg, encoding="ascii"))
        self.client_socket.waitForReadyRead()
        responseMsg = self.client_socket.readAll()
        print("reponse msg: ", bytes(responseMsg).decode())

        pulse_T_msg = "pulse_T=" + str(self.pulse_gen_display.pulse_T) + "\n"
        print("Sending: " + pulse_T_msg)
        self.client_socket.write(bytes(pulse_T_msg, encoding="ascii"))
        self.client_socket.waitForReadyRead()
        responseMsg = self.client_socket.readAll()
        print("reponse msg: ", bytes(responseMsg).decode())

        pulse_height_msg = "pulse_height=" + str(
            self.pulse_gen_display.pulse_height) + "\n"
        print("Sending: " + pulse_height_msg)
        self.client_socket.write(bytes(pulse_height_msg, encoding="ascii"))
        self.client_socket.waitForReadyRead()
        responseMsg = self.client_socket.readAll()
        print("reponse msg: ", bytes(responseMsg).decode())

        running_msg = 'running?=\n'
        print("Sending: " + running_msg)
        self.client_socket.write(bytes(running_msg, encoding="ascii"))
        self.client_socket.waitForReadyRead()
        responseMsg = self.client_socket.readAll()
        response = bytes(responseMsg).decode()
        print("reponse msg: ", response)
        if response == 'yes\n':
            print("task is running")
        elif response == 'no\n':
            print("task is not running")
        else:
            print("Don't know if task is running")

        self.connected = True

    def start_stop_meas(self):
        if not self.connected:
            QMessageBox.about(
                self, 'You must be connected to the generator server\n'
                'please connect and try again')
            return

        if self.start_stop_pb.isChecked():
            print("Start generation")
            # send current generator settings

            self.start_stop_pb.setText("Stop Pulse Generation")
            msg = 'start=\n'
            print("Sending: " + msg)
            self.client_socket.write(msg.encode())
            self.client_socket.waitForReadyRead()
            responseMsg = self.client_socket.readAll()
            print("reponse msg: ", bytes(responseMsg).decode())
            self.genRunning = True
        else:
            print("Stop generation")
            self.start_stop_pb.setText("Start Pulse Generation")
            msg = 'stop=\n'
            self.client_socket.write(msg.encode())
            self.client_socket.waitForReadyRead()
            responseMsg = self.client_socket.readAll()
            print("reponse msg: ", bytes(responseMsg).decode())
            self.genRunning = False

    def readTrace(self):
        print("Message from the generator")
        data = self.server_socket.readAll()
        msgstring = bytes(data).decode()
        print(msgstring)
        print(data, type(data))

    def display_pulse(self):
        self.pulse_gen_display.calc_pulse()
        self.pulse_gen_display.get_display_data()

        self.x_axis.setMax(500 * self.pulse_gen_display.display_T)
        data_points = self.series.pointsVector()
        for i in range(500):
            data_points[i].setX(i * self.pulse_gen_display.display_T)
            data_points[i].setY(self.pulse_gen_display.display_data[i] *
                                self.pulse_gen_display.calib)
        self.series.replace(data_points)

    def quit(self):
        app.exit()
예제 #6
0
class TelemetryDialog(QDialog):
    resized = QtCore.pyqtSignal()
    visibility = QtCore.pyqtSignal(bool)

    def __init__(self, winTitle="Network Telemetry", parent=None):
        super(TelemetryDialog, self).__init__(parent)

        self.visibility.connect(self.onVisibilityChanged)

        self.winTitle = winTitle

        self.updateLock = Lock()

        # Used to detect network change
        self.lastNetKey = ""
        self.lastSeen = None
        self.maxPoints = 20
        self.maxRowPoints = 60

        self.paused = False
        self.streamingSave = False
        self.streamingFile = None
        self.linesBeforeFlush = 10
        self.currentLine = 0

        # OK and Cancel buttons
        #buttons = QDialogButtonBox(QDialogButtonBox.Ok,Qt.Horizontal, self)
        #buttons.accepted.connect(self.accept)
        #buttons.move(170, 280)

        desktopSize = QApplication.desktop().screenGeometry()
        #self.mainWidth=1024
        #self.mainHeight=768
        #self.mainWidth = desktopSize.width() * 3 / 4
        #self.mainHeight = desktopSize.height() * 3 / 4

        self.setGeometry(self.geometry().x(),
                         self.geometry().y(),
                         desktopSize.width() / 2,
                         desktopSize.height() / 2)

        self.setWindowTitle(winTitle)

        self.radar = RadarWidget(self)
        self.radar.setGeometry(self.geometry().width() / 2, 10,
                               self.geometry().width() / 2 - 20,
                               self.geometry().width() / 2 - 20)

        self.createTable()

        self.btnExport = QPushButton("Export Table", self)
        self.btnExport.clicked[bool].connect(self.onExportClicked)
        self.btnExport.setStyleSheet("background-color: rgba(2,128,192,255);")

        self.btnPause = QPushButton("Pause Table", self)
        self.btnPause.setCheckable(True)
        self.btnPause.clicked[bool].connect(self.onPauseClicked)
        self.btnPause.setStyleSheet("background-color: rgba(2,128,192,255);")

        self.btnStream = QPushButton("Streaming Save", self)
        self.btnStream.setCheckable(True)
        self.btnStream.clicked[bool].connect(self.onStreamClicked)
        self.btnStream.setStyleSheet("background-color: rgba(2,128,192,255);")

        self.createChart()

        self.setBlackoutColors()

        self.setMinimumWidth(600)
        self.setMinimumHeight(600)

        self.center()

    def createTable(self):
        # Set up location table
        self.locationTable = QTableWidget(self)
        self.locationTable.setColumnCount(8)
        self.locationTable.setGeometry(10, 10,
                                       self.geometry().width() / 2 - 20,
                                       self.geometry().height() / 2)
        self.locationTable.setShowGrid(True)
        self.locationTable.setHorizontalHeaderLabels([
            'macAddr', 'SSID', 'Strength', 'Timestamp', 'GPS', 'Latitude',
            'Longitude', 'Altitude'
        ])
        self.locationTable.resizeColumnsToContents()
        self.locationTable.setRowCount(0)
        self.locationTable.horizontalHeader().setSectionResizeMode(
            1, QHeaderView.Stretch)

        self.ntRightClickMenu = QMenu(self)
        newAct = QAction('Copy', self)
        newAct.setStatusTip('Copy data to clipboard')
        newAct.triggered.connect(self.onCopy)
        self.ntRightClickMenu.addAction(newAct)

        self.locationTable.setContextMenuPolicy(Qt.CustomContextMenu)
        self.locationTable.customContextMenuRequested.connect(
            self.showNTContextMenu)

    def setBlackoutColors(self):
        self.locationTable.setStyleSheet(
            "QTableView {background-color: black;gridline-color: white;color: white} QTableCornerButton::section{background-color: white;}"
        )
        headerStyle = "QHeaderView::section{background-color: white;border: 1px solid black;color: black;} QHeaderView::down-arrow,QHeaderView::up-arrow {background: none;}"
        self.locationTable.horizontalHeader().setStyleSheet(headerStyle)
        self.locationTable.verticalHeader().setStyleSheet(headerStyle)

        mainTitleBrush = QBrush(Qt.red)
        self.timeChart.setTitleBrush(mainTitleBrush)

        self.timeChart.setBackgroundBrush(QBrush(Qt.black))
        self.timeChart.axisX().setLabelsColor(Qt.white)
        self.timeChart.axisY().setLabelsColor(Qt.white)
        titleBrush = QBrush(Qt.white)
        self.timeChart.axisX().setTitleBrush(titleBrush)
        self.timeChart.axisY().setTitleBrush(titleBrush)

    def resizeEvent(self, event):
        wDim = self.geometry().width() / 2 - 20
        hDim = self.geometry().height() / 2

        smallerDim = wDim
        if hDim < smallerDim:
            smallerDim = hDim

        # Radar
        self.radar.setGeometry(self.geometry().width() - smallerDim - 10, 10,
                               smallerDim, smallerDim)

        # chart
        self.timePlot.setGeometry(10, 10,
                                  self.geometry().width() - smallerDim - 30,
                                  smallerDim)

        # Buttons
        self.btnPause.setGeometry(10,
                                  self.geometry().height() / 2 + 18, 110, 25)
        self.btnExport.setGeometry(150,
                                   self.geometry().height() / 2 + 18, 110, 25)
        self.btnStream.setGeometry(290,
                                   self.geometry().height() / 2 + 18, 110, 25)

        # Table
        self.locationTable.setGeometry(10,
                                       self.geometry().height() / 2 + 50,
                                       self.geometry().width() - 20,
                                       self.geometry().height() / 2 - 60)

    def center(self):
        # Get our geometry
        qr = self.frameGeometry()
        # Find the desktop center point
        cp = QDesktopWidget().availableGeometry().center()
        # Move our center point to the desktop center point
        qr.moveCenter(cp)
        # Move the top-left point of the application window to the top-left point of the qr rectangle,
        # basically centering the window
        self.move(qr.topLeft())

    def showNTContextMenu(self, pos):
        curRow = self.locationTable.currentRow()

        if curRow == -1:
            return

        self.ntRightClickMenu.exec_(self.locationTable.mapToGlobal(pos))

    def onCopy(self):
        self.updateLock.acquire()

        curRow = self.locationTable.currentRow()
        curCol = self.locationTable.currentColumn()

        if curRow == -1 or curCol == -1:
            self.updateLock.release()
            return

        curText = self.locationTable.item(curRow, curCol).text()

        clipboard = QApplication.clipboard()
        clipboard.setText(curText)

        self.updateLock.release()

    def onVisibilityChanged(self, visible):
        if not visible:
            self.paused = True
            self.btnPause.setStyleSheet("background-color: rgba(255,0,0,255);")
            # We're coming out of streaming
            self.streamingSave = False
            self.btnStream.setStyleSheet(
                "background-color: rgba(2,128,192,255);")
            self.btnStream.setChecked(False)
            if (self.streamingFile):
                self.streamingFile.close()
                self.streamingFile = None
            return
        else:
            self.paused = False
            self.btnPause.setStyleSheet(
                "background-color: rgba(2,128,192,255);")
            if self.locationTable.rowCount() > 1:
                self.locationTable.scrollToItem(self.locationTable.item(0, 0))

    def hideEvent(self, event):
        self.visibility.emit(False)

    def showEvent(self, event):
        self.visibility.emit(True)

    def onPauseClicked(self, pressed):
        if self.btnPause.isChecked():
            self.paused = True
            self.btnPause.setStyleSheet("background-color: rgba(255,0,0,255);")
        else:
            self.paused = False
            self.btnPause.setStyleSheet(
                "background-color: rgba(2,128,192,255);")

    def onStreamClicked(self, pressed):
        if not self.btnStream.isChecked():
            # We're coming out of streaming
            self.streamingSave = False
            self.btnStream.setStyleSheet(
                "background-color: rgba(2,128,192,255);")
            if (self.streamingFile):
                self.streamingFile.close()
                self.streamingFile = None
            return

        self.btnStream.setStyleSheet("background-color: rgba(255,0,0,255);")
        self.streamingSave = True

        fileName = self.saveFileDialog()

        if not fileName:
            self.btnStream.setStyleSheet(
                "background-color: rgba(2,128,192,255);")
            self.btnStream.setChecked(False)
            return

        try:
            self.streamingFile = open(
                fileName, 'w', 1
            )  # 1 says use line buffering, otherwise it fully buffers and doesn't write
        except:
            QMessageBox.question(self, 'Error',
                                 "Unable to write to " + fileName,
                                 QMessageBox.Ok)
            self.streamingFile = None
            self.streamingSave = False
            self.btnStream.setStyleSheet(
                "background-color: rgba(2,128,192,255);")
            self.btnStream.setChecked(False)
            return

        self.streamingFile.write(
            'MAC Address,SSID,Strength,Timestamp,GPS,Latitude,Longitude,Altitude\n'
        )

    def onExportClicked(self):
        fileName = self.saveFileDialog()

        if not fileName:
            return

        try:
            outputFile = open(fileName, 'w')
        except:
            QMessageBox.question(self, 'Error',
                                 "Unable to write to " + fileName,
                                 QMessageBox.Ok)
            return

        outputFile.write(
            'MAC Address,SSID,Strength,Timestamp,GPS,Latitude,Longitude,Altitude\n'
        )

        numItems = self.locationTable.rowCount()

        if numItems == 0:
            outputFile.close()
            return

        self.updateLock.acquire()

        for i in range(0, numItems):
            outputFile.write(
                self.locationTable.item(i, 0).text() + ',"' +
                self.locationTable.item(i, 1).text() + '",' +
                self.locationTable.item(i, 2).text() + ',' +
                self.locationTable.item(i, 3).text())
            outputFile.write(',' + self.locationTable.item(i, 4).text() + ',' +
                             self.locationTable.item(i, 5).text() + ',' +
                             self.locationTable.item(i, 6).text() + ',' +
                             self.locationTable.item(i, 7).text() + '\n')

        self.updateLock.release()
        outputFile.close()

    def saveFileDialog(self):
        options = QFileDialog.Options()
        options |= QFileDialog.DontUseNativeDialog
        fileName, _ = QFileDialog.getSaveFileName(
            self,
            "QFileDialog.getSaveFileName()",
            "",
            "CSV Files (*.csv);;All Files (*)",
            options=options)
        if fileName:
            return fileName
        else:
            return None

    def createChart(self):
        self.timeChart = QChart()
        titleFont = QFont()
        titleFont.setPixelSize(18)
        titleBrush = QBrush(QColor(0, 0, 255))
        self.timeChart.setTitleFont(titleFont)
        self.timeChart.setTitleBrush(titleBrush)
        self.timeChart.setTitle('Signal (Past ' + str(self.maxPoints) +
                                ' Samples)')
        # self.timeChart.addSeries(testseries)
        # self.timeChart.createDefaultAxes()
        self.timeChart.legend().hide()

        # Axis examples: https://doc.qt.io/qt-5/qtcharts-multiaxis-example.html
        newAxis = QValueAxis()
        newAxis.setMin(0)
        newAxis.setMax(self.maxPoints)
        newAxis.setTickCount(11)
        newAxis.setLabelFormat("%d")
        newAxis.setTitleText("Sample")
        self.timeChart.addAxis(newAxis, Qt.AlignBottom)

        newAxis = QValueAxis()
        newAxis.setMin(-100)
        newAxis.setMax(-10)
        newAxis.setTickCount(9)
        newAxis.setLabelFormat("%d")
        newAxis.setTitleText("dBm")
        self.timeChart.addAxis(newAxis, Qt.AlignLeft)

        chartBorder = Qt.darkGray
        self.timePlot = QChartView(self.timeChart, self)
        self.timePlot.setBackgroundBrush(chartBorder)
        self.timePlot.setRenderHint(QPainter.Antialiasing)

        self.timeSeries = QLineSeries()
        pen = QPen(Qt.yellow)

        pen.setWidth(2)
        self.timeSeries.setPen(pen)
        self.timeChart.addSeries(self.timeSeries)
        self.timeSeries.attachAxis(self.timeChart.axisX())
        self.timeSeries.attachAxis(self.timeChart.axisY())

    def updateNetworkData(self, curNet):
        if not self.isVisible():
            return

        # Signal is -NN dBm.  Need to make it positive for the plot
        self.radar.updateData(curNet.signal * -1)

        if self.winTitle == "Client Telemetry":
            self.setWindowTitle(self.winTitle + " - [" + curNet.macAddr +
                                "] " + curNet.ssid)
        else:
            self.setWindowTitle(self.winTitle + " - " + curNet.ssid)

        self.radar.draw()

        #  Network changed.  Clear our table and time data
        updateChartAndTable = False

        self.updateLock.acquire()

        if (curNet.getKey() != self.lastNetKey):
            self.lastNetKey = curNet.getKey()
            self.locationTable.setRowCount(0)
            self.timeSeries.clear()
            updateChartAndTable = True

            ssidTitle = curNet.ssid
            if len(ssidTitle) > 28:
                ssidTitle = ssidTitle[:28]
                ssidTitle = ssidTitle + '...'

            self.timeChart.setTitle(ssidTitle + ' Signal (Past ' +
                                    str(self.maxPoints) + ' Samples)')
        else:
            if self.lastSeen != curNet.lastSeen:
                updateChartAndTable = True

        if updateChartAndTable:
            # Update chart
            numPoints = len(self.timeSeries.pointsVector())

            if numPoints >= self.maxPoints:
                self.timeSeries.remove(0)
                # Now we need to reset the x data to pull the series back
                counter = 0
                for curPoint in self.timeSeries.pointsVector():
                    self.timeSeries.replace(counter, counter, curPoint.y())
                    counter += 1

            if curNet.signal >= -100:
                self.timeSeries.append(numPoints, curNet.signal)
            else:
                self.timeSeries.append(numPoints, -100)

            # Update Table
            self.addTableData(curNet)

            # Limit points in each
            if self.locationTable.rowCount() > self.maxRowPoints:
                self.locationTable.setRowCount(self.maxRowPoints)

        self.updateLock.release()

    def addTableData(self, curNet):
        if self.paused:
            return

        # rowPosition = self.locationTable.rowCount()
        # Always insert at row(0)
        rowPosition = 0

        self.locationTable.insertRow(rowPosition)

        #if (addedFirstRow):
        #    self.locationTable.setRowCount(1)

        # ['macAddr','SSID', 'Strength', 'Timestamp','GPS', 'Latitude', 'Longitude', 'Altitude']
        self.locationTable.setItem(rowPosition, 0,
                                   QTableWidgetItem(curNet.macAddr))
        tmpssid = curNet.ssid
        if (len(tmpssid) == 0):
            tmpssid = '<Unknown>'
        newSSID = QTableWidgetItem(tmpssid)

        self.locationTable.setItem(rowPosition, 1, newSSID)
        self.locationTable.setItem(rowPosition, 2,
                                   IntTableWidgetItem(str(curNet.signal)))
        self.locationTable.setItem(
            rowPosition, 3,
            DateTableWidgetItem(curNet.lastSeen.strftime("%m/%d/%Y %H:%M:%S")))
        if curNet.gps.isValid:
            self.locationTable.setItem(rowPosition, 4, QTableWidgetItem('Yes'))
        else:
            self.locationTable.setItem(rowPosition, 4, QTableWidgetItem('No'))

        self.locationTable.setItem(
            rowPosition, 5, FloatTableWidgetItem(str(curNet.gps.latitude)))
        self.locationTable.setItem(
            rowPosition, 6, FloatTableWidgetItem(str(curNet.gps.longitude)))
        self.locationTable.setItem(
            rowPosition, 7, FloatTableWidgetItem(str(curNet.gps.altitude)))
        #order = Qt.DescendingOrder
        #self.locationTable.sortItems(3, order )

        # If we're in streaming mode, write the data out to disk as well
        if self.streamingFile:
            self.streamingFile.write(
                self.locationTable.item(rowPosition, 0).text() + ',"' +
                self.locationTable.item(rowPosition, 1).text() + '",' +
                self.locationTable.item(rowPosition, 2).text() + ',' +
                self.locationTable.item(rowPosition, 3).text() + ',' +
                self.locationTable.item(rowPosition, 4).text() + ',' +
                self.locationTable.item(rowPosition, 5).text() + ',' +
                self.locationTable.item(rowPosition, 6).text() + ',' +
                self.locationTable.item(rowPosition, 7).text() + '\n')

            if (self.currentLine > self.linesBeforeFlush):
                self.streamingFile.flush()
                self.currentLine += 1

        numRows = self.locationTable.rowCount()

        if numRows > 1:
            self.locationTable.scrollToItem(self.locationTable.item(0, 0))

    def onTableHeadingClicked(self, logical_index):
        header = self.locationTable.horizontalHeader()
        order = Qt.DescendingOrder
        # order = Qt.DescendingOrder
        if not header.isSortIndicatorShown():
            header.setSortIndicatorShown(True)
        elif header.sortIndicatorSection() == logical_index:
            # apparently, the sort order on the header is already switched
            # when the section was clicked, so there is no need to reverse it
            order = header.sortIndicatorOrder()
        header.setSortIndicator(logical_index, order)
        self.locationTable.sortItems(logical_index, order)

    def updateData(self, newRadius):
        self.radar.updateData(newRadius)

    def showTelemetry(parent=None):
        dialog = TelemetryDialog(parent)
        result = dialog.exec_()
        return (result == QDialog.Accepted)
class ContentView(QWidget):
    def __init__(self):
        super().__init__()

        self.m_chart_1 = QChart()
        self.m_chart_2 = QChart()
        self.m_chart_3 = QChart()
        self.m_chart_4 = QChart()
        self.m_series_1 = QLineSeries()
        self.m_series_2 = QLineSeries()
        self.m_series_3 = QLineSeries()
        self.m_series_4 = QLineSeries()

        self.y_original = []
        self.x_data = []
        self.y_processed = []
        self.sampling_rate = 0

        self.pathForVocalMute = ""

        self.select_action_drop = QComboBox()

        self.echo_shift = 0.4
        self.echo_alpha = 0.5

        self.init_ui()

    def init_ui(self):
        main_layout = QVBoxLayout()

        # Drag&Drop area
        drag_drop = DragDropArea(parent=self)
        main_layout.addWidget(drag_drop)

        # Chart layout
        chart_layout_1 = QHBoxLayout()
        chart_layout_2 = QHBoxLayout()

        # Chart 1
        chart_view_1 = QChartView(self.m_chart_1)
        chart_view_1.setMinimumSize(400, 300)

        self.m_chart_1.addSeries(self.m_series_1)

        pen = self.m_series_1.pen()
        pen.setColor(Qt.red)
        pen.setWidthF(.1)
        self.m_series_1.setPen(pen)
        self.m_series_1.setUseOpenGL(True)

        axis_x = QValueAxis()
        axis_x.setRange(0, 100)
        axis_x.setLabelFormat("%g")
        axis_x.setTitleText("Samples")

        axis_y = QValueAxis()
        axis_y.setRange(-10, 10)
        axis_y.setTitleText("Audio level")

        self.m_chart_1.setAxisX(axis_x, self.m_series_1)
        self.m_chart_1.setAxisY(axis_y, self.m_series_1)
        self.m_chart_1.setTitle("Original signal time domain")

        chart_layout_1.addWidget(chart_view_1)

        # Chart 2
        chart_view_2 = QChartView(self.m_chart_2)
        chart_view_2.setMinimumSize(400, 300)

        self.m_chart_2.setTitle("Original signal frequency domain")

        pen = self.m_series_2.pen()
        pen.setColor(Qt.blue)
        pen.setWidthF(.1)
        self.m_series_2.setPen(pen)
        self.m_series_2.setUseOpenGL(True)

        self.m_chart_2.addSeries(self.m_series_2)

        chart_layout_1.addWidget(chart_view_2)

        # Chart 3
        chart_view_3 = QChartView(self.m_chart_3)
        chart_view_3.setMinimumSize(400, 300)

        self.m_chart_3.addSeries(self.m_series_3)

        pen = self.m_series_3.pen()
        pen.setColor(Qt.green)
        pen.setWidthF(.1)
        self.m_series_3.setPen(pen)
        self.m_series_3.setUseOpenGL(True)

        axis_x = QValueAxis()
        axis_x.setRange(0, 100)
        axis_x.setLabelFormat("%g")
        axis_x.setTitleText("Samples")

        axis_y = QValueAxis()
        axis_y.setRange(-10, 10)
        axis_y.setTitleText("Audio level")

        self.m_chart_3.setAxisX(axis_x, self.m_series_3)
        self.m_chart_3.setAxisY(axis_y, self.m_series_3)
        self.m_chart_3.setTitle("Processed signal time domain")

        chart_layout_2.addWidget(chart_view_3)

        # Chart 4
        chart_view_4 = QChartView(self.m_chart_4)
        chart_view_4.setMinimumSize(400, 300)

        self.m_chart_4.setTitle("Processed signal frequency domain")

        pen = self.m_series_4.pen()
        pen.setColor(Qt.magenta)
        pen.setWidthF(.1)
        self.m_series_4.setPen(pen)
        self.m_series_4.setUseOpenGL(True)

        self.m_chart_4.addSeries(self.m_series_4)

        chart_layout_2.addWidget(chart_view_4)

        main_layout.addLayout(chart_layout_1)
        main_layout.addLayout(chart_layout_2)

        # Action buttons
        player_layout = QHBoxLayout()

        self.select_action_drop.addItems([
            "Add noise", "Filter", "Mute equipment", "Mute vocal", "Add echo",
            "Filter echo"
        ])

        player_layout.addWidget(self.select_action_drop)

        noise_jc = QIcon('rate_ic.png')
        noise_btn = QPushButton('Process')
        noise_btn.setIcon(noise_jc)
        noise_btn.clicked.connect(self.on_action)

        player_layout.addWidget(noise_btn)

        play_jc = QIcon('play_ic.png')
        play_orig_btn = QPushButton('Play Original')
        play_orig_btn.setIcon(play_jc)
        play_orig_btn.clicked.connect(self.on_play_orig)

        player_layout.addWidget(play_orig_btn)

        play_jc = QIcon('play_ic.png')
        play_btn = QPushButton('Play Processed')
        play_btn.setIcon(play_jc)
        play_btn.clicked.connect(self.on_play)

        player_layout.addWidget(play_btn)

        stop_jc = QIcon('stop_ic.png')
        stop_btn = QPushButton('Stop')
        stop_btn.setIcon(stop_jc)
        stop_btn.clicked.connect(self.on_stop)

        player_layout.addWidget(stop_btn)

        main_layout.addLayout(player_layout)

        self.setLayout(main_layout)

    ''''
        Toolbar actions
    '''

    def browse_file(self):
        path1 = QFileDialog.getOpenFileName(self, 'Open File',
                                            os.getenv('HOME'), '*.wav')
        print(path1[0])

        rate, data = wavfile.read(path1[0])

        self.sampling_rate = rate
        self.y_original = data[:, 0]

        self.show_original_data()

    def on_file_upload(self, file_url):
        print(file_url[7:])

        self.pathForVocalMute = file_url[7:]

        rate, data = wavfile.read(file_url[7:])

        self.sampling_rate = rate
        self.y_original = data[:, 0]

        self.show_original_data()

    def on_save(self):
        print("on_save")
        if len(self.y_processed) > 0:
            path = QFileDialog.getSaveFileName(self, 'Save File',
                                               os.getenv('HOME'), 'audio/wav')
            if path[0] != '':
                data2 = np.asarray([self.y_processed,
                                    self.y_processed]).transpose()
                wavfile.write(path[0], self.sampling_rate, data2)
            else:
                msg = QMessageBox()
                msg.setIcon(QMessageBox.Critical)
                msg.setText("No path")
                msg.setInformativeText("You should define path to save file")
                msg.setWindowTitle("Error")
                msg.exec_()
        else:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Critical)
            msg.setText("No data")
            msg.setInformativeText(
                "No data to save, you should upload and process sound file")
            msg.setWindowTitle("Error")
            msg.exec_()

    ''''
        Action selection
    '''

    def on_action(self):
        if self.select_action_drop.currentText() == "Add noise":
            self.on_add_noise()
        elif self.select_action_drop.currentText() == "Filter":
            self.on_filter()
        elif self.select_action_drop.currentText() == "Mute equipment":
            self.on_mute_equipment()
        elif self.select_action_drop.currentText() == "Mute vocal":
            self.on_mute_voice()
        elif self.select_action_drop.currentText() == "Add echo":
            self.on_add_echo()
        elif self.select_action_drop.currentText() == "Filter echo":
            self.on_filter_echo()

    '''
        Noise addition
    '''

    def on_add_noise(self):
        if len(self.y_original) == 0:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Critical)
            msg.setText("Upload sound file")
            msg.setInformativeText(
                "First you should add sound file to process")
            msg.setWindowTitle("Error")
            msg.exec_()
            return

        noise = np.random.normal(0,
                                 self.y_original.max() / 30,
                                 len(self.y_original))
        arr1 = np.array(self.y_original)
        self.y_processed = arr1 + noise
        self.show_processed_data()

    def on_filter(self):
        print("on_filter")

        if len(self.y_original) == 0:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Critical)
            msg.setText("Upload sound file")
            msg.setInformativeText(
                "First you should add sound file to process")
            msg.setWindowTitle("Error")
            msg.exec_()
            return

        filter1, filter2, limit1, limit2, extra, max_ripple, min_attenuation, ok = FilterSelectionDialog.show_dialog(
            parent=self)
        print(filter1, filter2, limit1, limit2, extra, max_ripple,
              min_attenuation, ok)

        if ok:
            if filter1 == "FIR filter":
                self.on_fir_filter(filter2, limit1, limit2, extra)
            elif filter1 == "IIR filter":
                self.on_iir_filter(filter2, limit1, limit2, extra, max_ripple,
                                   min_attenuation)

    def on_mute_equipment(self):
        print("on_mute_equipment")

        check_piano, check_organ, check_flute, check_french_horn, check_trumpet, check_violin, \
        check_guitar_acoustic, check_guitar_bass, check_clarinet, \
        check_saxophone, ok = MuteInstrumentsDialog.show_dialog(parent=self)

        print(check_piano, check_organ, check_flute, check_french_horn,
              check_trumpet, check_violin, check_guitar_acoustic,
              check_guitar_bass, check_clarinet, check_saxophone, ok)
        '''
        Piano	A0 (28 Hz) to C8 (4,186 Hz or 4.1 KHz)
        Organ	C0 (16 Hz) to A9 (7,040 KHz)	
        Concert Flute	C4 (262 Hz) to B6 (1,976 Hz)	
        French Horn	A2 (110 Hz) to A5 (880 Hz)
        Trumpet	E3 (165 Hz) to B5 (988 Hz)
        Violin	G3 (196 Hz) - G7 (3,136 Hz) (G-D-E-A) (or C8 (4,186 Hz?)
        Guitar (Acoustic)	E2 (82 Hz) to F6 (1,397 Hz)
        Guitar (Bass)	4 string E1 (41 Hz) to C4 (262 Hz)
        Clarinet	E3 (165 Hz) to G6 (1,568 Hz)	
        Saxaphone Eb 138-830 (880)
        '''
        if ok:
            print(check_piano)

        limit1 = 0.1
        limit2 = 0.2
        if check_piano:
            pass
        elif check_organ:
            pass
        elif check_flute:
            limit1 = 262 / self.sampling_rate
            limit2 = 1976 / self.sampling_rate
            pass
        elif check_french_horn:
            limit1 = 110 / self.sampling_rate
            limit2 = 880 / self.sampling_rate
            pass
        elif check_trumpet:
            limit1 = 165 / self.sampling_rate
            limit2 = 988 / self.sampling_rate
            pass
        elif check_violin:
            limit1 = 196 / self.sampling_rate
            limit2 = 3136 / self.sampling_rate
            pass
        elif check_guitar_acoustic:
            limit1 = 82 / self.sampling_rate
            limit2 = 1397 / self.sampling_rate
            pass
        elif check_guitar_bass:
            limit1 = 41 / self.sampling_rate
            limit2 = 262 / self.sampling_rate
            pass
        elif check_clarinet:
            limit1 = 165 / self.sampling_rate
            limit2 = 1568 / self.sampling_rate
            pass
        elif check_saxophone:
            limit1 = 138 / self.sampling_rate
            limit2 = 880 / self.sampling_rate
            pass

        print(limit1, limit2)

        print([
            0.0, 0.0001, limit1 - 0.0001, limit1, limit2, limit2 + 0.0001,
            0.9991, 1.0
        ], [0, 1, 1, 0, 0, 1, 1, 0])
        design_filter = signal.firwin2(1000000, [
            0.0, 0.0001, limit1 - 0.0001, limit1, limit2, limit2 + 0.0001,
            0.9991, 1.0
        ], [0, 1, 1, 0, 0, 1, 1, 0])

        self.y_processed = signal.convolve(self.y_original,
                                           design_filter,
                                           mode='same')

        w1, h1 = signal.freqz(design_filter)

        result = FilterResponseDialog.show_dialog(parent=self, w1=w1, h1=h1)

        if result:
            self.show_processed_data()

    def on_mute_voice(self):
        y, sr = librosa.load(self.pathForVocalMute, sr=self.sampling_rate)

        S_full, phase = librosa.magphase(librosa.stft(y))

        S_filter = librosa.decompose.nn_filter(
            S_full,
            aggregate=np.median,
            metric='cosine',
            width=int(librosa.time_to_frames(2, sr=sr)))

        S_filter = np.minimum(S_full, S_filter)

        margin_i, margin_v = 2, 10
        power = 2

        mask_i = librosa.util.softmask(S_filter,
                                       margin_i * (S_full - S_filter),
                                       power=power)

        mask_v = librosa.util.softmask(S_full - S_filter,
                                       margin_v * S_filter,
                                       power=power)

        S_foreground = mask_v * S_full
        S_background = mask_i * S_full

        self.y_processed = librosa.istft(S_background)

        self.show_processed_data()

    def on_add_echo(self):
        if len(self.y_original) == 0:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Critical)
            msg.setText("Upload sound file")
            msg.setInformativeText(
                "First you should add sound file to process")
            msg.setWindowTitle("Error")
            msg.exec_()
            return

        num_shift = int(self.sampling_rate * self.echo_shift)
        zeros = np.zeros(num_shift)

        original = np.append(self.y_original, zeros)
        echo = np.append(zeros, self.y_original) * self.echo_alpha

        self.y_processed = original + echo

        np.delete(
            self.y_processed,
            np.arange(
                len(self.y_processed) - len(zeros), len(self.y_processed)))

        self.show_processed_data()

    def on_filter_echo(self):
        ceps = cepstrum.real_cepstrum(np.array(self.y_original))

        index, result = CepstrumDialog.show_dialog(self, ceps)

        if result:
            print(index)

            b = np.array([1])

            a = np.zeros(index + 1)
            a[0] = 1
            a[len(a) - 1] = self.echo_alpha

            zi = signal.lfilter_zi(b, a)

            self.y_processed, _ = signal.lfilter(b,
                                                 a,
                                                 self.y_original,
                                                 axis=0,
                                                 zi=zi * self.y_original[0])

            w1, h1 = signal.freqz(b, a)

            result = FilterResponseDialog.show_dialog(parent=self,
                                                      w1=w1,
                                                      h1=h1)

            if result:
                self.show_processed_data()

    '''
        Filters
    '''

    def on_fir_filter(self, filter_type, limit1, limit2, extra):
        if filter_type == "Low-pass":
            design_filter = signal.firwin(41, limit1, window=extra)
        elif filter_type == "High-pass":
            temp = np.zeros(41)
            temp[20] = 1
            design_filter = temp - np.array(
                signal.firwin(41, limit1, window=extra))
        elif filter_type == "Band-pass":
            temp = np.zeros(41)
            temp[20] = 1
            design_filter = temp - np.array(
                signal.firwin(41, [limit1, limit2], window=extra))
        elif filter_type == "Band-reject":
            design_filter = signal.firwin(41, [limit1, limit2], window=extra)

        self.y_processed = signal.convolve(self.y_original,
                                           design_filter,
                                           mode='same')

        w1, h1 = signal.freqz(design_filter)

        result = FilterResponseDialog.show_dialog(parent=self, w1=w1, h1=h1)

        if result:
            self.show_processed_data()

    def on_iir_filter(self, filter_type, limit1, limit2, extra, max_ripple,
                      min_attenuation):
        if filter_type == "Low-pass":
            b, a = signal.iirfilter(4,
                                    limit1,
                                    rp=int(max_ripple),
                                    rs=int(min_attenuation),
                                    btype='lowpass',
                                    ftype=extra)
        elif filter_type == "High-pass":
            b, a = signal.iirfilter(4,
                                    limit1,
                                    rp=int(max_ripple),
                                    rs=int(min_attenuation),
                                    btype='highpass',
                                    ftype=extra)
        elif filter_type == "Band-pass":
            b, a = signal.iirfilter(4, [limit1, limit2],
                                    rp=int(max_ripple),
                                    rs=int(min_attenuation),
                                    btype='bandpass',
                                    ftype=extra)
        elif filter_type == "Band-reject":
            b, a = signal.iirfilter(4, [limit1, limit2],
                                    rp=int(max_ripple),
                                    rs=int(min_attenuation),
                                    btype='bandstop',
                                    ftype=extra)

        self.y_processed = signal.lfilter(b, a, self.y_original)

        w1, h1 = signal.freqz(b, a)

        result = FilterResponseDialog.show_dialog(parent=self, w1=w1, h1=h1)

        if result:
            self.show_processed_data()

    '''
        Audio controls
    '''

    def on_play(self):
        print("on_play")

        if len(self.y_processed) > 0:
            data2 = np.asarray(self.y_processed)
            sd.play(data2, self.sampling_rate)
        else:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Critical)
            msg.setText("Upload sound file")
            msg.setInformativeText(
                "First you should upload and process sound file to play")
            msg.setWindowTitle("Error")
            msg.exec_()

    def on_stop(self):
        sd.stop()

    def on_play_orig(self):
        print("on_play_orig")

        if len(self.y_original) > 0:
            data = np.asarray(self.y_original)
            sd.play(data, self.sampling_rate)
        else:
            msg = QMessageBox()
            msg.setIcon(QMessageBox.Critical)
            msg.setText("Upload sound file")
            msg.setInformativeText("First you should add sound file to play")
            msg.setWindowTitle("Error")
            msg.exec_()

    '''
        Signal plots
    '''

    def show_original_data(self):
        # Time domain
        y_data_scaled = np.interp(
            self.y_original, (self.y_original.min(), self.y_original.max()),
            (-10, +10))

        sample_size = len(self.y_original)
        self.x_data = np.linspace(0., 100., sample_size)

        points_1 = []

        for k in range(len(y_data_scaled)):
            points_1.append(QPointF(self.x_data[k], y_data_scaled[k]))

        self.m_series_1.replace(points_1)

        # Frequency domain
        y_freq_data = np.abs(fftpack.fft(self.y_original))
        y_freq_data = np.interp(y_freq_data,
                                (y_freq_data.min(), y_freq_data.max()),
                                (0, +10))
        x_freq_data = fftpack.fftfreq(len(
            self.y_original)) * self.sampling_rate

        axis_x = QValueAxis()
        axis_x.setRange(0, self.sampling_rate / 2)
        axis_x.setLabelFormat("%g")
        axis_x.setTitleText("Frequency [Hz]")

        axis_y = QValueAxis()
        axis_y.setRange(np.min(y_freq_data), np.max(y_freq_data))
        axis_y.setTitleText("Magnitude")

        self.m_chart_2.setAxisX(axis_x, self.m_series_2)
        self.m_chart_2.setAxisY(axis_y, self.m_series_2)

        points_2 = []

        for k in range(len(y_freq_data)):
            points_2.append(QPointF(x_freq_data[k], y_freq_data[k]))

        self.m_series_2.replace(points_2)

        self.m_series_3.clear()
        self.m_series_4.clear()

    def show_processed_data(self):
        # Time domain
        y_data_scaled = np.interp(
            self.y_processed, (self.y_processed.min(), self.y_processed.max()),
            (-10, +10))

        points_3 = []

        sample_size = len(self.y_processed)
        x_data = np.linspace(0., 100., sample_size)

        for k in range(len(y_data_scaled)):
            points_3.append(QPointF(x_data[k], y_data_scaled[k]))

        self.m_series_3.replace(points_3)

        # Frequency domain
        y_freq_data = np.abs(fftpack.fft(self.y_processed))
        y_freq_data = np.interp(y_freq_data,
                                (y_freq_data.min(), y_freq_data.max()),
                                (0, +10))
        x_freq_data = fftpack.fftfreq(len(
            self.y_processed)) * self.sampling_rate

        axis_x = QValueAxis()
        axis_x.setRange(0, self.sampling_rate / 2)
        axis_x.setLabelFormat("%g")
        axis_x.setTitleText("Frequency [Hz]")

        axis_y = QValueAxis()
        axis_y.setRange(np.min(y_freq_data), np.max(y_freq_data))
        axis_y.setTitleText("Magnitude")

        self.m_chart_4.setAxisX(axis_x, self.m_series_4)
        self.m_chart_4.setAxisY(axis_y, self.m_series_4)

        points_4 = []

        for k in range(len(y_freq_data)):
            points_4.append(QPointF(x_freq_data[k], y_freq_data[k]))

        self.m_series_4.replace(points_4)
예제 #8
0
class Chart(QChart):
    MIN_X = 0
    MAX_X = 750
    MIN_Y = -1
    MAX_Y = 1
    TICKS = 5
    PENCOLOR = Qt.red
    PENWIDTH = 1

    def __init__(self, parent=None):
        super(Chart, self).__init__(parent)
        self.parent = parent
        # we will draw lines
        self.series = QLineSeries(parent)
        # color and pen-width
        self.series.setPen(QPen(self.PENCOLOR, self.PENWIDTH))

        self.addSeries(self.series)

        self.legend().hide()
        self.__construct_axises()

    def setRange_X_axis(self, min_X, max_X):
        self.MIN_X = min_X
        self.MAX_X = max_X
        self.axisX().setRange(self.MIN_X, self.MAX_X)

    def setRange_Y_axis(self, min_Y, max_Y):
        self.MIN_Y = min_Y
        self.MAX_Y = max_Y
        self.axisY().setRange(self.MIN_Y, self.MAX_Y)

    def add_point(self, x, y):
        self.series.append(x, y)

    def get_series(self) -> list:
        return self.series.pointsVector()

    def remove_point(self, index):
        self.series.remove(index)

    def remove_points(self, index, count):
        self.series.removePoints(index, count)

    def replace_point(self, index, x, y):
        self.series.replace(index, x, y)

    def replace_series(self, lst):
        self.series.replace(lst)

    def get_series_count(self):
        return self.series.count()

    def __construct_axises(self):
        self.createDefaultAxes()

        # X-Axis
        x_axis = self.axisX()
        x_axis.hide()
        x_axis.setRange(self.MIN_X, self.MAX_X)

        # Y-axis
        y_axis = self.axisY()
        y_axis.setRange(self.MIN_Y, self.MAX_Y)
        y_axis.setTickCount(self.TICKS)