优化获取测量数据文件接口
This commit is contained in:
commit
d5caa22930
248
src/2DSpectralCompliance/TwoDSpectralCompliance.cpp
Normal file
248
src/2DSpectralCompliance/TwoDSpectralCompliance.cpp
Normal file
|
|
@ -0,0 +1,248 @@
|
|||
#include "TwoDSpectralCompliance.h"
|
||||
#include "ui_TwoDSpectralCompliance.h"
|
||||
#include "CustomQwtPlot.h"
|
||||
#include <QwtPlotCanvas>
|
||||
#include <QwtText>
|
||||
#include <QwtLegend>
|
||||
#include <QwtPlotSpectrogram>
|
||||
#include <QwtLinearColorMap>
|
||||
#include <QwtMatrixRasterData>
|
||||
#include <QHBoxLayout>
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
#include <QDebug>
|
||||
#include <cmath>
|
||||
#include <QwtInterval>
|
||||
#include <qwt_matrix_raster_data.h>
|
||||
#include <algorithm>
|
||||
|
||||
// 自定义颜色映射(热力图)
|
||||
class HeatMapColorMap : public QwtLinearColorMap
|
||||
{
|
||||
public:
|
||||
HeatMapColorMap() : QwtLinearColorMap(Qt::white, Qt::red)
|
||||
{
|
||||
addColorStop(0.25, Qt::blue);
|
||||
addColorStop(0.5, Qt::green);
|
||||
addColorStop(0.75, Qt::yellow);
|
||||
}
|
||||
};
|
||||
|
||||
TwoDSpectralCompliance::TwoDSpectralCompliance(QWidget *parent) :
|
||||
MeasureAnalysisView(parent),
|
||||
ui(new Ui::TwoDSpectralCompliance)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QHBoxLayout* layout = new QHBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
this->_plot = new CustomQwtPlot(this);
|
||||
layout->addWidget(this->_plot);
|
||||
setupPlot();
|
||||
}
|
||||
|
||||
TwoDSpectralCompliance::~TwoDSpectralCompliance()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void TwoDSpectralCompliance::InitViewWorkspace(const QString &project_name)
|
||||
{
|
||||
// 可预留用于项目初始化
|
||||
Q_UNUSED(project_name);
|
||||
}
|
||||
|
||||
void TwoDSpectralCompliance::SetAnalyzeDataFilename(const QMap<QString, QVariant> &data_files_set)
|
||||
{
|
||||
if (data_files_set.isEmpty())
|
||||
return;
|
||||
|
||||
// 约定:data_files_set 的 key 为符合次数(如 "2", "3"...),value 为 CSV 文件路径
|
||||
// 我们只处理第一个文件(通常只有一个)
|
||||
QString csvFile = data_files_set.first().toString();
|
||||
if (csvFile.isEmpty())
|
||||
return;
|
||||
|
||||
readCsv(csvFile);
|
||||
generateSurfaceData();
|
||||
updateSpectrogram();
|
||||
}
|
||||
|
||||
void TwoDSpectralCompliance::setupPlot()
|
||||
{
|
||||
_plot->setCanvasBackground(Qt::white);
|
||||
QwtPlotCanvas* canvas = qobject_cast<QwtPlotCanvas*>(_plot->canvas());
|
||||
if (canvas)
|
||||
canvas->setFrameStyle(QFrame::NoFrame);
|
||||
|
||||
QFont font = this->font();
|
||||
font.setBold(false);
|
||||
QwtText energy_label = QStringLiteral(u"次级粒子能量和 (keV)");
|
||||
energy_label.setFont(font);
|
||||
QwtText count_label = QStringLiteral(u"初级粒子能量 (keV)");
|
||||
count_label.setFont(font);
|
||||
_plot->setAxisTitle(QwtPlot::xBottom, energy_label);
|
||||
_plot->setAxisTitle(QwtPlot::yLeft, count_label);
|
||||
|
||||
// 自动缩放
|
||||
_plot->setAxisAutoScale(QwtPlot::xBottom, true);
|
||||
_plot->setAxisAutoScale(QwtPlot::yLeft, true);
|
||||
|
||||
_plot->enableAxis(QwtPlot::xBottom);
|
||||
_plot->enableAxis(QwtPlot::yLeft);
|
||||
|
||||
// 图例
|
||||
QwtLegend* legend = new QwtLegend();
|
||||
legend->setDefaultItemMode(QwtLegendData::ReadOnly);
|
||||
_plot->insertLegend(legend, QwtPlot::RightLegend);
|
||||
|
||||
// 启用拖拽缩放
|
||||
_plot->SetAxisDragScale(QwtPlot::xBottom, true);
|
||||
_plot->SetAxisDragScale(QwtPlot::yLeft, true);
|
||||
|
||||
// 创建 spectrogram
|
||||
_spectrogram = new QwtPlotSpectrogram();
|
||||
_spectrogram->setColorMap(new HeatMapColorMap());
|
||||
_spectrogram->attach(_plot);
|
||||
|
||||
_plot->setAutoFillBackground(true);
|
||||
QPalette pal = _plot->palette();
|
||||
pal.setColor(QPalette::Window, Qt::white);
|
||||
_plot->setPalette(pal);
|
||||
}
|
||||
|
||||
void TwoDSpectralCompliance::readCsv(const QString &filename)
|
||||
{
|
||||
m_rawData.clear();
|
||||
QFile file(filename);
|
||||
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
qWarning() << "无法打开文件:" << filename;
|
||||
return;
|
||||
}
|
||||
|
||||
QTextStream stream(&file);
|
||||
QString header = stream.readLine(); // 跳过标题行
|
||||
Q_UNUSED(header);
|
||||
|
||||
while (!stream.atEnd()) {
|
||||
QString line = stream.readLine();
|
||||
if (line.isEmpty())
|
||||
continue;
|
||||
|
||||
QStringList fields = line.split(',');
|
||||
if (fields.size() < 5)
|
||||
continue;
|
||||
|
||||
EventData data;
|
||||
data.eventId = fields[0].toInt();
|
||||
data.board = fields[1].toInt();
|
||||
data.channel = fields[2].toInt();
|
||||
data.energy = fields[3].toDouble();
|
||||
data.timeCounter = fields[4].toULongLong();
|
||||
m_rawData.append(data);
|
||||
}
|
||||
file.close();
|
||||
qDebug() << "读取了" << m_rawData.size() << "条事件记录";
|
||||
}
|
||||
|
||||
void TwoDSpectralCompliance::generateSurfaceData()
|
||||
{
|
||||
m_surfaceData.clear();
|
||||
if (m_rawData.isEmpty())
|
||||
return;
|
||||
|
||||
// 按事件ID分组,每个事件中第一个粒子为初级,其余为次级
|
||||
QMap<int, QVector<EventData>> eventMap;
|
||||
for (const auto& ev : m_rawData) {
|
||||
eventMap[ev.eventId].append(ev);
|
||||
}
|
||||
|
||||
// 使用 QMap 来累加相同坐标的计数(初级能量,次级能量和)
|
||||
QMap<QPair<float, float>, int> countMap;
|
||||
|
||||
for (auto it = eventMap.begin(); it != eventMap.end(); ++it) {
|
||||
const auto& events = it.value();
|
||||
if (events.isEmpty())
|
||||
continue;
|
||||
|
||||
// 第一个事件作为初级粒子
|
||||
float primaryEnergy = events[0].energy;
|
||||
float secondarySum = 0.0f;
|
||||
for (int i = 1; i < events.size(); ++i) {
|
||||
secondarySum += events[i].energy;
|
||||
}
|
||||
|
||||
auto key = qMakePair(primaryEnergy, secondarySum);
|
||||
countMap[key]++;
|
||||
}
|
||||
|
||||
// 转换为 SurfacePoint 列表
|
||||
for (auto it = countMap.begin(); it != countMap.end(); ++it) {
|
||||
TwoSurfacePoint point;
|
||||
point.primaryEnergy = it.key().first;
|
||||
point.secondaryEnergySum = it.key().second;
|
||||
point.count = it.value();
|
||||
m_surfaceData.append(point);
|
||||
}
|
||||
|
||||
qDebug() << "生成了" << m_surfaceData.size() << "个唯一坐标点";
|
||||
}
|
||||
|
||||
void TwoDSpectralCompliance::updateSpectrogram()
|
||||
{
|
||||
if (m_surfaceData.isEmpty()) {
|
||||
_spectrogram->setData(new QwtMatrixRasterData());
|
||||
_plot->replot();
|
||||
return;
|
||||
}
|
||||
|
||||
// 找出能量范围
|
||||
float minPrim = 1e9f, maxPrim = -1e9f;
|
||||
float minSec = 1e9f, maxSec = -1e9f;
|
||||
int maxCount = 0;
|
||||
|
||||
for (const auto& pt : m_surfaceData) {
|
||||
minPrim = std::min(minPrim, pt.primaryEnergy);
|
||||
maxPrim = std::max(maxPrim, pt.primaryEnergy);
|
||||
minSec = std::min(minSec, pt.secondaryEnergySum);
|
||||
maxSec = std::max(maxSec, pt.secondaryEnergySum);
|
||||
maxCount = std::max(maxCount, pt.count);
|
||||
}
|
||||
|
||||
// 增加边界
|
||||
double primRange = maxPrim - minPrim;
|
||||
double secRange = maxSec - minSec;
|
||||
if (primRange < 1e-6) primRange = 1.0;
|
||||
if (secRange < 1e-6) secRange = 1.0;
|
||||
double primStart = minPrim - primRange * 0.05;
|
||||
double primEnd = maxPrim + primRange * 0.05;
|
||||
double secStart = minSec - secRange * 0.05;
|
||||
double secEnd = maxSec + secRange * 0.05;
|
||||
|
||||
// 使用不同名称,避免宏冲突
|
||||
const int numCols = 200; // X轴方向点数(初级能量)
|
||||
const int numRows = 200; // Y轴方向点数(次级能量)
|
||||
|
||||
double stepX = (primEnd - primStart) / numCols;
|
||||
double stepY = (secEnd - secStart) / numRows;
|
||||
|
||||
QVector<double> zValues(numRows * numCols, 0.0);
|
||||
|
||||
for (const auto& pt : m_surfaceData) {
|
||||
int col = static_cast<int>((pt.primaryEnergy - primStart) / stepX);
|
||||
int row = static_cast<int>((pt.secondaryEnergySum - secStart) / stepY);
|
||||
col = qBound(0, col, numCols - 1);
|
||||
row = qBound(0, row, numRows - 1);
|
||||
zValues[row * numCols + col] += pt.count;
|
||||
}
|
||||
|
||||
QwtMatrixRasterData* data = new QwtMatrixRasterData();
|
||||
data->setInterval(Qt::XAxis, QwtInterval(primStart, primEnd));
|
||||
data->setInterval(Qt::YAxis, QwtInterval(secStart, secEnd));
|
||||
data->setInterval(Qt::ZAxis, QwtInterval(0, maxCount));
|
||||
data->setValueMatrix(zValues, numCols);
|
||||
|
||||
_spectrogram->setData(data);
|
||||
_plot->setAxisScale(QwtPlot::xBottom, primStart, primEnd);
|
||||
_plot->setAxisScale(QwtPlot::yLeft, secStart, secEnd);
|
||||
_plot->replot();
|
||||
}
|
||||
56
src/2DSpectralCompliance/TwoDSpectralCompliance.h
Normal file
56
src/2DSpectralCompliance/TwoDSpectralCompliance.h
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
#ifndef TWODSPECTRALCOMPLIANCE_H
|
||||
#define TWODSPECTRALCOMPLIANCE_H
|
||||
|
||||
#include <QWidget>
|
||||
#include <MeasureAnalysisView.h>
|
||||
#include <QVector>
|
||||
|
||||
class CustomQwtPlot;
|
||||
class QwtPlotSpectrogram;
|
||||
|
||||
namespace Ui {
|
||||
class TwoDSpectralCompliance;
|
||||
}
|
||||
|
||||
//// 用于存储三维数据点(初级能量,次级能量和,计数)
|
||||
struct TwoSurfacePoint {
|
||||
float primaryEnergy;
|
||||
float secondaryEnergySum;
|
||||
int count;
|
||||
};
|
||||
|
||||
class TwoDSpectralCompliance : public MeasureAnalysisView
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit TwoDSpectralCompliance(QWidget *parent = nullptr);
|
||||
~TwoDSpectralCompliance();
|
||||
|
||||
virtual void InitViewWorkspace(const QString& project_name) override final;
|
||||
virtual void SetAnalyzeDataFilename(const QMap<QString, QVariant>& data_files_set) override;
|
||||
|
||||
private:
|
||||
void setupPlot();
|
||||
void readCsv(const QString& filename);
|
||||
void generateSurfaceData();
|
||||
void updateSpectrogram();
|
||||
|
||||
private:
|
||||
Ui::TwoDSpectralCompliance *ui;
|
||||
CustomQwtPlot* _plot = nullptr;
|
||||
QwtPlotSpectrogram* _spectrogram = nullptr;
|
||||
|
||||
// 原始数据
|
||||
struct EventData {
|
||||
int eventId;
|
||||
int board;
|
||||
int channel;
|
||||
double energy;
|
||||
unsigned long long timeCounter;
|
||||
};
|
||||
QVector<EventData> m_rawData; // 从 CSV 读取的原始数据
|
||||
QVector<TwoSurfacePoint> m_surfaceData; // 生成的曲面点(每个事件一个点,计数累加)
|
||||
};
|
||||
|
||||
#endif // TWODSPECTRALCOMPLIANCE_H
|
||||
21
src/2DSpectralCompliance/TwoDSpectralCompliance.ui
Normal file
21
src/2DSpectralCompliance/TwoDSpectralCompliance.ui
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
<ui version="4.0">
|
||||
<author/>
|
||||
<comment/>
|
||||
<exportmacro/>
|
||||
<class>TwoDSpectralCompliance</class>
|
||||
<widget name="TwoDSpectralCompliance" class="QWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>400</width>
|
||||
<height>300</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
</widget>
|
||||
<pixmapfunction/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
@ -251,6 +251,15 @@ void MeasureAnalysisTreeView::onNodeDoubleClicked(const QModelIndex& index)
|
|||
}
|
||||
}
|
||||
} break;
|
||||
case AnalysisType::CoincidenceParticleEnergySpectrum2DView: {
|
||||
MeasureAnalysisProjectModel* project_model = _model->GetProjectModel(project_name);
|
||||
if (project_model) {
|
||||
auto file_name_list = project_model->GetTimeWinConformEnergyDataFilenameList(project_model->GetConformTimeWin());
|
||||
for (auto it = file_name_list.constBegin(); it!=file_name_list.constEnd(); ++it) {
|
||||
data_files_set[QString::number(it.key())] = it.value();
|
||||
}
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include "ParticleCountPlotView.h"
|
||||
#include "ParticleInjectTimeAnalysisView.h"
|
||||
#include "ParticleTimeDifferenceView.h"
|
||||
#include "TwoDSpectralCompliance.h"
|
||||
#include <QMap>
|
||||
|
||||
MeasureAnalysisView* MeasureAnalysisView::NewAnalyzeView(AnalysisType view_type)
|
||||
|
|
@ -63,8 +64,8 @@ MeasureAnalysisView* MeasureAnalysisView::NewAnalyzeView(AnalysisType view_type)
|
|||
new_view->setDeleteOnClose(false);
|
||||
} break;
|
||||
case AnalysisType::CoincidenceParticleEnergySpectrum2DView: {
|
||||
// new_view = new MeasureAnalysisDataTableView;
|
||||
// new_view->setDeleteOnClose(false);
|
||||
new_view = new TwoDSpectralCompliance;
|
||||
new_view->setDeleteOnClose(false);
|
||||
} break;
|
||||
case AnalysisType::CoincidenceParticleEnergySpectrum3DView: {
|
||||
new_view = new ConformityAnalysis;
|
||||
|
|
|
|||
|
|
@ -81,7 +81,13 @@ void MeasureClient::processCommand(const QString &command, const QString &device
|
|||
QString message = response["message"].toString();
|
||||
|
||||
if (command == "START") {
|
||||
QString gvf_filename;
|
||||
if (success) {
|
||||
gvf_filename = response["devices"].toString();
|
||||
emit startMeasureResult(success, gvf_filename);
|
||||
} else {
|
||||
emit startMeasureResult(success, message);
|
||||
}
|
||||
} else if (command == "STOP") {
|
||||
emit stopMeasureResult(success, message);
|
||||
} else if (command == "SET") {
|
||||
|
|
@ -161,6 +167,13 @@ QVariantMap MeasureClient::sendCommand(const QString &command, const QString &de
|
|||
}
|
||||
result["devices"] = devices;
|
||||
}
|
||||
} else if ((response_command == "START") && success) {
|
||||
// 处理设备列表响应
|
||||
if (success) {
|
||||
QString measure_gvf_data_filename;
|
||||
response_stream >> measure_gvf_data_filename;
|
||||
result["gvf"] = measure_gvf_data_filename;
|
||||
}
|
||||
} else {
|
||||
// 处理其他响应
|
||||
QString message;
|
||||
|
|
|
|||
11
src/src.pro
11
src/src.pro
|
|
@ -35,8 +35,8 @@ INCLUDEPATH += \
|
|||
$${PWD}/ParticleTimeDifferenceView \
|
||||
$${PWD}/MeasureAnalysisHistoryForm \
|
||||
$${PWD}/MeasureDeviceParamsConfigView \
|
||||
$${PWD}/DeviceParameterConfig
|
||||
|
||||
$${PWD}/DeviceParameterConfig \
|
||||
$${PWD}/2DSpectralCompliance
|
||||
|
||||
DEPENDPATH += \
|
||||
$${PWD}/BusyIndicator \
|
||||
|
|
@ -51,10 +51,13 @@ DEPENDPATH += \
|
|||
$${PWD}/ParticleTimeDifferenceView \
|
||||
$${PWD}/MeasureAnalysisHistoryForm \
|
||||
$${PWD}/MeasureDeviceParamsConfigView \
|
||||
$${PWD}/DeviceParameterConfig
|
||||
$${PWD}/DeviceParameterConfig \
|
||||
$${PWD}/2DSpectralCompliance
|
||||
|
||||
|
||||
|
||||
SOURCES += \
|
||||
2DSpectralCompliance/TwoDSpectralCompliance.cpp \
|
||||
AboutDlg.cpp \
|
||||
BusyIndicator/BusyIndicator.cpp \
|
||||
CountRateAnalysisView/CountRateAnalysisView.cpp \
|
||||
|
|
@ -95,6 +98,7 @@ SOURCES += \
|
|||
main.cpp
|
||||
|
||||
HEADERS += \
|
||||
2DSpectralCompliance/TwoDSpectralCompliance.h \
|
||||
AboutDlg.h \
|
||||
AnalysisTypeDefine.h \
|
||||
BusyIndicator/BusyIndicator.h \
|
||||
|
|
@ -139,6 +143,7 @@ HEADERS += \
|
|||
|
||||
|
||||
FORMS += \
|
||||
2DSpectralCompliance/TwoDSpectralCompliance.ui \
|
||||
AboutDlg.ui \
|
||||
CountRateAnalysisView/CountRateAnalysisView.ui \
|
||||
EnergyScaleForm.ui \
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user