#include #include #include "CoincidenceSpectrumProcess.h" using namespace arma; namespace CoincidenceSpectrum { mat EventFilter2Order(const mat& raw_spec_data, double coincidence_event_time_win) { // 原始谱数据排序 auto raw_spec_data_size = size(raw_spec_data); mat temp_data(raw_spec_data_size.n_rows, 3, fill::zeros); temp_data.col(0) = raw_spec_data.col(3); temp_data.col(1) = raw_spec_data.col(2); temp_data.col(2) = 4 * raw_spec_data.col(0) + raw_spec_data.col(1) + 1; uvec indices = sort_index(temp_data.col(0), "ascend"); mat raw_spec_sorted_data = temp_data.rows(indices); // 整理次级谱数据 temp_data.clear(); SizeMat raw_spec_sorted_data_size = size(raw_spec_sorted_data); uword rows_count = raw_spec_sorted_data_size.n_rows; uword cols_count = raw_spec_sorted_data_size.n_cols; uword last_row_num = rows_count - 1; uword last_col_num = cols_count - 1; temp_data = raw_spec_sorted_data.submat(1, 0, last_row_num, last_col_num); temp_data.insert_rows(last_row_num, raw_spec_sorted_data.row(last_row_num)); // 计算得到时间差谱数据 mat coincidence_spec_data(rows_count, 6); coincidence_spec_data.col(0) = temp_data.col(0) - raw_spec_sorted_data.col(0); coincidence_spec_data.col(1) = raw_spec_sorted_data.col(1); coincidence_spec_data.col(2) = raw_spec_sorted_data.col(2); coincidence_spec_data.col(3) = temp_data.col(1); coincidence_spec_data.col(4) = temp_data.col(2); coincidence_spec_data.col(5) = temp_data.col(0); raw_spec_sorted_data.clear(); temp_data.clear(); // 筛选出符合谱数据 indices = sort_index(coincidence_spec_data.col(0), "ascend"); coincidence_spec_data = coincidence_spec_data.rows(indices); auto time_difference_col = coincidence_spec_data.col(0); indices = find(time_difference_col <= coincidence_event_time_win); coincidence_spec_data = coincidence_spec_data.rows(indices); return coincidence_spec_data; } // 计算二维直方图 void Hist3(const mat& data, int nx, int ny, mat& counts, vec& x_edges, vec& y_edges) { // 检查输入数据是否为N×2矩阵 if (data.n_cols != 2) { cerr << "输入数据必须是N×2矩阵" << endl; return; } uword n = data.n_rows; if (n == 0) { counts = zeros(nx, ny); x_edges = zeros(nx + 1); y_edges = zeros(ny + 1); return; } // 提取x和y数据 vec x = data.col(0); // 对应MATLAB的第2列 vec y = data.col(1); // 对应MATLAB的第3列 // 计算x和y的分箱边界(等宽分箱) double x_min = x.min(); double x_max = x.max(); double y_min = y.min(); double y_max = y.max(); // 处理x或y所有值相同的特殊情况(避免除以0) if (x_min == x_max) { x_edges = linspace(x_min - 1e-6, x_max + 1e-6, nx + 1); // 微小范围 } else { x_edges = linspace(x_min, x_max, nx + 1); // nx+1个边界,nx个分箱 } if (y_min == y_max) { y_edges = linspace(y_min - 1e-6, y_max + 1e-6, ny + 1); } else { y_edges = linspace(y_min, y_max, ny + 1); } // 初始化频数矩阵(nx行,ny列) counts = zeros(nx, ny); // 遍历每个数据点,统计频数 for (int i = 0; i < n; ++i) { double xi = x(i); double yi = y(i); // 找到xi所在的x分箱索引(0-based) int bin_x = -1; for (int j = 0; j < nx; ++j) { if (xi >= x_edges(j) && xi < x_edges(j + 1)) { bin_x = j; break; } } // 处理刚好等于最大值的点(放入最后一个分箱) if (bin_x == -1 && xi == x_edges(nx)) { bin_x = nx - 1; } // 找到yi所在的y分箱索引(0-based) int bin_y = -1; for (int j = 0; j < ny; ++j) { if (yi >= y_edges(j) && yi < y_edges(j + 1)) { bin_y = j; break; } } if (bin_y == -1 && yi == y_edges(ny)) { bin_y = ny - 1; } // 累加频数(忽略超出范围的点) if (bin_x >= 0 && bin_x < nx && bin_y >= 0 && bin_y < ny) { counts(bin_x, bin_y)++; } } } namespace F2t9Order { // 读取CSV数据文件 std::vector ReadCsv(const std::string& filename) { std::vector data; std::ifstream file(filename); if (!file.is_open()) { std::cerr << "错误:无法打开文件 " << filename << std::endl; return data; } std::string line; // 跳过表头 std::getline(file, line); while (std::getline(file, line)) { std::stringstream ss(line); std::string token; std::vector tokens; while (std::getline(ss, token, ',')) { tokens.push_back(token); } if (tokens.size() == 4) { SpectrumData entry; entry.board_id = std::stoi(tokens[0]); entry.channel_id = std::stoi(tokens[1]); entry.energy = std::stod(tokens[2]); entry.timestamp = std::stoull(tokens[3]); data.push_back(entry); } } file.close(); std::cout << "成功读取 " << data.size() << " 条有效数据" << std::endl; return data; } // 按时间戳排序数据 void SortDataByTimestamp(std::vector& data) { std::sort(data.begin(), data.end(), [](const SpectrumData& a, const SpectrumData& b) { return a.timestamp < b.timestamp; }); } // 2-9次能谱符合处理 bool ProcessCoincidence( std::vector& data, std::vector& events, unsigned int time_window, int min_order, int max_order ) { int n = data.size(); if (n < min_order) { return false; } // 使用滑动窗口寻找符合事件 for (int i = 0; i < n; ++i) { std::vector current_coincidence; current_coincidence.push_back(data[i]); // 寻找时间窗口内的其他事件 for (int j = i + 1; j < n; ++j) { unsigned long long time_diff = data[j].timestamp - data[i].timestamp; if (time_diff > time_window) { break; // 由于已排序,后续事件时间差会更大 } current_coincidence.push_back(data[j]); // 达到最大符合次数时停止当前窗口 if (current_coincidence.size() >= max_order) { break; } } // 保存符合条件的事件 int coincidence_order = current_coincidence.size(); if (coincidence_order >= min_order && coincidence_order <= max_order) { CoincidenceEvent result; result.coincidence_order = coincidence_order; result.events = current_coincidence; result.time_window = time_window; events.push_back(result); } } return true; } // 统计符合事件结果 arma::mat AnalyzeCoincidenceResults(const std::vector& results, int max_order) { // 统计各粒子数符合事件的数量和能量信息 arma::mat stats(max_order + 1, 2, arma::fill::zeros); // 列:符合粒子数、事件数量 for (const auto& event : results) { int order = event.coincidence_order; stats(order, 0) = order; stats(order, 1) += 1; } return stats; } // 保存结果到文件 void SaveResults( const std::vector& results, const arma::mat& stats, const std::string& base_filename) { // 保存详细符合事件 std::ofstream detail_file(base_filename + "_detail.csv"); detail_file << "符合次数,时间窗口(ns),板卡号_通道号,能量,时间戳\n"; for (const auto& event : results) { for (size_t i = 0; i < event.events.size(); ++i) { const auto& data = event.events[i]; detail_file << event.coincidence_order << "," << event.time_window << "," << data.board_id << "_" << data.channel_id << "," << data.energy << "," << std::fixed << data.timestamp << "\n"; } } detail_file.close(); // 保存统计结果 std::ofstream stats_file(base_filename + "_stats.csv"); stats_file << "符合次数,事件数量\n"; for (int i = 2; i < stats.n_rows; ++i) { if (stats(i, 1) > 0) { stats_file << (int)stats(i, 0) << "," << (int)stats(i, 1) << "\n"; } } stats_file.close(); std::cout << "结果已保存到:" << base_filename << "_detail.csv 和 " << base_filename << "_stats.csv" << std::endl; } } }