欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Qt5编写的一个推力传感器静态性能计算程序

程序员文章站 2022-05-28 11:35:49
...

最近一门课设做推力传感器设计和标定,要用到一个辅助程序,所以就用Qt5写了一个界面的计算程序,也分享上来供大家参考一下思路。

小程序:

数据处理方法在这里:链接:http://pan.baidu.com/s/1jIagziu 密码:9ya5

exe程序在这里:链接:http://pan.baidu.com/s/1c1YqNrq 密码:09gy

使用时,先输入校准点个数K和校准循环次数R,从表格(QTableWidget)输入原始数据,程序计算出一系列统计参数并从输出框输出,在下方绘制校准曲线。

在QPixmap绘图,之后用QLabel加载,也不需要动态更新,没有用paintevent (有没有大神,这样做有问题吗?)

为了方便输出,用了一个二维数组vector<qstringlist>保存计算结果,编写过程可能有些繁琐


头文件:

mainwidget.h

#ifndef MAINWIDGET_H
#define MAINWIDGET_H

#include <QtWidgets/QWidget>
#include "ui_mainwidget.h"

class mainWidget : public QWidget
{
	Q_OBJECT

public:
	mainWidget(QWidget *parent = 0);
	~mainWidget();

private:
	Ui::mainWidgetClass ui;

	//私有变量
	int K = 0, R = 0;//校准点个数,校准循环次数
	//QPixmap pixmap;

	//函数
	void mainWidget::setHeaders();//设置表头
	void mainWidget::print(const std::vector<std::vector<double>>& outputData);
	void mainWidget::paintCurve(const std::vector<std::vector<double>>& tableData, const std::vector<std::vector<double>>& outputData);
	//槽函数
	void mainWidget::on_spinBoxK_valueChanged();
	void mainWidget::on_spinBoxR_valueChanged();
	void mainWidget::on_buttonClearTable_clicked();
	void mainWidget::on_buttonClearTexeEdit_clicked();
	void mainWidget::on_buttonCompute_clicked();
};

#endif // MAINWIDGET_H


compute.h

#ifndef COMPUTE_H
#define COMPUTE_H

#include <vector>

void compute(const std::vector<std::vector<double>>& tableData, std::vector<std::vector<double>>& outputData);


#endif // COMPUTE_H

源文件:

main.cpp

#include "mainwidget.h"
#include <QtWidgets/QApplication>

int main(int argc, char *argv[])
{
	QApplication a(argc, argv);
	mainWidget w;
	w.show();
	return a.exec();
}

mainwidget.cpp

#include "mainwidget.h"
#include "compute.h"
#include <QPainter>

mainWidget::mainWidget(QWidget *parent)
	: QWidget(parent)
{
	ui.setupUi(this);

	//隔行改变背景色
	ui.tableWidget->setAlternatingRowColors(true);

	//ui.labelCurve->setScaledContents(true);
	//ui.labelCurve->setStyleSheet("QLabel{background:rgb(0,0,0);color:white;}");
	//初始化spinbox
	K = ui.tableWidget->rowCount();
	R = (ui.tableWidget->columnCount() - 1)/ 2;
	ui.spinBoxNumK->setValue(K);
	ui.spinBoxNumR->setValue(R);

	//设置表头
	setHeaders();
	
	connect(ui.spinBoxNumK, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &mainWidget::on_spinBoxK_valueChanged);
	connect(ui.spinBoxNumR, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &mainWidget::on_spinBoxR_valueChanged);
	connect(ui.buttonClearTable, &QPushButton::clicked, this, &mainWidget::on_buttonClearTable_clicked);
	connect(ui.buttonClearTextEdit, &QPushButton::clicked, this, &mainWidget::on_buttonClearTexeEdit_clicked);
	connect(ui.buttonCompute, &QPushButton::clicked, this, &mainWidget::on_buttonCompute_clicked);

}

mainWidget::~mainWidget()
{

}

void mainWidget::setHeaders()
{
	//设置表头
	QStringList headers;
	headers.append(QString("Xi/kN"));
	for (int i = 1; i <= R; i++)
	{
		headers.append(QString("Yci") + QString("%1/mV").arg(i));
		headers.append(QString("Yfi") + QString("%1/mV").arg(i));
	}
	ui.tableWidget->setHorizontalHeaderLabels(headers);
}

