Compare commits

..

No commits in common. "adc67aac776d340a130c6d466dd19c0b5278ee66" and "7016f584b90f3bbfc94c7cd1a0569f65f52a5e27" have entirely different histories.

11 changed files with 51 additions and 52 deletions

Binary file not shown.

View File

@ -1,146 +0,0 @@
1.交互分析功能需求:
粒子数据文件索引及打开功能;
可对能谱进行重新刻度,或刻度数据导入;
常用功能:可进行谱放大缩小,自适应屏幕调整能谱大小,常规或对数能谱显示,显示能谱信息、刻度参数等常规信息;
粒子时间差统计给出粒子时间差的统计结果能够根据指定的时间差对符合事件进行筛选功能5
能谱显示:可显示能量计数谱、二维符合谱;在符合时间未给出的情况下不显示符合能谱,只显示能量计数谱;
能量计数谱可显示原始能谱、符合谱、反符合能谱(可选择探测器,如在信息中没有探测器的信息则此选项为不可选);
能量技术谱分析可根据选定能峰的信息给出可能的核素信息,通过选择核素可同步显示该核素其他能峰对应能量区域的能谱信息,如果有能峰存在给出该区域的能峰拟合信息;
时间切片功能按指定的时间间隔统计特征能峰或指定区域即ROI的计数率给出时间段内计数率随测量时间的变化
多条件粒子筛选、显示及统计功能:通过时间差、能量、符合次数筛选不同类型的符合事件及其粒子信息,指定筛选给出粒子的类型(电子、光子),统计事件次数,实现可视化;
数据拟合通过默认或输入的公式对指定ROI区域的能峰进行拟合给出峰位、FWHM、峰面积、本底计数等信息可在能谱上显示拟合能谱曲线及本底曲线只在能量计数谱上显示
符合能谱数据统计统计ROI区域的计数针对二维符合能谱ROI区域可设为圆形或任意角度的长方形统计区域中不同能量的计数及其粒子信息
二维符合谱的显示模式1横轴为初级入射粒子的能量keV纵轴为次级入射粒子的能量keV之和模式2横轴为入射γ、X光子的能量keV纵轴为电子的能量keV
2.目前使用的峰拟合函数:
光子
f_peak=f_peak=@(A,delt,H,W,C,P,x)A*exp(-(x-P).^2 ./(2*delt^2))+H./(1+exp((x-P)./W))+C;
电子
f_epeak=@(A,Bg,a,m.delt,a)Bg+A*(1+((x)./a).^2).^(-m).*exp(-delt.*atan((x)./a))
Matlab峰拟合脚本γ能谱
clear;
clc;
close all;
%% 参数设置
fname = 'SampleA.TKA';
count = load(fname); % * .TKA 是纯文本列向量
% load('E:\UnCSSSP\Matspace\electron\si_sp.mat')
% count=data1(:,2);
% 能量刻度: En = a * ch + b
par_encal = [3.509e-1, -1.965e-2]; % [a, b] 单位: keV/channel
a = par_encal(1);
b = par_encal(2);
x_ch=1:length(count);
x_en=a*x_ch+b;
% 峰形刻度: FWHM(keV) = p_form(1)*sqrt(En) + p_form(2)
p_form = [3.968e-2, 3.661e-1]; % [k, c]
% 拟合峰能量keV输入峰能量
E_peak =input('指定全能峰能量keV:');
% 计算 FWHM 和 高斯标准差
FWHM = p_form(1) * sqrt(E_peak) + p_form(2); % keV
delt = FWHM / 2.355; % 高斯 σkeV
% 转换为道址(用于提取数据)
FWHM_ch = FWHM / a; % 道址宽度
delt_ch = delt / a; % σ 道址
p_chn = round((E_peak - b) / a); % 峰位道址
% 提取数据范围:+-1.5 FWHM共 p_w 个点
p_w = 9;
channels = (p_chn - round(6*FWHM_ch)) : (p_chn + round(5 * FWHM_ch));
% if length(channels) < p_w
% error('提取道址范围过小,请检查 FWHM 或 p_w');
% end
% channels = channels(1:p_w); % 截取 p_w 个点
% 提取能量和计数
en_p = a * channels + b; % 实际能量keV
p_count = count(channels)'; % 注意:转置为列向量
%% 定义拟合函数(所有参数显式列出)
% f(x) = Gaussian + Sigmoid tail + constant
f_peak = @(A, delt, H, W, C, P, x)A*exp(-(x-P).^2 ./(2*delt^2))+H./(1+exp((x-P)./W))+C;
%本底函数
f_BG=@(A, delt, H, W, C,P , x)H./(1+exp((x-P)./W))+C; %本底函数
%峰函数
f_pk_s=@(A, delt, H, W,P , x)A.*exp(-(x-P).^2/(2.*delt.^2)); %计算得出的峰函数
% 初始猜测
startA = max(p_count) - min(p_count); % 峰高
startC = min(p_count); % 基线
startH = 0.1 * startA; % 拖尾幅度(经验)
startW = delt * 2; % 拖尾尺度(经验)
startP = E_peak; % 峰位
opts = fitoptions('Method', 'NonlinearLeastSquares');
opts.StartPoint = [startA, delt, startH, startW, startC, startP]; % A, delt, H, W, C
opts.Robust = 'LAR'; % 抗异常值
opts.Display = 'off';
opts.TolFun = 1e-10;
opts.TolX = 1e-10;
% 定义 fittype
ft = fittype(f_peak,'independent','x','dependent', 'y','coefficients', {'A', 'delt', 'H', 'W', 'C','P'});
%% 拟合
[info_pfit, gof, output] = fit(en_p', p_count', ft, opts);
% 提取结果
A = info_pfit.A;
delt_fitted = info_pfit.delt; % 可更新
H = info_pfit.H;
W = info_pfit.W;
C = info_pfit.C;
P = info_pfit.P;
%% 输出结果
fprintf(' 全能峰拟合完成(%g keV:\n', E_peak);
fprintf(' A = %.2f\n', A);
fprintf(' H = %.2f\n', H);
fprintf(' W = %.2f keV\n', W);
fprintf(' P = %.2f keV\n',P);
fprintf(' C = %.2f (基线)\n', C);
fprintf(' R^2 = %.6f\n', gof.rsquare);
fprintf(' RMSE = %.4f\n', gof.rmse);
%% 计算峰计数
peak_only = @(x) f_pk_s(A, delt_fitted, H, W, P, x);
background = @(x) f_BG(A, delt_fitted, H, W, C, P, x);
full_peak = @(x) f_peak(A, delt_fitted, H, W, C, P, x);
% 积分范围:+-3σ能量空间
x_low = E_peak - 3 * delt_fitted;
x_high = E_peak + 3 * delt_fitted;
% 积分求解峰面积
Area_total = integral(full_peak, x_low, x_high, 'ArrayValued', true)/a;
BG_area = integral(background, x_low, x_high, 'ArrayValued', true)/a;
Peak_area = integral(peak_only, x_low, x_high, 'ArrayValued', true)/a;
fprintf('\n %.2f keV全能峰面积计算:\n',E_peak);
fprintf(' 全峰面积 = %.2f \n', Area_total);
fprintf(' 本底面积 = %.2f \n', BG_area);
fprintf(' 净峰面积 = %.2f \n', Peak_area);
%% 绘图
monitorPositions = get(0, 'MonitorPositions');
[~, numMonitors] = size(monitorPositions);
if numMonitors < 2
error('仅检测到一个显示器,无法在副屏显示。');
end
% 副屏位置
secondaryMonitor = monitorPositions(2, :); % [left, bottom, width, height]
fig_pos=secondaryMonitor;
fig_pos(1) = fig_pos(1) + 8 ;
fig_pos(3) = fig_pos(3) - 8 ;
fig_pos(4) = fig_pos(4) - 85;
figure;%figure('WindowState','fullscreen')
set(gcf, 'Units', 'pixels', 'Position', fig_pos);
subplot(1,3,[1,2]);
plot(x_en,count);
xlabel('能量 (keV)');
ylabel('计数');
grid on;
subplot(1,3,3);
plot(en_p, p_count, 'bo', 'DisplayName', '数据点');
hold on;
x_fine = linspace(min(en_p), max(en_p), 100);
plot(x_fine, f_peak(A, delt_fitted, H, W, C, P, x_fine), 'r-', 'LineWidth', 2, 'DisplayName', '拟合曲线');
plot(x_fine, f_pk_s(A, delt_fitted, H, W, P, x_fine), 'g--', 'LineWidth', 2, 'DisplayName', '单峰曲线')
plot(x_fine, f_BG(A, delt_fitted, H, W, C, P, x_fine), 'c--', 'LineWidth', 1, 'DisplayName', '本底曲线')
plot(x_fine, f_pk_s(A, delt_fitted, H, W, P, x_fine)+f_BG(A, delt_fitted, H, W, C, P, x_fine), 'b--', 'LineWidth', 1, 'DisplayName', '单峰曲线')
xlabel('能量 (keV)');
ylabel('计数');
title(sprintf('%.1f keV 峰拟合', P));
legend('Location', 'best');
grid on;
hold off;
%% 添加文本框显示结果
annotation('textbox', [0.898, 0.81, 0.1, 0.1], 'String',{sprintf('修正后峰位:%.3f', P),sprintf('修正后方差:%.3f keV', delt_fitted), ...
sprintf('拟合优度:%.5f',gof.rsquare),sprintf('净峰面积:%.0f', Peak_area)}, 'BackgroundColor', 'white', 'EdgeColor', 'k', 'FontSize', 10);

