2025-04-21T17:31:37
This commit is contained in:
parent
1e2a73bd02
commit
a00031c009
Binary file not shown.
BIN
experiment_data/analysis_state/玻璃化转变.xlsx
Normal file
BIN
experiment_data/analysis_state/玻璃化转变.xlsx
Normal file
Binary file not shown.
@ -363,7 +363,7 @@ QPair<float,float> PointCalculate::getCurveInflectionPointTangent(const float x1
|
|||||||
dataVtr.push_back(ed.sampleTemp);
|
dataVtr.push_back(ed.sampleTemp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
// 5
|
||||||
std::vector<float> processedVtr = movingAverage(dataVtr,5);
|
std::vector<float> processedVtr = movingAverage(dataVtr,5);
|
||||||
|
|
||||||
// find max slope.
|
// find max slope.
|
||||||
@ -387,7 +387,7 @@ QPair<float,float> PointCalculate::getCurveInflectionPointTangent(const float x1
|
|||||||
|
|
||||||
return qMakePair<float,float>(maxSlope,b);
|
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 x = (line2.intercept - line1.intercept) / (line1.slope - line2.slope);
|
||||||
float y = line1.slope * x + line1.intercept;
|
float y = line1.slope * x + line1.intercept;
|
||||||
// return {x, y};
|
// return {x, y};
|
||||||
@ -541,3 +541,81 @@ QVector<Global::ExperimentData> PointCalculate::getDataInXRange(const float x1,
|
|||||||
|
|
||||||
return targetVtr;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@ -10,9 +10,13 @@ void setExperimentData(const QVector<Global::ExperimentData>&);
|
|||||||
|
|
||||||
QPair<QPointF,QPointF> getStartAndEndPoint();
|
QPair<QPointF,QPointF> getStartAndEndPoint();
|
||||||
QVector<Global::ExperimentData> getDataInXRange(const float, const float);
|
QVector<Global::ExperimentData> getDataInXRange(const float, const float);
|
||||||
|
QVector<QPointF> getPointVtrInXRange(const float, const float);
|
||||||
|
|
||||||
void setRegionPointX(const float,const float);
|
void setRegionPointX(const float,const float);
|
||||||
|
|
||||||
QPointF getClosestPointByX(const float);
|
QPointF getClosestPointByX(const float);
|
||||||
|
QVector<QPointF> getNearbyPointGroupByX(const float);
|
||||||
|
|
||||||
QPointF getClosestPointByY(const float left,const float right,const float valueY);
|
QPointF getClosestPointByY(const float left,const float right,const float valueY);
|
||||||
QPointF getPeakPoint();
|
QPointF getPeakPoint();
|
||||||
QPair<float, float> getMaxMinValue();
|
QPair<float, float> getMaxMinValue();
|
||||||
@ -32,11 +36,14 @@ QString textFormatGlassTranstion(const float t1,const float tg,const float t2);
|
|||||||
|
|
||||||
// glass transition
|
// glass transition
|
||||||
QPair<float,float> getCurveInflectionPointTangent(const float,const float);
|
QPair<float,float> getCurveInflectionPointTangent(const float,const float);
|
||||||
struct LineStruct {
|
struct Line {
|
||||||
float slope; //
|
double slope; //
|
||||||
float intercept; //
|
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
|
//private
|
||||||
void updateStartEndPoint();
|
void updateStartEndPoint();
|
||||||
|
|||||||
@ -352,7 +352,8 @@ void CentralWidget::slotAnalysisSettingApply()
|
|||||||
}
|
}
|
||||||
case AnalysisMode::GlassTransition:
|
case AnalysisMode::GlassTransition:
|
||||||
{
|
{
|
||||||
glassTransitionHandle();
|
// glassTransitionHandle();
|
||||||
|
glassTransitionHandle2();
|
||||||
//
|
//
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -452,7 +453,7 @@ void CentralWidget::glassTransitionHandle()
|
|||||||
_customPlot->replot();
|
_customPlot->replot();
|
||||||
#endif
|
#endif
|
||||||
//
|
//
|
||||||
PointCalculate::LineStruct lineStrc1,lineStrc2,tangetLineStrc;
|
PointCalculate::Line lineStrc1,lineStrc2,tangetLineStrc;
|
||||||
|
|
||||||
lineStrc1.slope = 0.0;
|
lineStrc1.slope = 0.0;
|
||||||
lineStrc1.intercept = point1.y();
|
lineStrc1.intercept = point1.y();
|
||||||
@ -464,8 +465,8 @@ void CentralWidget::glassTransitionHandle()
|
|||||||
tangetLineStrc.slope = tangentLinePair.first;
|
tangetLineStrc.slope = tangentLinePair.first;
|
||||||
tangetLineStrc.intercept = tangentLinePair.second;
|
tangetLineStrc.intercept = tangentLinePair.second;
|
||||||
|
|
||||||
QPointF intersection1 = PointCalculate::getIntersectionBySlope(tangetLineStrc,lineStrc1);
|
QPointF intersection1 = PointCalculate::getIntersection(tangetLineStrc,lineStrc1);
|
||||||
QPointF intersection2 = PointCalculate::getIntersectionBySlope(tangetLineStrc,lineStrc2);
|
QPointF intersection2 = PointCalculate::getIntersection(tangetLineStrc,lineStrc2);
|
||||||
|
|
||||||
// logde<<"intersection1 x:"<<intersection1.x();
|
// logde<<"intersection1 x:"<<intersection1.x();
|
||||||
// logde<<"intersection2 x:"<<intersection2.x();
|
// logde<<"intersection2 x:"<<intersection2.x();
|
||||||
@ -487,8 +488,37 @@ void CentralWidget::glassTransitionHandle()
|
|||||||
QString str = PointCalculate::textFormatGlassTranstion(intersection2.x(),
|
QString str = PointCalculate::textFormatGlassTranstion(intersection2.x(),
|
||||||
averagePoint.x(),
|
averagePoint.x(),
|
||||||
intersection1.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);
|
drawText(averagePoint,str);
|
||||||
|
|
||||||
|
_customPlot->replot();
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// 创建一个圆形绘图项
|
// 创建一个圆形绘图项
|
||||||
QCPItemEllipse *circle = new QCPItemEllipse(_customPlot);
|
QCPItemEllipse *circle = new QCPItemEllipse(_customPlot);
|
||||||
@ -515,6 +545,192 @@ void CentralWidget::glassTransitionHandle()
|
|||||||
#endif
|
#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)
|
void CentralWidget::setEventHandlerEnable(const bool flag)
|
||||||
{
|
{
|
||||||
logde<<"setEventHandlerEnable..."<<flag;
|
logde<<"setEventHandlerEnable..."<<flag;
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
#include "global.h"
|
#include "global.h"
|
||||||
#include "eventhandler.h"
|
#include "eventhandler.h"
|
||||||
#include "filemanager.h"
|
#include "filemanager.h"
|
||||||
|
#include "pointcalculate.h"
|
||||||
|
|
||||||
class CentralWidget:public QWidget
|
class CentralWidget:public QWidget
|
||||||
{
|
{
|
||||||
@ -51,6 +52,13 @@ protected:
|
|||||||
void contextMenuEvent(QContextMenuEvent *event);
|
void contextMenuEvent(QContextMenuEvent *event);
|
||||||
private:
|
private:
|
||||||
void glassTransitionHandle();
|
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 setEventHandlerEnable(const bool);
|
||||||
void drawText(const QPointF,const QString);
|
void drawText(const QPointF,const QString);
|
||||||
void fillGraph(const double x1,const double x2);
|
void fillGraph(const double x1,const double x2);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user