void mainWidget::print(const std::vector<std::vector<double>>& outputData)//输出
{
	for (int i = 0; i < K; i++)
	{
		ui.textEdit->append(QString(QString::fromLocal8Bit("-----------------------")));
		ui.textEdit->append(QString(QString::fromLocal8Bit("第%1个校准点:")).arg(i + 1));
		ui.textEdit->append(QString(QString::fromLocal8Bit("正行程平均值:%1")).arg(outputData.at(0).at(i)));
		ui.textEdit->append(QString(QString::fromLocal8Bit("反行程平均值:%1")).arg(outputData.at(1).at(i)));
		ui.textEdit->append(QString(QString::fromLocal8Bit("正、反行程总平均值:%1")).arg(outputData.at(2).at(i)));
		ui.textEdit->append(QString(QString::fromLocal8Bit("最小二乘值:%1")).arg(outputData.at(4).at(i)));
		ui.textEdit->append(QString(QString::fromLocal8Bit("线性差值ΔL:%1")).arg(outputData.at(5).at(i)));
		ui.textEdit->append(QString(QString::fromLocal8Bit("迟滞性ΔH:%1")).arg(outputData.at(6).at(i)));
		ui.textEdit->append(QString(QString::fromLocal8Bit("正行程标准差Sc:%1")).arg(outputData.at(7).at(i)));
		ui.textEdit->append(QString(QString::fromLocal8Bit("反行程标准差Sf:%1")).arg(outputData.at(8).at(i)));
		ui.textEdit->append(QString(QString::fromLocal8Bit("正行程系统偏差Bc:%1")).arg(outputData.at(9).at(i)));
		ui.textEdit->append(QString(QString::fromLocal8Bit("反行程系统偏差Bf:%1")).arg(outputData.at(10).at(i)));
		ui.textEdit->append(QString(QString::fromLocal8Bit("不确定度Bc+tSc:%1")).arg(outputData.at(11).at(i)));
		ui.textEdit->append(QString(QString::fromLocal8Bit("不确定度Bf+tSf:%1")).arg(outputData.at(12).at(i)));
		ui.textEdit->append(QString(QString::fromLocal8Bit("-----------------------")));
	}

	ui.textEdit->append(QString(QString::fromLocal8Bit("最终结果:")));
	ui.textEdit->append(QString(QString::fromLocal8Bit("y = bx + a,其中:")));
	ui.textEdit->append(QString(QString::fromLocal8Bit("b = %1")).arg(outputData.at(3).at(0)));
	ui.textEdit->append(QString(QString::fromLocal8Bit("a = %1")).arg(outputData.at(3).at(1)));
	//ui.textEdit->append(QString(QString::fromLocal8Bit("YF:%1")).arg(outputData.at(13).at(0)));
	//ui.textEdit->append(QString(QString::fromLocal8Bit("t_alpha:%1")).arg(outputData.at(13).at(1)));
	ui.textEdit->append(QString(QString::fromLocal8Bit("重复性:%1")).arg(outputData.at(13).at(2)));
	ui.textEdit->append(QString(QString::fromLocal8Bit("相对不确定度:%1")).arg(outputData.at(13).at(3)));
	ui.textEdit->append(QString(QString::fromLocal8Bit("非线性:%1")).arg(outputData.at(13).at(4)));
	ui.textEdit->append(QString(QString::fromLocal8Bit("迟滞性:%1")).arg(outputData.at(13).at(5)));
}

void mainWidget::paintCurve(const std::vector<std::vector<double>>& tableData, const std::vector<std::vector<double>>& outputData)//绘制曲线
{
	QPixmap pixmap(ui.labelCurve->width(), ui.labelCurve->height());
	pixmap.fill(Qt::black);//黑色背景
	QPainter p(&pixmap);//开始绘图----------------------------------------------------------

	//定义边距及图像大小
	int left = 35;
	int up = 10;
	int right = 15;
	int down = 20;
	int imgWidth = ui.labelCurve->width() - left - right;
	int imgHeight = ui.labelCurve->height() - up - down;

	//白色边框
	p.setPen(Qt::white);
	p.drawRect(left, up, imgWidth, imgHeight);
	
	//绿色网格线
	p.setPen(QPen(Qt::green, 1, Qt::DotLine));
	for (int i = left + imgWidth / 10; i <= left + imgWidth * 9 / 10; i += imgWidth / 10)
	{
		p.drawLine(i, up, i, up + imgHeight);
	}
	for (int j = up + imgHeight / 10; j <= up + imgHeight * 9 / 10; j += imgHeight / 10)
	{
		p.drawLine(left, j, left + imgWidth, j);
	}

	//坐标值
	p.setPen(QPen(Qt::white));
	p.drawText(left - 3, up + imgHeight + 15, QString("0"));
	p.drawText(left - 34, up + imgHeight + 5, QString("0.000"));

	double maxX = tableData.at(K - 1).at(0);//X坐标最大值
	for (int i = 1; i <= 10; i++)
	{
		p.drawText(left - 15 + i * imgWidth / 10, up + imgHeight + 15, QString::number(i * maxX / 10,'f',2));
	}
	
	double maxY = tableData.at(K - 1).at(1) * 1.1;//Y坐标最大值
	for (int j = 1; j <= 10; j++)
	{
		p.drawText(left - 34, up + imgHeight + 5 - j * imgHeight / 10, QString::number(j * maxY / 10, 'f', 3));
	}

	//工作曲线
	int numA = 0;//左截距 像素坐标值
	int numB = 0;//右截距 像素坐标值
	numA = outputData.at(3).at(1) / maxY * imgHeight;
	numB = (outputData.at(3).at(0) * tableData.at(K - 1).at(0) + outputData.at(3).at(1)) / maxY * imgHeight;
	p.setPen(QPen(Qt::yellow, 2));
	p.drawLine(left, up + imgHeight - numA, left + imgWidth, up + imgHeight - numB);

	//数据点
	p.setPen(QPen(Qt::red, 2));
	for (int i = 0; i < K; i++)
	{
		for (int j = 1; j <= 2 * R; j++)//j从1到R
		{
			int X;
			int Y;
			X = tableData.at(i).at(0) / tableData.at(K - 1).at(0) * imgWidth + left;
			Y = up + imgHeight - tableData.at(i).at(j) / maxY * imgHeight;
			p.drawPoint(X,Y);
		}

	}

	p.end();//结束绘图-------------------------------------------------------------------
	
	ui.labelCurve->setPixmap(pixmap);//显示
}