View File

@ -9,11 +9,10 @@ BusyIndicator::BusyIndicator(QWidget* parent)
setAttribute(Qt::WA_TransparentForMouseEvents);
QLabel* icon = new QLabel;
// icon->setMaximumSize(80, 80);
// QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
// icon->setSizePolicy(sizePolicy);
icon->resize(80, 80);
QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
icon->setSizePolicy(sizePolicy);
_busy_movie = new QMovie(":gif/BusyIndicator.gif"); // 转圈 GIF
_busy_movie->setScaledSize(QSize(50, 50));
icon->setMovie(_busy_movie);
_busy_movie->start();
QLabel* text = new QLabel(QStringLiteral(u"加载数据中......"));
@ -27,14 +26,14 @@ BusyIndicator::BusyIndicator(QWidget* parent)
void BusyIndicator::Start()
{
_busy_movie->start();
// _busy_movie->start();
this->setVisible(true);
this->update();
}
void BusyIndicator::Stop()
{
_busy_movie->stop();
// _busy_movie->stop();
this->setVisible(false);
this->update();
}

View File

@ -304,15 +304,18 @@ void MainWindow::initAction()
}
}
});
/*
connect(_tree_measure_analysis, &MeasureAnalysisTree::TreeWidget::newMeasureAnalysisProject, new_measurement_analysis_handler);
*/
}
void MainWindow::applyStyleSheet()
{
// #ifdef ENABLE_DEBUG
// QString style_file_path = "D:/Workspace/EnergySpectrumAnalyerProject/EnergySpectrumAnalyer/style/stylesheet/";
// #else
#ifdef ENABLE_DEBUG
QString style_file_path = "D:/Workspace/EnergySpectrumAnalyerProject/EnergySpectrumAnalyer/style/stylesheet/";
#else
QString style_file_path = ":/stylesheet/";
// #endif
#endif
QFile file_stylesheet_default(style_file_path + "default.qss");
if (file_stylesheet_default.open(QFile::ReadOnly)) {
const QString& str_stylesheet_default = file_stylesheet_default.readAll();
@ -354,12 +357,6 @@ void MainWindow::closeProject(const QString& project_name)
}
}
void MainWindow::showEvent(QShowEvent *event)
{
QMainWindow::showEvent(event);
this->applyStyleSheet();
}
void MainWindow::closeEvent(QCloseEvent* event)
{
QList<MeasureAnalysisProjectModel *> models = ProjectList::Instance()->GetProjectModels();

View File

@ -53,7 +53,6 @@ signals:
void newProject(const QString &project_name);
protected:
virtual void showEvent(QShowEvent* event) override;
virtual void closeEvent(QCloseEvent* event) override;
private:

View File

@ -35,7 +35,7 @@ MeasureAnalysisHistoryForm::~MeasureAnalysisHistoryForm()
delete ui;
}
void MeasureAnalysisHistoryForm::loadHistoryInfo(const QString &history_name)
void MeasureAnalysisHistoryForm::loadHistoryInfo()
{
auto row_count = ui->tablew_history->rowCount();
for (int row = row_count - 1; row >= 0; --row) {
@ -57,11 +57,9 @@ void MeasureAnalysisHistoryForm::loadHistoryInfo(const QString &history_name)
const QString& project_filename = project_dir_path.filePath(msproject_files.first());
MeasureAnalysisProjectModel project_model;
project_model.LoadProjectModel(project_filename);
const QString& project_name = project_model.GetProjectName();
int row = ui->tablew_history->rowCount();
ui->tablew_history->insertRow(row);
ui->tablew_history->setItem(row, 0, new QTableWidgetItem(project_name));
ui->tablew_history->setItem(row, 0, new QTableWidgetItem(project_model.GetProjectName()));
ui->tablew_history->item(row, 0)->setCheckState(Qt::Unchecked);
ui->tablew_history->item(row, 0)->setData(Qt::UserRole, project_filename);
const QString& is_measure_complete = project_model.GetIsMeasureComplete() ? QStringLiteral(u"") : QStringLiteral(u"");
@ -75,15 +73,6 @@ void MeasureAnalysisHistoryForm::loadHistoryInfo(const QString &history_name)
ui->tablew_history->setItem(row, 5, new QTableWidgetItem());
ui->tablew_history->setItem(row, 6, new QTableWidgetItem());
ui->tablew_history->setItem(row, 7, new QTableWidgetItem(project_model.GetDescriptionInfo()));
if (history_name == project_name) {
for (int col = 0; col < ui->tablew_history->columnCount(); ++col) {
QTableWidgetItem* other_item = ui->tablew_history->item(row, col);
if (other_item) {
other_item->setFlags(other_item->flags() & ~(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsUserCheckable));
}
}
}
}
}
}
@ -137,13 +126,12 @@ void MeasureAnalysisHistoryForm::onReverseSelect()
void MeasureAnalysisHistoryForm::onRemoveSelectedProject()
{
QMap<int, QPair<QString, QString> > selected_project_list;
QMap<int, QString> selected_project_list;
auto row_count = ui->tablew_history->rowCount();
for (int row = row_count - 1; row >= 0; --row) {
if (Qt::Checked == ui->tablew_history->item(row, 0)->checkState()) {
const QString& project_name = ui->tablew_history->item(row, 0)->text();
const QString& project_filename = ui->tablew_history->item(row, 0)->data(Qt::UserRole).toString();
selected_project_list[row] = qMakePair(project_name, project_filename);
selected_project_list[row] = project_filename;
}
}
if (selected_project_list.isEmpty()) {
@ -154,15 +142,12 @@ void MeasureAnalysisHistoryForm::onRemoveSelectedProject()
return;
}
for (int row : selected_project_list.keys()) {
const QString& project_name = selected_project_list.value(row).first;
ProjectList::Instance()->RmProjectModel(project_name);
const QString& project_filename = selected_project_list.value(row).second;
QFileInfo project_file_info(project_filename);
QFileInfo project_file_info(selected_project_list.value(row));
const QString& project_dir_path = project_file_info.absoluteDir().absolutePath();
QDir(project_dir_path).removeRecursively();
QDir(project_dir_path).rmdir(project_dir_path);
ui->tablew_history->removeRow(row);
LOG_INFO(QStringLiteral(u"测量分析项目\"%1\"已经删除.").arg(project_name));
LOG_INFO(QStringLiteral(u"测量分析项目\"%1\"已经删除.").arg(project_file_info.baseName()));
}
}
@ -240,5 +225,6 @@ void MeasureAnalysisHistoryForm::onUpdateCloseHistoryProject(const QString &proj
void MeasureAnalysisHistoryForm::onUpdateNewHistoryProject(const QString &project_name)
{
loadHistoryInfo(project_name);
Q_UNUSED(project_name);
loadHistoryInfo();
}

View File

@ -16,7 +16,7 @@ public:
~MeasureAnalysisHistoryForm();
private:
void loadHistoryInfo(const QString& history_name = QString());
void loadHistoryInfo();
private slots:
void onQueryHistory();
void onAllSelect();

View File

@ -155,6 +155,9 @@ void ParticleTimeDifferenceView::loadDataFromFile()
x_max = bin_max;
if ( y_max < count )
y_max = count;
// if ( _max_diff <= bin ) {
// break;
// }
}
_histogram->setData(new QwtIntervalSeriesData(samples));
_plot->SetAxisInitRange(QwtPlot::xBottom, 0.0f, _x_max);

