新增道址计数谱实时读取数据,修改道址计数谱逻辑

This commit is contained in:
anxinglong 2026-06-12 18:43:51 +08:00
parent 9a8a102dcf
commit cad4ee2df7
6 changed files with 129 additions and 19 deletions

View File

@ -299,6 +299,11 @@ void CustomQwtPlot::AddCurve(QwtPlotCurve *curve, bool auto_color)
}
}
void CustomQwtPlot::clearCurve()
{
_curves.clear();
}
QwtPlotMarker *CustomQwtPlot::GetMarker(const QString &marker_name, const QString &postion)
{
return _markers.value(marker_name).value(postion);

View File

@ -72,6 +72,7 @@ public:
QwtPlotCurve* GetCurve(const QString& curve_name);
QList<QwtPlotCurve*> GetCurveList() const;
void AddCurve(QwtPlotCurve* curve, bool auto_color = true);
void clearCurve();
QwtPlotMarker* GetMarker(const QString& marker_name, const QString& postion);
QList<QwtPlotMarker*> GetMarkerList() const;

View File

@ -34,6 +34,8 @@
#include "MeasureAnalysisDataTableView.h"
#include "DataCalcProcess/GaussPolyCoe.h"
#include "EnergyScaleDataModel.h"
#include "ParticleCountPlotView.h"
#include <array>
#include "csv.h"
#include <fstream>
@ -100,6 +102,10 @@ MainWindow::MainWindow(QWidget* parent)
_status_bar = ui->statusbar;
_gvfToCsv = new GvfToCsv;
_measure_client = new MeasureClient;
m_AddressCountTimer = new QTimer(this);
m_AddressCountTimer->setInterval(10000);//10秒刷新一次
connect(m_AddressCountTimer, &QTimer::timeout, this, &MainWindow::on_AddressCountTimer);
connect(_measure_client, &MeasureClient::getDeviceListResult, this, &MainWindow::onGetDeviceListResult);
connect(_measure_client, &MeasureClient::startMeasureResult, this, &MainWindow::onStartMeasureResult);
connect(_measure_client, &MeasureClient::stopMeasureResult, this, &MainWindow::onStopMeasureResult);
@ -611,6 +617,8 @@ void MainWindow::onGvfData(const QByteArray &data)
changeParticleEnergyData(particles);
//处理能量计数
changeEnergyCountData(particles);
//处理道址计数谱
changeAddressCountView(particles);
}
//处理粒子数据
@ -704,7 +712,15 @@ void MainWindow::changeChannelParticleCount(QList<ParticleData> &data)
// 计算本次数据的增量计数
for (const auto &info : data) {
int channel_num = (info.boardId) * 4 + (info.channelId + 1);
deltaCounts[channel_num][info.address]++;
uint address = info.address;
// 道址范围校验(防止越界)
if (address >= 4096) {
LOG_WARN(QStringLiteral(u"道址%1超出最大范围%2已跳过").arg(address).arg(4096));
continue;
}
deltaCounts[channel_num][address]++;
totalParticles++;
}
@ -739,6 +755,22 @@ void MainWindow::changeChannelParticleCount(QList<ParticleData> &data)
uint channel_num = channelIt.key();
const auto& addressDeltas = channelIt.value();
// 关键优化如果是新通道初始化4096个道址为0
if (!channel_address_counts.contains(channel_num)) {
std::array<unsigned long long, 4096> initCounts;
initCounts.fill(0); // 所有道址初始化为0
channel_address_counts.insert(channel_num, initCounts);
}
// 更新内存中的总计数
auto& channelCounts = channel_address_counts[channel_num];
for (auto addressIt = addressDeltas.constBegin(); addressIt != addressDeltas.constEnd(); ++addressIt) {
uint address = addressIt.key();
unsigned long long delta = addressIt.value();
channelCounts[address] += delta;
}
// 获取或创建通道文件名
QString count_data_filename;
if (particle_count_filename_list.contains(channel_num)) {
count_data_filename = particle_count_filename_list[channel_num];
@ -749,12 +781,7 @@ void MainWindow::changeChannelParticleCount(QList<ParticleData> &data)
newChannelFiles.insert(channel_num, count_data_filename);
}
for (auto addressIt = addressDeltas.constBegin(); addressIt != addressDeltas.constEnd(); ++addressIt) {
uint address = addressIt.key();
unsigned long long delta = addressIt.value();
channel_address_counts[channel_num][address] += delta;
}
// 重写整个CSV文件Truncate模式
QFile outFile(count_data_filename);
if (!outFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
LOG_ERROR(QStringLiteral(u"无法打开通道%1的计数文件: %2错误: %3")
@ -771,16 +798,12 @@ void MainWindow::changeChannelParticleCount(QList<ParticleData> &data)
// 写入表头
out << QStringLiteral(u"道址,计数\n");
// 写入所有道址的最新总计数(按道址排序)
// 关键修改写入完整的0-4095道址数据
QString csvBuffer;
csvBuffer.reserve(channel_address_counts[channel_num].size() * 32); // 预分配内存
csvBuffer.reserve(4096 * 32); // 预分配足够内存约128KB
// 获取排序后的道址列表
QList<uint> sortedAddresses = channel_address_counts[channel_num].keys();
std::sort(sortedAddresses.begin(), sortedAddresses.end());
for (uint address : sortedAddresses) {
unsigned long long total = channel_address_counts[channel_num][address];
for (int address = 0; address < 4096; ++address) {
unsigned long long total = channelCounts[address];
csvBuffer += QString("%1,%2\n").arg(address).arg(total);
}
@ -932,7 +955,60 @@ void MainWindow::changeEnergyCountData(QList<ParticleData> &dataList)
{
}
//处理道址计数谱
void MainWindow::changeAddressCountView(QList<ParticleData> &dataList)
{
if (dataList.isEmpty()) {
return;
}
MeasureAnalysisProjectModel* pro_model = ProjectList::Instance()->GetCurrentProjectModel();
if (!pro_model) {
LOG_ERROR(QStringLiteral(u"当前没有打开的测量项目,无法处理能谱数据"));
return;
}
bool status_ok = !pro_model->GetChannelAddressCountDataFilenameList().isEmpty();
QString status = status_ok ? QStringLiteral(u"有效") : QStringLiteral(u"无效");
QString item_name = QStringLiteral(u"道址计数谱");
QStandardItem * particleData = nodeMap[item_name];
//获取道址计数谱状态
bool bStatus = ProjectList::Instance()->GetNodeStatus(particleData);
if(!bStatus)
{
ProjectList::Instance()->SetNodeStatus(particleData,status,true);
m_AddressCountTimer->start();
}
}
void MainWindow::on_AddressCountTimer()
{
QMap<QString, QVariant> data_files_set;
//获取道址计数谱
auto dockList = _dock_manager->dockWidgetsMap().values();
for(auto dock : dockList)
{
ParticleCountPlotView* view = dynamic_cast<ParticleCountPlotView*>(dock->widget());
if(!view) continue;
if(view->GetAnalyzeType() == AnalysisType::AddressCountSpectrumView)
{
MeasureAnalysisProjectModel* project_model = ProjectList::Instance()->GetCurrentProjectModel();
if (project_model) {
auto file_name_list = project_model->GetChannelAddressCountDataFilenameList();
if ( !file_name_list.isEmpty() ) {
auto ch_num_list = file_name_list.keys();
for(auto ch_num : ch_num_list) {
auto file_name = file_name_list[ch_num];
if ( !file_name.isEmpty() ) {
data_files_set[QStringLiteral(u"通道%1").arg(ch_num)] = file_name;
}
}
}
}
view->updateView(data_files_set);
}
}
}
void MainWindow::on_action_stop_measure_triggered()
{
@ -942,5 +1018,5 @@ void MainWindow::on_action_stop_measure_triggered()
return;
}
_measure_client->stopMeasure(device_guid);
m_AddressCountTimer->stop();
}

View File

@ -5,6 +5,7 @@
#include <QMutex>
#include "GvfToCsv/GvfToCsv.h"
#include "MeasureAnalysisProjectModel.h"
#include <QTimer>
QT_BEGIN_NAMESPACE
namespace Ui {
@ -65,7 +66,8 @@ private:
void changeParticleEnergyData(QList<ParticleData> &dataList);
//处理能量计数
void changeEnergyCountData(QList<ParticleData> &dataList);
//处理道址计数谱
void changeAddressCountView(QList<ParticleData> &dataList);
signals:
void newProject(const QString &project_name);
@ -93,7 +95,7 @@ private slots:
void on_action_stop_measure_triggered();
void on_AddressCountTimer();
private:
QMutex _mutex_info_output;
QPlainTextEdit* _plain_edit_info_output;
@ -115,7 +117,7 @@ private:
GvfToCsv *_gvfToCsv = nullptr;
QMap<uint, QMap<uint, unsigned long long>> channel_address_counts; // 通道号 -> 地址 -> 计数
QHash<uint, std::array<unsigned long long, 4096>> channel_address_counts; // 改为数组
QMap<uint, QString> particle_count_filename_list;
//2026-06-11
QMap<QString, QStandardItem *> nodeMap;
@ -128,5 +130,8 @@ private:
QMap<double, unsigned long long> m_allChannelEnergyStats; // 全通道能量bin -> 计数
QMutex m_energyCountMutex; // 保护能量计数数据的互斥锁
QHash<QString, std::vector<double>> m_energyScaleCoeffCache;// 能量刻度系数缓存
//道址计数视图定时器
QTimer* m_AddressCountTimer;
};
#endif // MAINWINDOW_H

View File

@ -116,6 +116,27 @@ void ParticleCountPlotView::SetAnalyzeDataFilename(const QMap<QString, QVariant>
}
}
void ParticleCountPlotView::updateView(const QMap<QString, QVariant>& data_files_set)
{
// 清除现有所有曲线
for (QwtPlotCurve* curve : this->_plot->GetCurveList()) {
curve->detach();
delete curve;
}
_plot->clearCurve();
// 重新加载数据
if (!data_files_set.isEmpty()) {
SetAnalyzeDataFilename(data_files_set);
}
// 清除标记并重绘
this->_plot->CleanMarkers();
this->_plot->CleanZoneItems();
this->_plot->ResetPlot();
this->_plot->replot();
}
void ParticleCountPlotView::setupMenu()
{
this->setContextMenuPolicy(Qt::CustomContextMenu);

View File

@ -25,6 +25,8 @@ public:
virtual void InitViewWorkspace(const QString& project_name) override final;
virtual void SetAnalyzeDataFilename(const QMap<QString, QVariant>& data_files_set);
void updateView(const QMap<QString, QVariant>& data_files_set);
private:
void setupMenu();
void setupPlot();