void mainWidget::on_spinBoxK_valueChanged()
{
	K = ui.spinBoxNumK->value();
	ui.tableWidget->setRowCount(K);
}

void mainWidget::on_spinBoxR_valueChanged()
{
	R = ui.spinBoxNumR->value();
	ui.tableWidget->setColumnCount(2 * R + 1);
	setHeaders();
}

void mainWidget::on_buttonClearTable_clicked()
{
	ui.tableWidget->clearContents();
}

void mainWidget::on_buttonClearTexeEdit_clicked()
{
	ui.textEdit->clear();
}

void mainWidget::on_buttonCompute_clicked()
{
	if (K == 0 || R == 0) return;
	else//若列表不为空
	{
		std::vector<std::vector<double>> tableData(K, std::vector<double>(2 * R + 1));//表格原始输入数据

		//按列遍历读取并检查数据
		for (int i = 0; i < K; i++)
		{
			for (int j = 0; j < 2 * R + 1; j++)
			{
				if (ui.tableWidget->item(i, j) == NULL) return;//若表格有填写空缺,退出函数
				else//单元格非空,读取数据
				{
					bool ok = true;
					tableData.at(i).at(j) = ui.tableWidget->item(i, j)->text().toDouble(&ok);
					//ui.textEdit->append(QString("%1").arg(tableData.at(i).at(j)));
					if (ok == false) return;//若表格输入非double类型,退出函数
				}
			}
		}

		//计算并输出
		std::vector<std::vector<double>> outputData(17);//用二维数组保存计算结果,见compute.cpp
		compute(tableData, outputData);//计算
		print(outputData);//输出
		paintCurve(tableData, outputData);//绘图并显示
		//ui.labelCurve->setPixmap(pixmap);//显示
	}

}


compute.cpp

#include "compute.h"
#include <cmath>