View File

@ -5,7 +5,6 @@
#include <QResource>
#include <QStyleFactory>
#include "QsLogManage.h"
#include <QThreadPool>
int main(int argc, char *argv[])
{
@ -62,7 +61,5 @@ int main(int argc, char *argv[])
MainWindow w;
w.showMaximized();
int ret = app.exec();
QThreadPool::globalInstance()->waitForDone();
return ret;
return app.exec();
}

View File

@ -1,4 +1,4 @@
/*
QwtPlot {
background-color: white;
}
@ -12,18 +12,18 @@ QPlainTextEdit {
}
QTreeView::item:selected:active{
color: white;
background: #0078d4;
color: black;
background: #7bbfea;
}
QTreeView::item:selected:!active {
color: black;
background: white;
background: #7bbfea;
}
QTableView {
selection-color: white;
selection-background-color: #0078d4;
selection-color: black;
selection-background-color: #7bbfea;
}
QTableView QTableCornerButton::section {
@ -44,7 +44,8 @@ QHeaderView::section {
border-top: 0px;
}
QHeaderView::section {
QHeaderView::section:checked
{
font-weight: normal;
}
@ -90,5 +91,21 @@ QScrollBar::add-page {
QScrollBar::sub-page {
background: rgba(0, 0, 0, 0);
}
*/
/*
QTreeView[Checkable="false"]::indicator:unchecked {
background: blue;
}
QTreeView[Checkable="false"]::indicator:checked {
background: blue;
}
QTreeView[Checkable="true"]::unchecked {
background: red; }
QTreeView[Checkable="true"]::checked {
background: green;
}
*/

View File

@ -1,4 +1,4 @@
/*
ads--CDockContainerWidget ads--CDockSplitter::handle {
background: #2a5caa;
}
@ -10,3 +10,4 @@ ads--CDockSplitter::handle:horizontal {
ads--CDockSplitter::handle:vertical {
height: 1px;
}
*/