2025-03-26 09:30:02 +00:00
|
|
|
|
#include <QDebug>
|
|
|
|
|
|
|
|
|
|
|
|
#include "peakpoint.h"
|
|
|
|
|
|
|
|
|
|
|
|
QVector<FileManager::ExperimentData>PeakPoint:: _dataVtr;
|
2025-03-27 09:31:19 +00:00
|
|
|
|
float PeakPoint::_leftPointX,PeakPoint::_rightPointX;
|
2025-03-26 09:30:02 +00:00
|
|
|
|
QPointF PeakPoint::_peakPoint;
|
2025-03-27 09:31:19 +00:00
|
|
|
|
QPointF PeakPoint::_leftSelectedPoint,PeakPoint::_rightSelectedPoint;
|
2025-03-26 09:30:02 +00:00
|
|
|
|
|
|
|
|
|
|
void PeakPoint::setExperimentData(const QVector<FileManager::ExperimentData> &dataVtr)
|
|
|
|
|
|
{
|
|
|
|
|
|
_dataVtr = dataVtr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QPointF PeakPoint::findPeakPoint(){
|
|
|
|
|
|
int n = _dataVtr.size();
|
|
|
|
|
|
|
|
|
|
|
|
if (n < 3) {
|
|
|
|
|
|
return QPointF(); // 至少需要三个点才能找到波峰
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QPointF uniquePeak;
|
2025-03-27 09:31:19 +00:00
|
|
|
|
// 初始化为 float 类型能表示的最小负数,确保能处理负数 y 值
|
|
|
|
|
|
float maxY = 0.0;
|
2025-03-26 09:30:02 +00:00
|
|
|
|
bool findFlag = false;
|
|
|
|
|
|
|
|
|
|
|
|
// 直接在遍历过程中找出最大波峰
|
|
|
|
|
|
for (int i = 1; i < n - 1; ++i) {
|
2025-03-27 09:31:19 +00:00
|
|
|
|
const float currentX = _dataVtr.at(i).sampleTemp;
|
|
|
|
|
|
const float currentY = _dataVtr.at(i).dsc;
|
2025-03-26 09:30:02 +00:00
|
|
|
|
|
|
|
|
|
|
if(currentX < _leftPointX){
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(currentX > _rightPointX){
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-27 09:31:19 +00:00
|
|
|
|
const float preY = _dataVtr.at(i - 1).dsc;
|
|
|
|
|
|
const float lastY = _dataVtr.at(i + 1).dsc;
|
2025-03-26 09:30:02 +00:00
|
|
|
|
|
|
|
|
|
|
findFlag = false;
|
|
|
|
|
|
if(currentY >= preY && currentY >= lastY){
|
|
|
|
|
|
findFlag = true;
|
|
|
|
|
|
}else if(currentY <= preY && currentY <= lastY){
|
|
|
|
|
|
findFlag = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(findFlag){
|
2025-03-27 09:31:19 +00:00
|
|
|
|
float absY = std::abs(currentY);
|
2025-03-26 09:30:02 +00:00
|
|
|
|
if(absY >= maxY){
|
|
|
|
|
|
maxY = absY;
|
|
|
|
|
|
uniquePeak = QPointF(currentX,currentY);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
_peakPoint = uniquePeak;
|
|
|
|
|
|
|
|
|
|
|
|
return uniquePeak;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QPair<QPointF, QPointF> PeakPoint::calculateMaxDiffPointDetail(
|
|
|
|
|
|
const PeakPoint::MaxDiffPointDetailType type)
|
|
|
|
|
|
{
|
|
|
|
|
|
#if 1
|
2025-03-27 09:31:19 +00:00
|
|
|
|
float maxDiff = std::numeric_limits<float>::min();
|
2025-03-26 09:30:02 +00:00
|
|
|
|
QPointF currentPoint,lastPoint;
|
|
|
|
|
|
|
|
|
|
|
|
for (int i = 0; i < _dataVtr.size() - 1; ++i) {
|
2025-03-27 09:31:19 +00:00
|
|
|
|
const float currentX = _dataVtr.at(i).sampleTemp;
|
|
|
|
|
|
const float currentY = _dataVtr.at(i).dsc;
|
2025-03-26 09:30:02 +00:00
|
|
|
|
|
|
|
|
|
|
if(type == MaxDiffPointDetailType::Left){
|
|
|
|
|
|
if(currentX <= _leftPointX){
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(currentX >= _peakPoint.x()){
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}else{
|
|
|
|
|
|
if(currentX <= _peakPoint.x()){
|
|
|
|
|
|
continue;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(currentX >= _rightPointX){
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
//
|
2025-03-27 09:31:19 +00:00
|
|
|
|
const float lastX = _dataVtr.at(i + 1).sampleTemp;
|
|
|
|
|
|
const float lastY = _dataVtr.at(i + 1).dsc;
|
|
|
|
|
|
float diff = std::abs(currentY - lastY);
|
2025-03-26 09:30:02 +00:00
|
|
|
|
if(diff > maxDiff){
|
|
|
|
|
|
maxDiff = diff;
|
|
|
|
|
|
|
|
|
|
|
|
currentPoint.setX(currentX);
|
|
|
|
|
|
currentPoint.setY(currentY);
|
|
|
|
|
|
lastPoint.setX(lastX);
|
|
|
|
|
|
lastPoint.setY(lastY);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
return qMakePair(currentPoint,lastPoint);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QPair<QPointF, QPointF> PeakPoint::calculateMaxDiffPointLeft()
|
|
|
|
|
|
{
|
|
|
|
|
|
return calculateMaxDiffPointDetail(MaxDiffPointDetailType::Left);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QPair<QPointF, QPointF> PeakPoint::calculateMaxDiffPointRight()
|
|
|
|
|
|
{
|
|
|
|
|
|
return calculateMaxDiffPointDetail(MaxDiffPointDetailType::Right);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-27 09:31:19 +00:00
|
|
|
|
float PeakPoint::findClosestY(float targetX)
|
2025-03-26 09:30:02 +00:00
|
|
|
|
{
|
2025-03-27 09:31:19 +00:00
|
|
|
|
float minDiff = std::numeric_limits<float>::max();
|
|
|
|
|
|
float closestY = 0.0;
|
2025-03-26 09:30:02 +00:00
|
|
|
|
|
|
|
|
|
|
for(FileManager::ExperimentData &ed:_dataVtr){
|
|
|
|
|
|
// 计算当前 x 与目标 x 的差值的绝对值
|
2025-03-27 09:31:19 +00:00
|
|
|
|
float diff = std::abs(ed.sampleTemp - targetX);
|
2025-03-26 09:30:02 +00:00
|
|
|
|
// 更新最小差值和对应的 y 值
|
|
|
|
|
|
if (diff < minDiff) {
|
|
|
|
|
|
minDiff = diff;
|
|
|
|
|
|
closestY = ed.dsc;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return closestY;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-27 09:31:19 +00:00
|
|
|
|
QPointF PeakPoint::findClosestPointByX(float x) {
|
2025-03-26 09:30:02 +00:00
|
|
|
|
int left = 0;
|
|
|
|
|
|
int right = _dataVtr.size() - 1;
|
|
|
|
|
|
|
|
|
|
|
|
QPointF targetPoint;
|
|
|
|
|
|
targetPoint.setX(_dataVtr.value(0).sampleTemp);
|
|
|
|
|
|
targetPoint.setY(_dataVtr.value(0).dsc);
|
|
|
|
|
|
|
|
|
|
|
|
while (left <= right) {
|
|
|
|
|
|
int mid = left + (right - left) / 2;
|
|
|
|
|
|
FileManager::ExperimentData& ed = _dataVtr[mid];
|
|
|
|
|
|
|
|
|
|
|
|
if (std::abs(ed.sampleTemp - x) < std::abs(targetPoint.x() - x)) {
|
|
|
|
|
|
targetPoint.setX(ed.sampleTemp);
|
|
|
|
|
|
targetPoint.setY(ed.dsc);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(ed.sampleTemp < x){
|
|
|
|
|
|
left = mid + 1;
|
|
|
|
|
|
} else {
|
|
|
|
|
|
right = mid - 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return targetPoint;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-27 09:31:19 +00:00
|
|
|
|
void PeakPoint::setRegionPointX(const float left, const float right)
|
2025-03-26 09:30:02 +00:00
|
|
|
|
{
|
|
|
|
|
|
_leftPointX = left;
|
|
|
|
|
|
_rightPointX = right;
|
|
|
|
|
|
|
|
|
|
|
|
_leftSelectedPoint = findClosestPointByX(_leftPointX);
|
|
|
|
|
|
_rightSelectedPoint = findClosestPointByX(_rightPointX);
|
|
|
|
|
|
|
2025-03-27 09:31:19 +00:00
|
|
|
|
findPeakPoint();
|
|
|
|
|
|
|
|
|
|
|
|
updateStartEndPoint();
|
|
|
|
|
|
|
2025-03-26 09:30:02 +00:00
|
|
|
|
qDebug()<<"left,right point:"<<_leftSelectedPoint
|
|
|
|
|
|
<<","<<_rightSelectedPoint;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-27 09:31:19 +00:00
|
|
|
|
QVector<QPointF> PeakPoint::getPeakPointGroup()
|
|
|
|
|
|
{
|
|
|
|
|
|
QVector<QPointF> pointVtr;
|
|
|
|
|
|
for(FileManager::ExperimentData& ed:_dataVtr) {
|
|
|
|
|
|
if(ed.sampleTemp >= _leftSelectedPoint.x() && ed.sampleTemp <= _rightSelectedPoint.x()){
|
|
|
|
|
|
pointVtr.push_back(QPointF(ed.sampleTemp,ed.dsc));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return pointVtr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QPair<QPointF, QPointF> PeakPoint::calculateStartAndEndPoint()
|
|
|
|
|
|
{
|
|
|
|
|
|
QPair<QPointF,QPointF> leftMaxDiffPointPair = PeakPoint::calculateMaxDiffPointLeft();
|
|
|
|
|
|
QPair<QPointF,QPointF> rightMaxDiffPointPair = PeakPoint::calculateMaxDiffPointRight();
|
|
|
|
|
|
|
|
|
|
|
|
QPointF startPoint = calculateIntersection(_leftSelectedPoint,_rightSelectedPoint,
|
|
|
|
|
|
leftMaxDiffPointPair.first,leftMaxDiffPointPair.second);
|
|
|
|
|
|
|
|
|
|
|
|
QPointF endPoint = calculateIntersection(_leftSelectedPoint,_rightSelectedPoint,
|
|
|
|
|
|
rightMaxDiffPointPair.first,rightMaxDiffPointPair.second);
|
|
|
|
|
|
|
|
|
|
|
|
return qMakePair(startPoint,endPoint);
|
|
|
|
|
|
}
|
|
|
|
|
|
void PeakPoint::updateStartEndPoint()
|
|
|
|
|
|
{
|
|
|
|
|
|
//需要在a1和a2之间查询是否有高于a1和a2之间的点,若存在,则重新给a1、a2赋值
|
|
|
|
|
|
|
|
|
|
|
|
for(FileManager::ExperimentData& ed:_dataVtr){
|
|
|
|
|
|
if(ed.sampleTemp > _leftSelectedPoint.x() && ed.sampleTemp < _peakPoint.x()){
|
|
|
|
|
|
if(ed.dsc > _leftSelectedPoint.y()){
|
|
|
|
|
|
_leftSelectedPoint.setX(ed.sampleTemp);
|
|
|
|
|
|
_leftSelectedPoint.setY(ed.dsc);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if(ed.sampleTemp < _rightSelectedPoint.x() && ed.sampleTemp > _peakPoint.x()){
|
|
|
|
|
|
if(ed.dsc > _rightSelectedPoint.y()){
|
|
|
|
|
|
_rightSelectedPoint.setX(ed.sampleTemp);
|
|
|
|
|
|
_rightSelectedPoint.setY(ed.dsc);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
QString PeakPoint::textFormat(const float enthalpyValue,
|
|
|
|
|
|
const float peakValue,
|
|
|
|
|
|
const float startPoint,
|
|
|
|
|
|
const float endPoint)
|
2025-03-26 09:30:02 +00:00
|
|
|
|
{
|
|
|
|
|
|
return QString("峰的综合信息:\n"
|
|
|
|
|
|
"焓值:%1 J/g \n"
|
|
|
|
|
|
"峰值:%2℃ \n"
|
|
|
|
|
|
"起始点:%3℃ \n"
|
|
|
|
|
|
"终止点:%4℃"
|
|
|
|
|
|
).arg(QString::number(enthalpyValue, 'f', 2))
|
|
|
|
|
|
.arg(QString::number(peakValue, 'f', 2))
|
|
|
|
|
|
.arg(QString::number(startPoint, 'f', 2))
|
|
|
|
|
|
.arg(QString::number(endPoint, 'f', 2));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 计算两条直线的交点
|
|
|
|
|
|
QPointF PeakPoint::calculateIntersection(const QPointF p1,const QPointF p2,
|
|
|
|
|
|
const QPointF p3, const QPointF p4){
|
|
|
|
|
|
// 直线的一般式: A1x + B1y + C1 = 0 和 A2x + B2y + C2 = 0
|
2025-03-27 09:31:19 +00:00
|
|
|
|
float A1 = p2.y() - p1.y();
|
|
|
|
|
|
float B1 = p1.x() - p2.x();
|
|
|
|
|
|
float C1 = A1 * p1.x() + B1 * p1.y();
|
2025-03-26 09:30:02 +00:00
|
|
|
|
|
2025-03-27 09:31:19 +00:00
|
|
|
|
float A2 = p4.y() - p3.y();
|
|
|
|
|
|
float B2 = p3.x() - p4.x();
|
|
|
|
|
|
float C2 = A2 * p3.x() + B2 * p3.y();
|
2025-03-26 09:30:02 +00:00
|
|
|
|
|
2025-03-27 09:31:19 +00:00
|
|
|
|
float determinant = A1 * B2 - A2 * B1;
|
2025-03-26 09:30:02 +00:00
|
|
|
|
|
|
|
|
|
|
if (determinant == 0) {
|
|
|
|
|
|
// 两条直线平行或重合,无交点或无限交点
|
|
|
|
|
|
return {0, 0};
|
|
|
|
|
|
} else {
|
2025-03-27 09:31:19 +00:00
|
|
|
|
float x = (B2 * C1 - B1 * C2) / determinant;
|
|
|
|
|
|
float y = (A1 * C2 - A2 * C1) / determinant;
|
2025-03-26 09:30:02 +00:00
|
|
|
|
return {x, y};
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-27 09:31:19 +00:00
|
|
|
|
float PeakPoint::calculateArea() {
|
|
|
|
|
|
//getPoint group
|
|
|
|
|
|
QVector<QPointF> points = getPeakPointGroup();
|
|
|
|
|
|
#if 0
|
|
|
|
|
|
for(QPointF point:points){
|
|
|
|
|
|
qDebug()<<"x,y:"<<QString::number(point.x(),'f',3)<<","
|
|
|
|
|
|
<<QString::number(point.y(),'f',3);
|
|
|
|
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
|
|
qDebug()<<QString::number(points.at(0).x(),'f',3)<<","<<
|
|
|
|
|
|
QString::number(points.at(points.size() - 1).x(),'f',3);
|
|
|
|
|
|
|
|
|
|
|
|
//calculate Area
|
|
|
|
|
|
float integral = 0.0;
|
2025-03-26 09:30:02 +00:00
|
|
|
|
size_t n = points.size();
|
|
|
|
|
|
|
|
|
|
|
|
if (n < 2) {
|
|
|
|
|
|
return integral; // 至少需要两个点才能计算积分
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (size_t i = 1; i < n; ++i) {
|
2025-03-27 09:31:19 +00:00
|
|
|
|
float dx = points[i].x() - points[i - 1].x();
|
|
|
|
|
|
float avg_y = (points[i].y() + points[i - 1].y()) / 2.0;
|
|
|
|
|
|
|
|
|
|
|
|
float step = dx * std::abs(avg_y);
|
|
|
|
|
|
qDebug()<<points[i].x()<<","<<points[i].y()<<"integral:"<<integral<<","<<step;
|
|
|
|
|
|
|
|
|
|
|
|
integral += dx * std::abs(avg_y);
|
2025-03-26 09:30:02 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return integral;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-27 09:31:19 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|