示波软件
示波软件使用“像素点”的高低表示输入值的大小。
设输入值 \(x \in \left[source_{min},source_{max}\right]\),像素点的高度 \(y \in \left[target_{min},target_{max}\right]\),我们需要把 x 缩放成 y 。
可以用线性方程(一次方程)进行缩放,以保证数值分布的均匀性。
待定缩放方程 \(y = mx + b\) ,
其斜率 \(m = \frac{\Delta y}{\Delta x} = \frac{target_{max} - target_{min}}{source_{max} - source_{min}}\) 。
因方程过点 \(\left(source_{min},target_{min}\right)\), 有 \(y - target_{min} = m(x - source_{min})\) ,
代入 m,得 \(y = \frac{target_{max} - target_{min}}{source_{max} - source_{min}}(x - source_{min}) + target_{min}\) 。
当 \(source_{min} = target_{min} = 0\) 时,缩放方程可简化为 \(y = \frac{target_{max}}{source_{max}}x\) 。
Form.cs
using System;
using System.IO.Ports;
using System.Text.RegularExpressions;
namespace wave
{
public partial class Form : System.Windows.Forms.Form
{
private SerialPort? serialPort;
private readonly List<Point> targetPoints = [];
private readonly List<Point> actualPoints = [];
private Point minLeftPoint, maxLeftPoint, minRightPoint, maxRightPoint;
private const int STEP = 2;
private int pointX = -STEP;
private int minValue = int.MaxValue;
private int maxValue = int.MinValue;
public Form()
{
InitializeComponent();
this.DoubleBuffered = true;
}
/**
* 绘图
*/
private void PanelChart_Paint(object sender, PaintEventArgs e)
{
if (pointX > 0)
{
Graphics g = e.Graphics;
// 画目标值折线
using Pen penTarget = new(Color.Red, 2);
g.DrawLines(penTarget, targetPoints.ToArray());
// 画实际值折线
using Pen penActual = new(Color.Blue, 2);
g.DrawLines(penActual, actualPoints.ToArray());
// 画实际值的边界线
using Pen penEdge = new(Color.Yellow, 2);
g.DrawLine(penEdge, minLeftPoint, minRightPoint);// 最小值
g.DrawLine(penEdge, maxLeftPoint, maxRightPoint);// 最大值
this.labelStatus.Text = minValue + "," + maxValue;
}
}
/**
* 启动
*/
private void ButtonStart_Click(object sender, EventArgs e)
{
serialPort = new()
{
PortName = this.comboBoxCOM.Text,
BaudRate = 9600,
Parity = Parity.None,
DataBits = 8,
StopBits = StopBits.One
};
serialPort.DataReceived += new SerialDataReceivedEventHandler(SerialDataReceivedHandler);
serialPort.Open();// 打开串口
this.buttonStart.Enabled = false;
this.buttonStop.Enabled = true;
}
/**
* 接收数据
*/
private void SerialDataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
SerialPort sp = (SerialPort)sender;
string data = sp.ReadExisting();
string pattern = @"Val:(\d+),(\d+)";
Match match = Regex.Match(data, pattern);
if (match.Success)
{
// 提取目标值,实际值,实际值边界。
int targetValue = int.Parse(match.Groups[1].Value);
int actualValue = int.Parse(match.Groups[2].Value);
if (actualValue < minValue) minValue = actualValue;
if (actualValue > maxValue) maxValue = actualValue;
// 计算像素横坐标
pointX += STEP;
// 横坐标到达右侧边界后,立即返回左侧边界,从头绘制。
if (pointX > this.panelChart.Width)
{
pointX = 0;
minValue = int.MaxValue;
maxValue = int.MinValue;
targetPoints.Clear();
actualPoints.Clear();
}
// 生成像素
targetPoints.Add(new Point(pointX, CalcPointY(targetValue)));
actualPoints.Add(new Point(pointX, CalcPointY(actualValue)));
minLeftPoint = new Point(0, CalcPointY(minValue));
maxLeftPoint = new Point(0, CalcPointY(maxValue));
minRightPoint = new Point(this.panelChart.Width, CalcPointY(minValue));
maxRightPoint = new Point(this.panelChart.Width, CalcPointY(maxValue));
// 开始绘图
this.panelChart.Invalidate();
}
}
/**
* 停止
*/
private void ButtonStop_Click(object sender, EventArgs e)
{
serialPort?.Close();
this.buttonStart.Enabled = true;
this.buttonStop.Enabled = false;
}
/**
* 计算像素纵坐标
*/
public int CalcPointY(int sourceValue)
{
/**
* 将 sourceValue 从原始区间[sourceMin,sourceMax]线性缩放至目标区间[targetMin,targetMax]。
*/
int sourceMin = 0;
int sourceMax = 4095;
int targetMin = 0;
int targetMax = this.panelChart.Height;
double targetValue = 1.0 * (targetMax - targetMin) / (sourceMax - sourceMin)
* (sourceValue - sourceMin)
+ targetMin;
/**
* 像素坐标系原点位于容器(panelChart)左上角,向右的方向为x轴正方向,向下的方向为y轴正方向。
* 将缩放后的数值进一步转换成像素纵坐标。
*/
return Convert.ToInt32(this.panelChart.Height - targetValue);
}
/**
* 识别串口
*/
private void ComboBoxCOM_Click(object sender, EventArgs e)
{
string[] names = SerialPort.GetPortNames();
comboBoxCOM.Items.Clear();
comboBoxCOM.Items.AddRange(names);
}
}
}
浙公网安备 33010602011771号