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);
|
||||
}
|
||||
}
|
||||
//
|
||||
// 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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user