2025-04-21T17:31:37

This commit is contained in:
yuntang 2025-04-21 17:31:38 +08:00
parent 1e2a73bd02
commit a00031c009
6 changed files with 320 additions and 11 deletions

Binary file not shown.

View File

@ -363,7 +363,7 @@ QPair<float,float> PointCalculate::getCurveInflectionPointTangent(const float x1
dataVtr.push_back(ed.sampleTemp);
}
}
//
// 5
std::vector<float> processedVtr = movingAverage(dataVtr,5);
// find max slope.
@ -387,7 +387,7 @@ QPair<float,float> PointCalculate::getCurveInflectionPointTangent(const float x1
return qMakePair<float,float>(maxSlope,b);
}
QPointF PointCalculate::getIntersectionBySlope(const LineStruct& line1, const LineStruct& line2) {
QPointF PointCalculate::getIntersection(const Line& line1, const Line& line2) {
float x = (line2.intercept - line1.intercept) / (line1.slope - line2.slope);
float y = line1.slope * x + line1.intercept;
// return {x, y};
@ -541,3 +541,81 @@ QVector<Global::ExperimentData> PointCalculate::getDataInXRange(const float x1,
return targetVtr;
}
QVector<QPointF> PointCalculate::getNearbyPointGroupByX(const float targetX)
{
const int conCount = 10;
QVector<QPointF> tmpPointVtr,targetPointVtr;
float minDiff = std::numeric_limits<float>::max();
for(Global::ExperimentData &ed:_dataVtr){
float diff = std::abs(ed.sampleTemp - targetX);
if(diff > 10){
continue;
}
tmpPointVtr.push_back({ed.sampleTemp,ed.dsc});
if (diff < minDiff) {
minDiff = diff;
targetPointVtr = QVector<QPointF>(tmpPointVtr.end() - conCount, tmpPointVtr.end());
}
}
return targetPointVtr;
}
// 计算两点之间的斜率
double PointCalculate::calculateSlope(double x1, double y1, double x2, double y2) {
return (y2 - y1) / (x2 - x1);
}
// 寻找第一个拐点
QVector<double> PointCalculate::findInflectionPoints(
const QVector<double>& x, const QVector<double>& y) {
QVector<double> inflectionPointsX;
for (int i = 2; i < x.size() - 2; ++i) {
double d1 = calculateSlope(x[i - 2], y[i - 2], x[i - 1], y[i - 1]);
double d2 = calculateSlope(x[i - 1], y[i - 1], x[i], y[i]);
double d3 = calculateSlope(x[i], y[i], x[i + 1], y[i + 1]);
double d4 = calculateSlope(x[i + 1], y[i + 1], x[i + 2], y[i + 2]);
// 检查二阶导数的符号变化
if (((d2 - d1) * (d3 - d2) < 0) && ((d3 - d2) * (d4 - d3) < 0)) {
inflectionPointsX.append(x[i]);
}
}
return inflectionPointsX;
}
// 计算切线方程
QMap<double, PointCalculate::Line> PointCalculate::calculateTangentLine(
const QVector<double>& x, const QVector<double>& y) {
QMap<double, Line> tangentLines;
QVector<double> inflectionPointsX = findInflectionPoints(x, y);
for (double xInflection : inflectionPointsX) {
int i = std::distance(x.begin(), std::find(x.begin(), x.end(), xInflection));
double slope = calculateSlope(x[i - 1], y[i - 1], x[i + 1], y[i + 1]);
double yInflection = y[i];
double intercept = yInflection - slope * xInflection;
tangentLines[xInflection] = {slope, intercept};
}
return tangentLines;
}
QVector<QPointF> PointCalculate::getPointVtrInXRange(const float x1, const float x2)
{
QVector<QPointF> targetVtr;
for(const Global::ExperimentData &ed : _dataVtr) {
if(x1 < ed.sampleTemp && ed.sampleTemp < x2){
targetVtr.push_back({ed.sampleTemp,ed.dsc});
}else if (ed.sampleTemp > x2){
break;
}
}
return targetVtr;
}

View File

@ -10,9 +10,13 @@ void setExperimentData(const QVector<Global::ExperimentData>&);
QPair<QPointF,QPointF> getStartAndEndPoint();
QVector<Global::ExperimentData> getDataInXRange(const float, const float);
QVector<QPointF> getPointVtrInXRange(const float, const float);
void setRegionPointX(const float,const float);
QPointF getClosestPointByX(const float);
QVector<QPointF> getNearbyPointGroupByX(const float);
QPointF getClosestPointByY(const float left,const float right,const float valueY);
QPointF getPeakPoint();
QPair<float, float> getMaxMinValue();
@ -32,11 +36,14 @@ QString textFormatGlassTranstion(const float t1,const float tg,const float t2);
// glass transition
QPair<float,float> getCurveInflectionPointTangent(const float,const float);
struct LineStruct {
float slope; //
float intercept; //
struct Line {
double slope; //
double intercept; //
};
QPointF getIntersectionBySlope(const LineStruct& line1, const LineStruct& line2);
QPointF getIntersection(const Line& line1, const Line& line2);
double calculateSlope(double x1, double y1, double x2, double y2) ;
QVector<double> findInflectionPoints(const QVector<double>& x, const QVector<double>& y) ;
QMap<double, Line> calculateTangentLine(const QVector<double>& x, const QVector<double>& y) ;
//private
void updateStartEndPoint();

View File

@ -352,7 +352,8 @@ void CentralWidget::slotAnalysisSettingApply()
}
case AnalysisMode::GlassTransition:
{
glassTransitionHandle();
// glassTransitionHandle();
glassTransitionHandle2();
//
break;
}
@ -452,7 +453,7 @@ void CentralWidget::glassTransitionHandle()
_customPlot->replot();
#endif
//
PointCalculate::LineStruct lineStrc1,lineStrc2,tangetLineStrc;
PointCalculate::Line lineStrc1,lineStrc2,tangetLineStrc;
lineStrc1.slope = 0.0;
lineStrc1.intercept = point1.y();
@ -464,8 +465,8 @@ void CentralWidget::glassTransitionHandle()
tangetLineStrc.slope = tangentLinePair.first;
tangetLineStrc.intercept = tangentLinePair.second;
QPointF intersection1 = PointCalculate::getIntersectionBySlope(tangetLineStrc,lineStrc1);
QPointF intersection2 = PointCalculate::getIntersectionBySlope(tangetLineStrc,lineStrc2);
QPointF intersection1 = PointCalculate::getIntersection(tangetLineStrc,lineStrc1);
QPointF intersection2 = PointCalculate::getIntersection(tangetLineStrc,lineStrc2);
// logde<<"intersection1 x:"<<intersection1.x();
// logde<<"intersection2 x:"<<intersection2.x();
@ -487,8 +488,37 @@ void CentralWidget::glassTransitionHandle()
QString str = PointCalculate::textFormatGlassTranstion(intersection2.x(),
averagePoint.x(),
intersection1.x());
//draw line
///line1
QVector<double> xVtr,yVtr;
xVtr.push_back(intersection1.x());
xVtr.push_back(point1.x());
yVtr.push_back(intersection1.y());
yVtr.push_back(point1.y());
QCPGraph *lineGraph1 = _customPlot->addGraph();
lineGraph1->setData(xVtr, yVtr);
_customPlot->replot();
///line2
QVector<double> xVtr2,yVtr2;
xVtr2.push_back(intersection2.x());
xVtr2.push_back(point2.x());
yVtr2.push_back(intersection2.y());
yVtr2.push_back(point2.y());
QCPGraph *lineGraph2 = _customPlot->addGraph();
lineGraph2->setData(xVtr2, yVtr2);
_customPlot->replot();
//draw text
drawText(averagePoint,str);
_customPlot->replot();
#if 0
// 创建一个圆形绘图项
QCPItemEllipse *circle = new QCPItemEllipse(_customPlot);
@ -515,6 +545,192 @@ void CentralWidget::glassTransitionHandle()
#endif
}
void CentralWidget::glassTransitionHandle2()
{
QPointF point1 = PointCalculate::getClosestPointByX(_line1->point1->coords().x());
QPointF point2 = PointCalculate::getClosestPointByX(_line2->point1->coords().x());
logde<<"point1:"<<point1.x()<<","<<point1.y();
logde<<"point2:"<<point2.x()<<","<<point2.y();
QVector<QPointF> point1Vtr = PointCalculate::getNearbyPointGroupByX(point1.x());
QVector<QPointF> point2Vtr = PointCalculate::getNearbyPointGroupByX(point2.x());
QVector<double> xVtr,yVtr;
for(QPointF &p:point1Vtr){
xVtr.append(p.x());
yVtr.append(p.y());
}
PointCalculate::Line line1 = calculateLinearRegression(xVtr,yVtr);
#if 1
///line1
// QVector<double> xVtr,yVtr;
xVtr.clear();
yVtr.clear();
xVtr.push_back(point1.x());
yVtr.push_back(point1.y());
xVtr.push_back(point1.x() + 10);
double y1 = line1.slope * (point1.x() + 10) + line1.intercept;
yVtr.push_back(y1);
QCPGraph *lineGraph1 = _customPlot->addGraph();
lineGraph1->setData(xVtr, yVtr);
QPen pen;
pen.setColor(Qt::darkGreen);
lineGraph1->setPen(pen);
#endif
xVtr.clear();
yVtr.clear();
for(QPointF &p:point2Vtr){
xVtr.append(p.x());
yVtr.append(p.y());
}
PointCalculate::Line line2 = calculateLinearRegression(xVtr,yVtr);
#if 1
///line2
QVector<double> xVtr2,yVtr2;
xVtr2.push_back(point2.x());
yVtr2.push_back(point2.y());
xVtr2.push_back(point2.x() - 10);
double y2 = line2.slope * (point2.x() - 10) + line2.intercept;
yVtr2.push_back(y2);
QCPGraph *lineGraph2 = _customPlot->addGraph();
lineGraph2->setData(xVtr2, yVtr2);
lineGraph2->setPen(pen);
_customPlot->replot();
#endif
// inflection point.
QVector<QPointF> pointVtr = PointCalculate::getPointVtrInXRange(point1.x(),point2.x());
xVtr.clear();
yVtr.clear();
for(QPointF& p:pointVtr){
xVtr.append(p.x());
yVtr.append(p.y());
}
QMap<double, PointCalculate::Line> tangentLines =
PointCalculate::calculateTangentLine(xVtr,yVtr);
double targetX = 0.0;
PointCalculate::Line targetLine;
double maxSlopeAbs = 0.0; // 初始化最大斜率绝对值为0
for (auto it = tangentLines.begin(); it != tangentLines.end(); ++it) {
if (std::fabs(it.value().slope) > maxSlopeAbs) {
maxSlopeAbs = std::fabs(it.value().slope); // 更新最大斜率绝对值
targetX = it.key();
targetLine = it.value();
}
}
#if 1
QPointF intersection1 = PointCalculate::getIntersection(targetLine,line1);
QPointF intersection2 = PointCalculate::getIntersection(targetLine,line2);
// graph 3
xVtr.clear();
yVtr.clear();
#if 0
xVtr.push_back(point1.x());
yVtr.push_back(point1.y());
xVtr.push_back(point1.x());
yVtr.push_back(point1.y());
#endif
#if 1
xVtr.push_back(intersection1.x());
yVtr.push_back(intersection1.y());
xVtr.push_back(intersection2.x());
yVtr.push_back(intersection2.y());
#endif
QCPGraph *lineGraph3 = _customPlot->addGraph();
lineGraph3->setData(xVtr, yVtr);
lineGraph3->setPen(pen);
#endif
_customPlot->replot();
// point value
double averageY = (point1.y() + point2.y()) / 2;
QPointF averagePoint = PointCalculate::getClosestPointByY(point1.x(),point2.x(),averageY);
QString str = PointCalculate::textFormatGlassTranstion(intersection2.x(),
averagePoint.x(),
intersection1.x());
drawText(averagePoint,str);
}
// 使用最小二乘法计算线性回归
PointCalculate::Line CentralWidget::calculateLinearRegression(const QVector<double>& x, const QVector<double>& y) {
PointCalculate::Line line;
double sum_x = 0, sum_y = 0, sum_xy = 0, sum_xx = 0;
size_t n = x.size();
// 计算所需的总和
for (size_t i = 0; i < n; ++i) {
sum_x += x[i];
sum_y += y[i];
sum_xy += x[i] * y[i];
sum_xx += x[i] * x[i];
}
// 计算斜率和截距
double x_mean = sum_x / n;
double y_mean = sum_y / n;
double numerator = n * sum_xy - sum_x * sum_y;
double denominator = n * sum_xx - sum_x * sum_x;
line.slope = numerator / denominator;
line.intercept = y_mean - line.slope * x_mean;
return line;
}
// 二次多项式拟合函数
void CentralWidget::quadraticFit(const QVector<QPointF>& points, double& a, double& b, double& c) {
int n = points.size();
if (n < 3) {
throw std::invalid_argument("At least three points are required for quadratic fit.");
}
double sumX = 0, sumY = 0, sumXX = 0, sumXY = 0, sumX2Y = 0;
for (const QPointF& p : points) {
sumX += p.x();
sumY += p.y();
sumXX += p.x() * p.x();
sumXY += p.x() * p.y();
sumX2Y += p.x() * p.x() * p.y();
}
double det = n * (sumXX * sumY - sumX * sumXY) - sumX * sumX * sumY + sumX * sumX2Y;
a = (sumXX * sumY - sumX * sumXY) / det;
b = (sumX2Y - n * sumXY) / det;
c = (sumY - a * sumX - b * sumX) / n;
}
// 计算二次多项式拟合曲线的导数(切线斜率)
double CentralWidget::derivativeAt(const double a, const double b, const double x) {
return 2 * a * x + b;
}
void CentralWidget::setEventHandlerEnable(const bool flag)
{
logde<<"setEventHandlerEnable..."<<flag;
@ -632,7 +848,7 @@ void CentralWidget::clearData(const CentralWidget::ClearDataMode mode)
// Clear graph on plot.
for (int i = _customPlot->graphCount() - 1; i >= 0; --i) {
QCPGraph *graph = _customPlot->graph(i);
_customPlot->removeGraph(graph);
_customPlot->removeGraph(graph);
}
#endif

View File

@ -9,6 +9,7 @@
#include "global.h"
#include "eventhandler.h"
#include "filemanager.h"
#include "pointcalculate.h"
class CentralWidget:public QWidget
{
@ -51,6 +52,13 @@ protected:
void contextMenuEvent(QContextMenuEvent *event);
private:
void glassTransitionHandle();
void glassTransitionHandle2();
void quadraticFit(const QVector<QPointF>& points, double& a, double& b, double& c);
double derivativeAt(const double a, const double b, const double x);
PointCalculate::Line calculateLinearRegression(const QVector<double>& x, const QVector<double>& y);
void setEventHandlerEnable(const bool);
void drawText(const QPointF,const QString);
void fillGraph(const double x1,const double x2);