我想绘制从TCP服务器获得的所有数据点。但我想不出一种方法来绘制所有的数据点。目前,我将字符串打印到文本框中。从文本框中只打印第一行。这是一个用于示波器GUI的实时数据绘图。如何绘制所有的值
我用I2S麦克风测试了一个正弦波,当用下面的代码绘制时,它给出了一个扭曲的信号。
int t;
private void Timer1_Tick(object sender, EventArgs e)
{
one = new Thread(test);
one.Start();
t++;
}
public void test()
{
byte[] bytes = new byte[client.ReceiveBufferSize];
var readCount = stream.Read(bytes, 0, bytes.Length);
string datastring = Encoding.UTF8.GetString(bytes);
txtdata.Invoke((MethodInvoker)(() => txtdata.Text = datastring.Substring(0, 100)));
txtno.Invoke((MethodInvoker)(() =>
txtno.Text = ("nnumber of bytes read: " + readCount)
));
String ch1 = txtdata.Text; ;
String[] ch1y = ch1.Split(new char[] { 'n', 'r' }, StringSplitOptions.RemoveEmptyEntries);
for (int a = 1; a < ch1y.Length - 1; a++)
{
chart1.Invoke((MethodInvoker)(() =>
chart1.Series[0].Points.AddXY(t, Convert.ToDouble(ch1y[a]))
));
}
}
这里的问题不在于您绘制数据的速度有多快,而在于您正在尝试使用非统一的异步模式绘制实时模拟值。
听起来你是在试图从第一原则的角度来解决这个问题,但是你忽略了很多必要的背景理解。
示波器有许多功能,可以让您专注于您在显示器上看到的模拟样本的特定宽度或长度,这可能代表音频的微小样本,显示器中线的振幅通常表示在相对时间点的电脉冲电压,而不是特定的时间点。
如果你的正弦波代表一个恒定的2KHz,你可以在屏幕上看到2个峰值(和2个低谷),那么你实际上是在看在1ms的间隔内捕获的数据,在图表中绘制像这样的波浪线需要许多点,所以你最初尝试将其绘制为单个X,Y坐标将需要许多,也许数百个,超过1ms的离散点来呈现相同类型的线,但是,您还必须特别小心,以确保x间隔表示确切的时间量,否则您绘制的点将不在正确的位置,相对于采样值的时间。
这种处理频率不是你想用c#实现的,那需要在硬件级别完成。
您使用的ESP32采样模拟输入将在特定间隔捕获特定数据包的数据,您可能已经看到像8位16Khz单声道这样的短语来描述音频质量。
根据ESP32中正在进行的处理,您接收到的字节通常将代表总样本,然后我们需要使用位来确定如何将字节分解为数组值,它不是单个值。
所以8位单声道意味着每8位将代表一个值,所以在这种情况下,每个字节都是一个单独的值。单声道表示这是一个一维的值数组,在立体声或2声道交错中,字节代表两个独立的值数组,因此每隔一个字节实际上就会进入第二个数组…所以你不简单地将字节转换为文本使用UTF8编码,你需要使用其他库,如NAudio解码这个,你可以尝试手动虽然。
在简单的c#术语中,假设8位单声道,您可以使用数组索引为X
, x索引处的字节值为Y
来绘制整个样本,但是这仍然与您在示波器中看到的不太匹配。
相反,考虑一下你真正想要在屏幕上看到什么,做一些研究使用快速傅立叶变换计算(FFT)来分析模拟读数,甚至有方法直接在ESP32上做到这一点,这可能会减少你在c#代码中所做的处理。
我降低了波特率。在此之后的2kHz波形几乎为纯正弦波。但只有2kHz的波是这样的。不是运行一个线程,而是使用Add
命令绘制每个时钟刻度的图表。