我正在尝试使用 Vispy 实时获取和显示信号。我通过 pyserial 通过串行端口获取信号。
我已经修改了 realtime_signals 示例(https://github.com/vispy/vispy/blob/master/examples/demo/gloo/realtime_signals.py)并且能够单独显示每个信号。我还可以显示相同信号的 3 或 5 个图。但我无法在同一画布或插入 PyQt5 应用程序的两个不同画布中显示两个信号(每个来自不同的串行端口)。我对 OpenGL 和着色器没有经验。
串口代码和修改后的场景定时器代码如下。
#import multiprocessing
from PyQt5.QtWidgets import *
import vispy.app
import sys
from vispy import gloo
from vispy import app
import numpy as np
import math
import serial
datam=0.0
seri=serial.Serial("/dev/ttyACM0", baudrate=115200, timeout=1)
class Seriport(serial.Serial):
def oku():
global datam
while seri.isOpen:
dataGet=''
serialData = seri.read().decode('ascii')
if serialData == '$':
while not serialData == ';':
serialData = seri.read().decode('ascii')
if not serialData == ';':
dataGet += serialData
if not '$' in dataGet:
dataList = dataGet.split(',')
if len(dataList) == 3:
datam=float(dataList[0])-125000
print(datam)
return datam
# Number of cols and rows in the table.
nrows = 3
ncols = 1
# Number of signals.x = np.arange(sample)
m = nrows*ncols
# Number of samples per signal.
n = 1000
# Various signal amplitudes.
amplitudes = .1 + .2 * np.random.rand(m, 1).astype(np.float32)
# Generate the signals as a (m, n) array.
# y = amplitudes * np.random.randn(m, n).astype(np.float32)
y = np.zeros([m, n], dtype = np.float32)
# Color of each vertex (TODO: make it more efficient by using a GLSL-based
# color map and the index).
color = np.repeat(np.random.uniform(size=(m, 3), low=.5, high=.9),
n, axis=0).astype(np.float32)
# Signal 2D index of each vertex (row and col) and x-index (sample index
# within each signal).
index = np.c_[np.repeat(np.repeat(np.arange(ncols), nrows), n),
np.repeat(np.tile(np.arange(nrows), ncols), n),
np.tile(np.arange(n), m)].astype(np.float32)
VERT_SHADER = """
#version 120
// y coordinate of the position.
attribute float a_position;
// row, col, and time index.
attribute vec3 a_index;
varying vec3 v_index;
// 2D scaling factor (zooming).
uniform vec2 u_scale;
// Size of the table.
uniform vec2 u_size;
// Number of samples per signal.
uniform float u_n;
// Color.
attribute vec3 a_color;
varying vec4 v_color;
// Varying variables used for clipping in the fragment shader.
varying vec2 v_position;
varying vec4 v_ab;
void main() {
float nrows = u_size.x;
float ncols = u_size.y;
// Compute the x coordinate from the time index.
float x = -1 + 2*a_index.z / (u_n-1);
vec2 position = vec2(x - (1 - 1 / u_scale.x), a_position);
// Find the affine transformation for the subplots.
vec2 a = vec2(1./ncols, 1./nrows)*.9;
vec2 b = vec2(-1 + 2*(a_index.x+.5) / ncols,
-1 + 2*(a_index.y+.5) / nrows);
// Apply the static subplot transformation + scaling.
gl_Position = vec4(a*u_scale*position+b, 0.0, 1.0);
v_color = vec4(a_color, 1.);
v_index = a_index;
// For clipping test in the fragment shader.
v_position = gl_Position.xy;
v_ab = vec4(a, b);
}
"""
FRAG_SHADER = """
#version 120
varying vec4 v_color;
varying vec3 v_index;
varying vec2 v_position;
varying vec4 v_ab;
void main() {
gl_FragColor = v_color;
// Discard the fragments between the signals (emulate glMultiDrawArrays).
if ((fract(v_index.x) > 0.) || (fract(v_index.y) > 0.))
discard;
// Clipping test.
vec2 test = abs((v_position.xy-v_ab.zw)/v_ab.xy);
if ((test.x > 1) || (test.y > 1))
discard;
}
"""
class Canvas(app.Canvas):
def __init__(self):
app.Canvas.__init__(self, title='Use your wheel to zoom!',
keys='interactive')
self.program = gloo.Program(VERT_SHADER, FRAG_SHADER)
self.program['a_position'] = y.reshape(-1, 1)
self.program['a_color'] = color
self.program['a_index'] = index
self.program['u_scale'] = (1., 1.)
self.program['u_size'] = (nrows, ncols)
self.program['u_n'] = n
gloo.set_viewport(0, 0, *self.physical_size)
self._timer = app.Timer(0.001, connect=self.on_timer, start=True)
gloo.set_state(clear_color='black', blend=True,
blend_func=('src_alpha', 'one_minus_src_alpha'))
self.show()
def on_resize(self, event):
gloo.set_viewport(0, 0, *event.physical_size)
def on_mouse_wheel(self, event):
dx = np.sign(event.delta[1]) * .05
scale_x, scale_y = self.program['u_scale']
scale_x_new, scale_y_new = (scale_x * math.exp(2.5*dx),
scale_y * math.exp(0.0*dx))
self.program['u_scale'] = (max(1, scale_x_new), max(1, scale_y_new))
self.update()
def on_timer(self, event):
"""Add some data at the end of each signal (real-time signals)."""
global datam
k = 1
y[:, :-k] = y[:, k:]
# y[:, -k:] = datam/50000
y[:, -k:] = (Seriport.oku()/5000)
# y[:, -k:] = amplitudes * np.random.randn(m, k)
self.program['a_position'].set_data(y.ravel().astype(np.float32))
self.update()
def on_draw(self, event):
gloo.clear()
self.program.draw('line_strip')
canvas = Canvas()
w = QMainWindow()
widget = QWidget()
frame = QFrame()
w.setCentralWidget(widget)
widget.setLayout(QHBoxLayout())
frame.setLayout(QVBoxLayout())
widget.layout().addWidget(canvas.native)
#widget.layout().addWidget(canvas2.native)
widget.layout().addWidget(frame)
frame.layout().addWidget(QPushButton())
frame.layout().addWidget(QPushButton())
frame.layout().addWidget(QPushButton())
frame.layout().addWidget(QPushButton())
frame.layout().addWidget(QPushButton())
w.show()
vispy.app.run()
def on_timer(self, event):
"""Add some data at the end of each signal (real-time signals)."""
global datam
k = 1
y[:, :-k] = y[:, k:]
# y[:, -k:] = datam/50000
y[:, -k:] = (Seriport.oku()/5000)
# y[:, -k:] = amplitudes * np.random.randn(m, k)
self.program['a_position'].set_data(y.ravel().astype(np.float32))
self.update()
任何帮助,将不胜感激。