读取开始测量时间,编写生成死时间活时间实时间实现,修改生成报告内容
This commit is contained in:
parent
e83492e7a9
commit
f3eb0cbf59
|
|
@ -1,9 +1,12 @@
|
|||
#include "GvfToCsv.h"
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QTextStream>
|
||||
#include <QEventLoop>
|
||||
#include <QTimer>
|
||||
#include <QDir>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include "GlobalDefine.h"
|
||||
GvfToCsv::GvfToCsv(QObject *parent)
|
||||
: QObject(parent)
|
||||
|
|
@ -234,6 +237,9 @@ void GvfToCsv::processDBData()
|
|||
throw std::runtime_error("GVF数据库中无任何记录");
|
||||
return;
|
||||
}
|
||||
|
||||
// 从lmstatisticinfov2读取软件记录的测量启动时间,精度最高
|
||||
QString measureStartAbsTime = m_sqliteWorker->getMeasureStartTime();
|
||||
QFile outFile(m_csvPath);
|
||||
if (!outFile.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
|
||||
throw std::runtime_error(QString("无法创建CSV文件: %1,错误: %2")
|
||||
|
|
@ -250,6 +256,9 @@ void GvfToCsv::processDBData()
|
|||
csvBuffer.reserve(4 * 1024 * 1024); // 4MB缓冲区
|
||||
|
||||
quint64 totalParticles = 0;
|
||||
quint64 totalIcrSum = 0; // 所有粒子ICR输入触发总计数 Cicr
|
||||
quint64 tsMin = ULLONG_MAX; // 全部粒子最小时间戳计数(用于计算总时长)
|
||||
quint64 tsMax = 0; // 全部粒子最大时间戳计数
|
||||
int emptyFrameCount = 0;
|
||||
int processedFrames = 0;
|
||||
const int totalFrames = dbList.size();
|
||||
|
|
@ -260,13 +269,18 @@ void GvfToCsv::processDBData()
|
|||
emptyFrameCount++;
|
||||
} else {
|
||||
totalParticles += particles.size();
|
||||
|
||||
for (const auto &p : particles) {
|
||||
csvBuffer += QString("%1,%2,%3,%4\n")
|
||||
.arg(p.boardId)
|
||||
.arg(p.channelId)
|
||||
.arg(p.address)
|
||||
.arg(p.timestampCount);
|
||||
//硬件输入触发ICR总和累加
|
||||
totalIcrSum += p.icr;
|
||||
//更新全局最小时间戳
|
||||
if(p.timestampCount < tsMin) tsMin = p.timestampCount;
|
||||
//更新全局最大时间戳
|
||||
if(p.timestampCount > tsMax) tsMax = p.timestampCount;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -287,6 +301,54 @@ void GvfToCsv::processDBData()
|
|||
out << csvBuffer;
|
||||
}
|
||||
|
||||
double realTime = 0.0; // 实时间RealTime Tr:物理测量总时长(单位s)
|
||||
double liveTime = 0.0; // 活时间LiveTime Tl:探测器有效采集时长(单位s)
|
||||
double deadTime = 0.0; // 死时间DeadTime Td:硬件阻塞无法采集时长(单位s)
|
||||
// 存在有效粒子且时间戳有差值,才具备计算时间的条件
|
||||
if(totalParticles > 0 && tsMax > tsMin)
|
||||
{
|
||||
// 时间戳差值 = 最大计数 - 最小计数
|
||||
quint64 tsDelta = tsMax - tsMin;
|
||||
// 计算公式:实时间 = 总计数差 / 时钟频率(200MHz)
|
||||
realTime = static_cast<double>(tsDelta) / (GvfConst::CLOCK_FREQ_MHZ * 1e6);
|
||||
// 防止ICR总和为0除零崩溃
|
||||
if(totalIcrSum > 0)
|
||||
{
|
||||
// 有效粒子占输入触发总计数比例
|
||||
double countRatio = static_cast<double>(totalParticles) / totalIcrSum;
|
||||
// 活时间 = 实时间 × 有效粒子占比
|
||||
liveTime = realTime * countRatio;
|
||||
// 死时间 = 实时间 - 活时间
|
||||
deadTime = realTime - liveTime;
|
||||
}
|
||||
}
|
||||
QFileInfo csvFileInfo(m_csvPath);
|
||||
QString jsonFilePath = csvFileInfo.absoluteDir().filePath("report_params.json");
|
||||
QFile jsonFile(jsonFilePath);
|
||||
|
||||
QJsonObject rootObj;
|
||||
rootObj["real_time_s"] = realTime; // 真时间,单位秒
|
||||
rootObj["live_time_s"] = liveTime; // 活时间,单位秒
|
||||
rootObj["dead_time_s"] = deadTime; // 死时间,单位秒
|
||||
rootObj["start_absolute_time"] = measureStartAbsTime;
|
||||
QFileInfo gvfInfo(m_gvfPath);
|
||||
rootObj["gvf_file_name"] = gvfInfo.fileName();
|
||||
// 生成带缩进格式化JSON文本,便于阅读
|
||||
QJsonDocument jsonDoc(rootObj);
|
||||
QByteArray jsonContent = jsonDoc.toJson(QJsonDocument::Indented);
|
||||
|
||||
// 写入JSON文件,覆盖原有文件
|
||||
if (!jsonFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text))
|
||||
{
|
||||
throw std::runtime_error(QString("Generate report_params.json failed, path:%1 error:%2")
|
||||
.arg(jsonFilePath)
|
||||
.arg(jsonFile.errorString())
|
||||
.toStdString());
|
||||
}
|
||||
jsonFile.write(jsonContent);
|
||||
jsonFile.flush();
|
||||
jsonFile.close();
|
||||
|
||||
out.flush();
|
||||
outFile.close();
|
||||
|
||||
|
|
|
|||
|
|
@ -270,6 +270,29 @@ QVector<DataBaseStruct> SQLiteReadWrite::DataBaseList() const
|
|||
return m_DataBaseList;
|
||||
}
|
||||
|
||||
QString SQLiteReadWrite::getMeasureStartTime()
|
||||
{
|
||||
QMutexLocker locker(&m_mutex);
|
||||
if (m_isClosed || !m_database.isOpen())
|
||||
{
|
||||
log("Database not open, cannot read statistic starttime");
|
||||
return "";
|
||||
}
|
||||
QSqlQuery query(m_database);
|
||||
// lmstatisticinfov2 存储本次测量标准起止时间
|
||||
if (!query.exec("SELECT starttime FROM lmstatisticinfov2 LIMIT 1;"))
|
||||
{
|
||||
log(QString("Query lmstatisticinfov2 failed: %1").arg(query.lastError().text()));
|
||||
return "";
|
||||
}
|
||||
if (query.next())
|
||||
{
|
||||
return query.value("starttime").toString();
|
||||
}
|
||||
log("lmstatisticinfov2 table has no starttime record");
|
||||
return "";
|
||||
}
|
||||
|
||||
void SQLiteReadWrite::setIdValue(int value)
|
||||
{
|
||||
idValue = value;
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ public:
|
|||
|
||||
QVector<DataBaseStruct> DataBaseList() const;
|
||||
|
||||
// 获取测量官方起始时间 lmstatisticinfov2.starttime
|
||||
QString getMeasureStartTime();
|
||||
signals:
|
||||
void progressUpdated(int percent, qint64 processed, qint64 total);
|
||||
void operationCompleted(bool success, const QString &message);
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ QString ReportGenerator::generateMeasurementSection() const
|
|||
.arg(formatDateTime(m_data.measurement.startTime))
|
||||
.arg(formatDecimal(m_data.measurement.liveTime, 0));
|
||||
html += QString("<tr><td>实时间(S):</td><td>%1</td>"
|
||||
"<td>死时间:</td><td>%2 %</td></tr>")
|
||||
"<td>死时间:</td><td>%2</td></tr>")
|
||||
.arg(formatDecimal(m_data.measurement.realTime, 0))
|
||||
.arg(formatDecimal(m_data.measurement.deadTime, 2));
|
||||
html += "</table>";
|
||||
|
|
@ -345,7 +345,7 @@ QString ReportGenerator::generateTextReport() const
|
|||
stream << QStringLiteral(u" 开始时间: ") << formatDateTime(m_data.measurement.startTime) << "\n";
|
||||
stream << QStringLiteral(u" 活时间: ") << formatDecimal(m_data.measurement.liveTime, 0) << "\n";
|
||||
stream << QStringLiteral(u" 实时间: ") << formatDecimal(m_data.measurement.realTime, 0) << "\n";
|
||||
stream << QStringLiteral(u" 死时间: ") << formatDecimal(m_data.measurement.deadTime, 2) << " %\n\n";
|
||||
stream << QStringLiteral(u" 死时间: ") << formatDecimal(m_data.measurement.deadTime, 2) << " \n\n";
|
||||
|
||||
stream << QStringLiteral(u"刻度\n");
|
||||
stream << "----------------------------------------\n";
|
||||
|
|
|
|||
|
|
@ -14,6 +14,10 @@
|
|||
#include <QLabel>
|
||||
#include <QTableWidget>
|
||||
#include <QScrollArea>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include "MeasureAnalysisProjectModel.h"
|
||||
|
||||
ReportWidget::ReportWidget(QWidget *parent)
|
||||
: QWidget(parent)
|
||||
{
|
||||
|
|
@ -467,9 +471,17 @@ void ReportWidget::exportText()
|
|||
|
||||
void ReportWidget::loadSampleData()
|
||||
{
|
||||
SpectrumReportData data;
|
||||
data.fillSampleData();
|
||||
setReportData(data);
|
||||
auto project_model = ProjectList::Instance()->GetCurrentProjectModel();
|
||||
if (project_model == nullptr) {
|
||||
QMessageBox::information(this, "提示:", "请先加载项目!");
|
||||
return;
|
||||
}
|
||||
//获取当前可执行目录下
|
||||
QString jsonPath = project_model->GetProjectDir() + "/report_params.json";
|
||||
m_data.loadReportParamsJson(jsonPath);
|
||||
// SpectrumReportData data;
|
||||
// data.fillSampleData();
|
||||
setReportData(m_data);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
#include "spectrumdata.h"
|
||||
|
||||
#include <QDebug>
|
||||
SpectrumReportData::SpectrumReportData()
|
||||
{
|
||||
}
|
||||
|
|
@ -107,3 +107,138 @@ void SpectrumReportData::fillSampleData()
|
|||
signature.laboratory = "GAMMASPEC";
|
||||
signature.reportDate = QDate(2025, 11, 13);
|
||||
}
|
||||
|
||||
bool SpectrumReportData::loadReportParamsJson(const QString &jsonPath)
|
||||
{
|
||||
QFile jsonFile(jsonPath);
|
||||
// 判断文件是否存在
|
||||
if (!jsonFile.exists())
|
||||
{
|
||||
qDebug() << "loadReportParamsJson: 文件不存在 " << jsonPath;
|
||||
return false;
|
||||
}
|
||||
// 只读打开
|
||||
if (!jsonFile.open(QIODevice::ReadOnly | QIODevice::Text))
|
||||
{
|
||||
qDebug() << "loadReportParamsJson: 打开失败 " << jsonFile.errorString();
|
||||
return false;
|
||||
}
|
||||
QByteArray jsonRaw = jsonFile.readAll();
|
||||
jsonFile.close();
|
||||
|
||||
QJsonParseError parseErr;
|
||||
QJsonDocument doc = QJsonDocument::fromJson(jsonRaw, &parseErr);
|
||||
// JSON语法错误判断
|
||||
if (parseErr.error != QJsonParseError::NoError || doc.isNull() || !doc.isObject())
|
||||
{
|
||||
qDebug() << "loadReportParamsJson: JSON解析错误 " << parseErr.errorString();
|
||||
return false;
|
||||
}
|
||||
QJsonObject rootObj = doc.object();
|
||||
|
||||
// 临时拷贝原有测量参数,只覆盖时间相关字段
|
||||
SpectrumReportData tempData = *this;
|
||||
// ===================== 1. 测量参数模块 =====================
|
||||
//读取能谱文件名
|
||||
if (rootObj.contains("gvf_file_name"))
|
||||
{
|
||||
tempData.measurement.spectrumFile = rootObj["gvf_file_name"].toString();
|
||||
}
|
||||
|
||||
// 读取实时间 real_time_s
|
||||
if (rootObj.contains("real_time_s"))
|
||||
{
|
||||
tempData.measurement.realTime = rootObj["real_time_s"].toDouble(0.0);
|
||||
}
|
||||
// 读取活时间 live_time_s
|
||||
if (rootObj.contains("live_time_s"))
|
||||
{
|
||||
tempData.measurement.liveTime = rootObj["live_time_s"].toDouble(0.0);
|
||||
}
|
||||
// 读取死时间秒,换算百分比存入deadTime
|
||||
if (rootObj.contains("dead_time_s"))
|
||||
{
|
||||
tempData.measurement.deadTime = rootObj["dead_time_s"].toDouble(0.0);
|
||||
}
|
||||
// 读取测量开始时间字符串 start_absolute_time
|
||||
if (rootObj.contains("start_absolute_time"))
|
||||
{
|
||||
QString dtStr = rootObj["start_absolute_time"].toString();
|
||||
QDateTime dt = QDateTime::fromString(dtStr, "yyyy-M-d hh:mm:ss");
|
||||
if (dt.isValid())
|
||||
{
|
||||
tempData.measurement.startTime = dt;
|
||||
}
|
||||
}
|
||||
// ===================== 2. 刻度参数模块 =====================
|
||||
// 刻度文件名称
|
||||
if (rootObj.contains("calib_file"))
|
||||
tempData.calibration.fileName = rootObj["calib_file"].toString();
|
||||
// 标准源
|
||||
if (rootObj.contains("standard_source"))
|
||||
tempData.calibration.standardSource = rootObj["standard_source"].toString();
|
||||
// 能量刻度生成时间
|
||||
if (rootObj.contains("energy_calib_time"))
|
||||
{
|
||||
QString dtStr = rootObj["energy_calib_time"].toString();
|
||||
QDateTime dt = QDateTime::fromString(dtStr, "yyyy-M-d hh:mm:ss");
|
||||
if (dt.isValid())
|
||||
tempData.calibration.energy.generateTime = dt;
|
||||
}
|
||||
// 能量截距
|
||||
if (rootObj.contains("energy_intercept"))
|
||||
tempData.calibration.energy.intercept = rootObj["energy_intercept"].toDouble(0.0);
|
||||
// 能量斜率
|
||||
if (rootObj.contains("energy_slope"))
|
||||
tempData.calibration.energy.slope = rootObj["energy_slope"].toDouble(0.0);
|
||||
// 二次项系数
|
||||
if (rootObj.contains("energy_quadratic"))
|
||||
tempData.calibration.energy.quadratic = rootObj["energy_quadratic"].toDouble(0.0);
|
||||
// 效率刻度生成时间
|
||||
if (rootObj.contains("eff_calib_time"))// 生成时间
|
||||
{
|
||||
QString dtStr = rootObj["eff_calib_time"].toString();
|
||||
QDateTime dt = QDateTime::fromString(dtStr, "yyyy-M-d hh:mm:ss");
|
||||
if (dt.isValid())
|
||||
tempData.calibration.efficiency.generateTime = dt;
|
||||
}
|
||||
// 拐点能量
|
||||
if (rootObj.contains("inflection_energy"))// 拐点能量 (keV)
|
||||
tempData.calibration.efficiency.inflectionEnergy = rootObj["inflection_energy"].toDouble(0.0);
|
||||
// 拐点以上拟合公式
|
||||
if (rootObj.contains("above_eq"))// 拐点以上方法
|
||||
tempData.calibration.efficiency.aboveInflection = rootObj["above_eq"].toString();
|
||||
// 拐点以上误差
|
||||
if (rootObj.contains("above_err"))// 拐点以上误差
|
||||
tempData.calibration.efficiency.aboveError = rootObj["above_err"].toDouble(0.0);
|
||||
// 拐点以下拟合公式
|
||||
if (rootObj.contains("below_eq"))// 拐点以下方法
|
||||
tempData.calibration.efficiency.belowInflection = rootObj["below_eq"].toString();
|
||||
// 拐点以下误差
|
||||
if (rootObj.contains("below_err"))// 拐点以下误差
|
||||
tempData.calibration.efficiency.belowError = rootObj["below_err"].toDouble(0.0);
|
||||
// 效率对数方程式
|
||||
if (rootObj.contains("eff_log_eq"))// 效率对数方程式
|
||||
tempData.calibration.efficiency.logEquation = rootObj["eff_log_eq"].toString();
|
||||
// ===================== 3. 核素库模块 =====================
|
||||
if (rootObj.contains("nuclide_lib_file"))// 库文件名
|
||||
tempData.nuclideLib.fileName = rootObj["nuclide_lib_file"].toString();
|
||||
if (rootObj.contains("peak_match_width"))// 峰匹配宽度
|
||||
tempData.nuclideLib.peakMatchWidth = rootObj["peak_match_width"].toDouble(0.0);
|
||||
// ===================== 4. 分析参数模块 =====================
|
||||
if (rootObj.contains("start_energy"))//起始能量
|
||||
tempData.analysis.startEnergy = rootObj["start_energy"].toDouble(0.0);
|
||||
if (rootObj.contains("end_energy"))//终止能量
|
||||
tempData.analysis.endEnergy = rootObj["end_energy"].toDouble(0.0);
|
||||
if (rootObj.contains("stat_error_limit"))//统计误差限值
|
||||
tempData.analysis.statErrorLimit = rootObj["stat_error_limit"].toDouble(0.0);
|
||||
if (rootObj.contains("activity_ratio"))// 活度比例系数
|
||||
tempData.analysis.activityRatio = rootObj["activity_ratio"].toDouble(0.0);
|
||||
if (rootObj.contains("mda_method"))// 探测限计算方法
|
||||
tempData.analysis.mdaMethod = rootObj["mdaMethod"].toString();
|
||||
|
||||
|
||||
// 替换本类测量参数,其余刻度/核素/峰数据不变
|
||||
*this = tempData;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -4,7 +4,10 @@
|
|||
#include <QString>
|
||||
#include <QDateTime>
|
||||
#include <QVector>
|
||||
|
||||
#include <QFile>
|
||||
#include <QJsonDocument>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonParseError>
|
||||
// 能量刻度参数
|
||||
struct EnergyCalibration {
|
||||
QDateTime generateTime; // 生成时间
|
||||
|
|
@ -109,6 +112,9 @@ public:
|
|||
|
||||
// 示例数据填充
|
||||
void fillSampleData();
|
||||
//读取report_params.json,填充measurement时间参数
|
||||
bool loadReportParamsJson(const QString &jsonPath);
|
||||
|
||||
};
|
||||
|
||||
#endif // SPECTRUMDATA_H
|
||||
|
|
@ -6,7 +6,6 @@
|
|||
#include <QStyleFactory>
|
||||
#include "QsLogManage.h"
|
||||
#include <QThreadPool>
|
||||
|
||||
void InitAppRunEnv() {
|
||||
// 在应用程序可执行文件所在目录检查并创建Projects目录
|
||||
QString projects_dir_path = QDir(qApp->applicationDirPath()).filePath("Projects");
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user