void compute(const std::vector<std::vector<double>>& tableData, std::vector<std::vector<double>>& outputData)
{
	const int K = tableData.size();
	const int R = (tableData.at(0).size() - 1) / 2;
	double temp1 = 0;//中间临时变量
	double temp2 = 0;

	//0正行程平均值
	//1反行程平均值
	//2总平均值
	for (int i = 0; i < K; i++)
	{
		for (int j = 1; j <= R; j++)//j从1到R
		{
			temp1 += tableData.at(i).at(2 * j - 1);//temp1、temp2表示正反行程Y的和
			temp2 += tableData.at(i).at(2 * j);
		}
		outputData.at(0).push_back(temp1 / R);//正行程平均值,一共push_back了K次
		outputData.at(1).push_back(temp2 / R);//反行程平均值
		outputData.at(2).push_back((temp1 + temp2) / R / 2);//总平均值

		temp1 = 0;//置零
		temp2 = 0;

	}
	
	//3求a 求b
	double sum_x = 0;
	double sum_x2 = 0;
	double sum_y = 0;
	double sum_xy = 0;
	double a = 0, b = 0;
	for (int i = 0; i < K; i++)
	{
		sum_x += tableData.at(i).at(0);
		sum_x2 += tableData.at(i).at(0) * tableData.at(i).at(0);
		sum_y += outputData.at(2).at(i);
		sum_xy += tableData.at(i).at(0) * outputData.at(2).at(i);
	}
	b = (K * sum_xy - sum_x * sum_y) / (K * sum_x2 - sum_x * sum_x);
	a = sum_y / K - b * sum_x / K;
	outputData.at(3).push_back(b);
	outputData.at(3).push_back(a);

	//4最小二乘值bx+a
	//5线性差值
	//6迟滞性
	//9正行程系统偏差Bc
	//10反行程系统偏差Bf
	for (int i = 0; i < K; i++)
	{
		outputData.at(4).push_back(b * tableData.at(i).at(0) + a);
		outputData.at(5).push_back(std::abs(outputData.at(2).at(i) - outputData.at(4).at(i)));
		outputData.at(6).push_back(std::abs(outputData.at(0).at(i) - outputData.at(1).at(i)));

		outputData.at(9).push_back(std::abs(outputData.at(0).at(i) - outputData.at(4).at(i)));
		outputData.at(10).push_back(std::abs(outputData.at(1).at(i) - outputData.at(4).at(i)));
		
	}
	
	//7正行程标准差Sc
	//8反行程标准差Sf
	temp1 = 0;//temp1、temp2表示正反行程(Yi-Y_average)^2的和
	temp2 = 0;//置零
	for (int i = 0; i < K; i++)//第i个校准点
	{
		for (int j = 1; j <= R; j++)//j从1到R
		{
			temp1 += (tableData.at(i).at(2 * j - 1) - outputData.at(0).at(i))
					* (tableData.at(i).at(2 * j - 1) - outputData.at(0).at(i));
			temp2 += (tableData.at(i).at(2 * j) - outputData.at(1).at(i))
					* (tableData.at(i).at(2 * j) - outputData.at(1).at(i));
		}
		outputData.at(7).push_back(std::sqrt(temp1 / (R - 1)));//正行程标准差
		outputData.at(8).push_back(std::sqrt(temp2 / (R - 1)));//反行程标准差
	}

	//11 Bc+t0.95Sc
	//12 Bf+t0.95Sf
	double t_alpha = 0;//t_0.95
	switch (R)
	{
		case 2:
		{
			t_alpha = 12.706;
			break;
		}
		case 3:
		{
			t_alpha = 4.303;
			break;
		}
		case 4:
		{
			t_alpha = 3.182;
			break;
		}
		case 5:
		{
			t_alpha = 2.776;
			break;
		}
		case 6:
		{
			t_alpha = 2.571;
			break;
		}
		case 7:
		{
			t_alpha = 2.447;
			break;
		}
		case 8:
		{
			t_alpha = 2.365;
			break;
		}
	}

	for (int i = 0; i < K; i++)
	{
		outputData.at(11).push_back(outputData.at(9).at(i) + t_alpha * outputData.at(7).at(i));//11 Bc+t0.95Sc
		outputData.at(12).push_back(outputData.at(10).at(i) + t_alpha * outputData.at(8).at(i));//12 Bf+t0.95Sf
	}
	

	//13 0:Yfc = b * (Xk - X1)、1:t_alpha、2:重复性、3:不确定度、4:非线性、5:迟滞
	outputData.at(13).push_back(b * (tableData.at(K - 1).at(0) - tableData.at(0).at(0)));
	outputData.at(13).push_back(t_alpha);

	double maxS = outputData.at(7).at(0);//最大标准差
	double maxU = outputData.at(11).at(0);//不确定度
	double maxL = outputData.at(5).at(0);//最大线性差值
	double maxH = outputData.at(6).at(0);//最大迟滞性
	for (int i = 0; i < K; i++)
	{
		if (outputData.at(7).at(i) > maxS) maxS = outputData.at(7).at(i);
		if (outputData.at(8).at(i) > maxS) maxS = outputData.at(8).at(i);

		if (outputData.at(11).at(i) > maxU) maxU = outputData.at(11).at(i);
		if (outputData.at(12).at(i) > maxU) maxU = outputData.at(12).at(i);

		if (outputData.at(5).at(i) > maxL) maxL = outputData.at(5).at(i);

		if (outputData.at(6).at(i) > maxH) maxH = outputData.at(6).at(i);
	}

	outputData.at(13).push_back(t_alpha * maxS / outputData.at(13).at(0));//重复性2
	outputData.at(13).push_back(maxU / outputData.at(13).at(0));//相对不确定度3
	outputData.at(13).push_back(maxL / outputData.at(13).at(0));//非线性4
	outputData.at(13).push_back(maxH / outputData.at(13).at(0));//迟滞5
}



mainwidget.ui:

Qt5编写的一个推力传感器静态性能计算程序

控件布局:

Qt5编写的一个推力传感器静态性能计算程序


最终效果(虚构的数据):

Qt5编写的一个推力传感器静态性能计算程序


就这些,除 了计算各种统计量有些繁琐以外,没有什么难的地方。以上可供Qt初学者参考,我也只是个菜鸟,可能有很多地方写得不好,欢迎批评指正

相关标签: qt5 界面 软件

上一篇: javaGUI基础(一)

下一篇: 3