function radar_signal_sorting_gui()
% 雷达信号分选算法主界面
% 创建一个GUI界面,让用户选择使用SDIF或CDIF算法进行信号分选
% 创建主选择界面
mainFig = figure('Name', '雷达信号分选算法', 'NumberTitle', 'off', ...
'Position', [300, 200, 400, 250], 'MenuBar', 'none', ...
'Resize', 'off', 'Color', [0.95, 0.95, 0.95]);
% 添加标题
uicontrol('Style', 'text', 'String', '请选择分选算法', ...
'Position', [100, 180, 200, 40], ...
'FontSize', 16, 'FontWeight', 'bold', ...
'BackgroundColor', [0.95, 0.95, 0.95]);
% SDIF算法按钮
uicontrol('Style', 'pushbutton', 'String', 'SDIF 算法', ...
'Position', [100, 120, 200, 40], ...
'FontSize', 14, 'FontWeight', 'bold', ...
'BackgroundColor', [0.4, 0.8, 1.0], ...
'Callback', @sdif_callback);
% CDIF算法按钮
uicontrol('Style', 'pushbutton', 'String', 'CDIF 算法', ...
'Position', [100, 60, 200, 40], ...
'FontSize', 14, 'FontWeight', 'bold', ...
'BackgroundColor', [1.0, 0.8, 0.4], ...
'Callback', @cdif_callback);
% SDIF算法回调函数
function sdif_callback(~, ~)
close(mainFig); % 关闭主界面
sdif_gui(); % 打开SDIF参数设置界面
end
% CDIF算法回调函数
function cdif_callback(~, ~)
close(mainFig); % 关闭主界面
CDIF_GUI(); % 打开CDIF参数设置界面
end
end
function sdif_gui()
% SDIF算法参数设置界面
% 允许用户设置SDIF算法的各项参数
fig = figure('Name', 'SDIF参数设置', 'NumberTitle', 'off', ...
'Position', [300, 200, 500, 500], 'MenuBar', 'none', ...
'Color', [0.95, 0.95, 0.95]);
% 默认参数值
defaultParams = struct(...
'filename', 'PDW2.txt', ... % 数据文件名
'bin_size', 5, ... % 直方图箱大小(µs)
'max_interval', 1200, ... % 最大间隔(µs)
'A', 0.4, ... % 门限参数A
'lambda', 0.25, ... % 脉冲流密度λ
'max_order', 8, ... % 最大直方图阶数
'tolerance', 3, ... % 容差范围(µs)
'min_seq_length', 5 ... % 序列最小长度
);
% 界面标题
uicontrol('Style', 'text', 'String', 'SDIF参数配置', ...
'Position', [150, 450, 200, 30], ...
'FontSize', 16, 'FontWeight', 'bold', ...
'BackgroundColor', [0.95, 0.95, 0.95]);
% 创建参数输入控件
params = fieldnames(defaultParams);
yPos = 400; % 初始Y坐标
controls = struct(); % 存储控件句柄
for i = 1:length(params)
param = params{i};
value = defaultParams.(param);
% 参数标签
uicontrol('Style', 'text', 'String', [strrep(param, '_', ' '), ':'], ...
'Position', [50, yPos, 150, 25], ...
'HorizontalAlignment', 'left', ...
'FontSize', 12, ...
'BackgroundColor', [0.95, 0.95, 0.95]);
% 参数输入框
if isnumeric(value)
valueStr = num2str(value);
else
valueStr = value;
end
ctrl = uicontrol('Style', 'edit', ...
'String', valueStr, ...
'Position', [220, yPos, 150, 25], ...
'FontSize', 11, ...
'Tag', param);
controls.(param) = ctrl;
yPos = yPos - 40; % 下移位置
end
% 文件浏览按钮
uicontrol('Style', 'pushbutton', 'String', '浏览...', ...
'Position', [380, 400, 80, 25], ...
'FontSize', 10, ...
'Callback', @browseFile);
% 运行分析按钮
uicontrol('Style', 'pushbutton', 'String', '运行 SDIF 分析', ...
'Position', [150, 50, 200, 40], ...
'FontSize', 14, 'FontWeight', 'bold', ...
'BackgroundColor', [0.4, 0.8, 0.4], ...
'Callback', @runAnalysis);
% 返回主菜单按钮
uicontrol('Style', 'pushbutton', 'String', '返回主菜单', ...
'Position', [20, 20, 100, 30], ...
'Callback', @returnToMain);
% 文件浏览回调函数
function browseFile(~, ~)
[file, path] = uigetfile('*.txt', '选择数据文件');
if file
set(controls.filename, 'String', fullfile(path, file));
end
end
% 运行分析回调函数
function runAnalysis(~, ~)
% 获取用户输入的参数值
params = struct();
paramNames = fieldnames(defaultParams);
for i = 1:length(paramNames)
name = paramNames{i};
strVal = get(controls.(name), 'String');
if strcmp(name, 'filename')
params.(name) = strVal; % 文件名直接使用字符串
else
params.(name) = str2double(strVal); % 其他参数转换为数值
end
end
% 验证文件是否存在
if ~isfile(params.filename)
errordlg('数据文件不存在!', '文件错误');
return;
end
try
% 运行SDIF算法
[sequences, pris, remaining_toa] = run_sdif(...
params.filename, ...
params.bin_size, ...
params.max_interval, ...
params.A, ...
params.lambda, ...
params.max_order, ...
params.tolerance, ...
params.min_seq_length);
% 显示结果
show_sdif_results(sequences, pris, remaining_toa);
catch ME
% 错误处理
errordlg(sprintf('分析错误: %s', ME.message), '分析错误');
end
end
% 返回主菜单回调函数
function returnToMain(~, ~)
close(fig); % 关闭当前界面
radar_signal_sorting_gui(); % 重新打开主界面
end
end
function [sequences, pris, remaining_toa] = run_sdif(filename, bin_size, max_interval, A, lambda, max_order, tolerance, min_seq_length)
% SDIF算法核心执行函数
% 读取数据文件并执行SDIF分选算法
% 读取数据文件
fid = fopen(filename, 'r');
data = textscan(fid, '%f %f %f %f %f');
fclose(fid);
data = [data{1}, data{2}, data{3}, data{4}, data{5}];
% 提取到达时间(TOA)并排序
toa = data(:, 4);
[toa_sorted, sort_idx] = sort(toa);
data_sorted = data(sort_idx, :);
% 计算直方图箱数
num_bins = floor(max_interval / bin_size);
% 执行SDIF核心算法
[sequences, pris, remaining_toa] = sdif_core(...
toa_sorted, bin_size, max_interval, num_bins, ...
A, lambda, max_order, tolerance, min_seq_length);
end
function show_sdif_results(sequences, pris, remaining_toa)
% 显示SDIF分选结果
% 创建结果展示界面,包含表格和多种图表
fig = figure('Name', 'SDIF分选结果', 'NumberTitle', 'off', ...
'Position', [300, 50, 1200, 800], 'MenuBar', 'none');
% 结果摘要面板
summaryPanel = uipanel('Title', '分选结果摘要', 'Position', [0.02, 0.85, 0.96, 0.13], ...
'FontSize', 12, 'FontWeight', 'bold');
% 计算统计信息
totalPulses = sum(cellfun(@length, sequences)) + length(remaining_toa);
extracted = length(pris(pris>0)); % 提取的有效序列数
% 显示摘要信息
uicontrol('Parent', summaryPanel, 'Style', 'text', ...
'String', sprintf('提取序列数: %d | 总脉冲数: %d | 剩余脉冲: %d', ...
extracted, totalPulses, length(remaining_toa)), ...
'Position', [20, 40, 900, 30], ...
'FontSize', 14, 'FontWeight', 'bold', ...
'HorizontalAlignment', 'left');
% 结果表格
resultTable = uitable(fig, 'Position', [50, 450, 1100, 150], ...
'ColumnName', {'序列ID', 'PRI(μs)', '脉冲数', '起始时间(μs)', '结束时间(μs)'}, ...
'ColumnWidth', {120, 210, 210, 240, 240}, ...
'FontSize', 12);
% 填充表格数据
tableData = cell(length(sequences), 5);
for i = 1:length(sequences)
seq = sequences{i};
% 处理未知PRI值
pri_val = ifelse(pris(i)>0, sprintf('%.1f', pris(i)), '未知');
tableData{i,1} = i;
tableData{i,2} = pri_val;
tableData{i,3} = length(seq);
tableData{i,4} = min(seq);
tableData{i,5} = max(seq);
end
set(resultTable, 'Data', tableData);
% 创建选项卡组
tabGroup = uitabgroup(fig, 'Position', [0.05, 0.05, 0.9, 0.5]);
% 选项卡1: 序列脉冲分布
tab1 = uitab(tabGroup, 'Title', '序列脉冲分布');
ax1 = axes('Parent', tab1);
hold(ax1, 'on');
grid(ax1, 'on');
% 为每个序列分配不同颜色
colors = lines(length(sequences));
% 绘制每个序列的脉冲分布
for i = 1:length(sequences)
seq = sequences{i};
y_pos = i * ones(size(seq));
scatter(ax1, seq, y_pos, 40, colors(i,:), 'filled');
plot(ax1, seq, y_pos, 'Color', colors(i,:), 'LineWidth', 1.5);
% 添加序列信息标注
if pris(i) > 0
text(ax1, min(seq), i+0.3, sprintf('序列%d: PRI=%.1fµs', i, pris(i)), ...
'Color', colors(i,:), 'FontSize', 10);
end
end
% 绘制未分选脉冲
if ~isempty(remaining_toa)
y_pos = (length(sequences)+1) * ones(size(remaining_toa));
scatter(ax1, remaining_toa, y_pos, 40, [0.8 0.2 0.2], 'filled');
text(ax1, min(remaining_toa), length(sequences)+1.3, '未分选脉冲', ...
'Color', [0.8 0.2 0.2], 'FontSize', 10);
end
% 设置坐标轴范围
ylim(ax1, [0, length(sequences)+2]);
xlabel(ax1, '到达时间(TOA, µs)');
ylabel(ax1, '信号序列');
title(ax1, '脉冲序列分布');
% 选项卡2: 脉冲数量统计
tab2 = uitab(tabGroup, 'Title', '脉冲数量统计');
ax2 = axes('Parent', tab2);
% 计算每个序列的脉冲数量
pulseCounts = cellfun(@length, sequences);
validSeqs = find(pris > 0); % 只统计有效序列
% 绘制条形图
bar(ax2, validSeqs, pulseCounts(validSeqs), 'FaceColor', [0.3, 0.6, 0.9]);
% 添加数量标签
for i = 1:length(validSeqs)
text(ax2, validSeqs(i), pulseCounts(validSeqs(i))+0.5, ...
num2str(pulseCounts(validSeqs(i))), ...
'HorizontalAlignment', 'center', 'FontSize', 10);
end
xlabel(ax2, '序列ID');
ylabel(ax2, '脉冲数量');
title(ax2, '各序列脉冲数量统计');
grid(ax2, 'on');
set(ax2, 'XTick', validSeqs);
% 选项卡3: PRI分布
tab3 = uitab(tabGroup, 'Title', 'PRI分布');
ax3 = axes('Parent', tab3);
% 提取有效PRI值
valid_pris = pris(pris > 0);
if ~isempty(valid_pris)
% 绘制直方图
hist(ax3, valid_pris, 20);
xlabel(ax3, 'PRI值(µs)');
ylabel(ax3, '出现次数');
title(ax3, '提取的PRI值分布');
grid(ax3, 'on');
else
% 无有效PRI时显示提示
text(ax3, 0.5, 0.5, '未检测到有效PRI', ...
'HorizontalAlignment', 'center', 'FontSize', 14);
end
% 返回主菜单按钮
uicontrol('Style', 'pushbutton', 'String', '返回主菜单', ...
'Position', [50, 20, 120, 30], ...
'Callback', @returnToMain);
% 返回主菜单回调函数
function returnToMain(~, ~)
close(fig); % 关闭结果界面
radar_signal_sorting_gui(); % 重新打开主界面
end
end
% 条件判断辅助函数
function s = ifelse(condition, true_str, false_str)
if condition
s = true_str;
else
s = false_str;
end
end
% SDIF核心算法实现
function [sequences, pris, remaining_toa] = sdif_core(...
toa_data, bin_size, max_interval, num_bins, ...
A, lambda, max_order, tolerance, min_seq_length)
% 初始化变量
n_pulses = length(toa_data);
pulse_mask = true(n_pulses, 1); % 脉冲掩码,标记哪些脉冲未被分选
sequences = {}; % 存储分选出的序列
pris = []; % 存储每个序列的PRI值
iteration = 0; % 迭代计数器
% 主循环:当剩余脉冲数足够时分选
while nnz(pulse_mask) >= min_seq_length
iteration = iteration + 1;
current_toa = toa_data(pulse_mask); % 当前未被分选的脉冲
n_current = length(current_toa);
found_sequence = false; % 标记是否找到序列
% 遍历不同阶数
for order = 1:max_order
% 检查脉冲数量是否足够
if n_current < order + 1
continue;
end
% 计算间隔差
if order == 1
% 一阶:连续脉冲间的间隔
intervals = current_toa(2:end) - current_toa(1:end-1);
else
% 高阶:间隔order个脉冲的间隔差
intervals = current_toa(order+1:end) - current_toa(1:end-order);
end
% 计算直方图
[hist_counts, bin_edges] = histcounts(intervals, num_bins, 'BinLimits', [0, max_interval]);
bin_centers = bin_edges(1:end-1) + bin_size/2;
% 计算SDIF门限
E = n_current; % 当前脉冲数量
C = order; % 当前阶数
threshold_values = A * (E - C) * exp(-lambda * bin_centers);
% 找出超过门限的箱
exceed_idx = find(hist_counts > threshold_values);
if ~isempty(exceed_idx)
% 选择PRI候选值
if order == 1
if numel(exceed_idx) == 1
pri_candidate = bin_centers(exceed_idx(1));
else
% 多个候选时选择最小PRI(子谐波检验)
[min_pri, min_idx] = min(bin_centers(exceed_idx));
pri_candidate = min_pri;
end
else
% 高阶选择最小PRI
[min_pri, min_idx] = min(bin_centers(exceed_idx));
pri_candidate = min_pri;
end
% 搜索序列
[seq_found, seq_idx] = find_sequence_sdif(...
current_toa, pri_candidate, tolerance, min_seq_length);
if seq_found
% 转换为全局索引
global_idx = find(pulse_mask);
global_seq_idx = global_idx(seq_idx);
% 保存序列
sequences{end+1} = current_toa(seq_idx);
pris(end+1) = pri_candidate;
% 更新脉冲掩码
pulse_mask(global_seq_idx) = false;
found_sequence = true;
break; % 找到序列后跳出阶数循环
end
end
end
% 未找到新序列时终止分选
if ~found_sequence
break;
end
end
% 处理剩余脉冲
remaining_toa = toa_data(pulse_mask);
if ~isempty(remaining_toa)
sequences{end+1} = remaining_toa;
pris(end+1) = 0; % 未知PRI
end
end
% 查找序列函数
function [found, seq_indices] = find_sequence_sdif(toa, pri, tolerance, min_length)
% 使用动态规划算法查找最长的连续序列
n = length(toa);
dp = ones(1, n); % dp[i]表示以第i个脉冲结尾的序列长度
prev = zeros(1, n); % 前驱指针,记录序列中的前一个脉冲
max_len = 1; % 最长序列长度
max_idx = 1; % 最长序列的结束位置
% 动态规划填表
for i = 2:n
dp(i) = 1;
prev(i) = 0;
% 检查所有可能的j
for j = 1:i-1
interval = toa(i) - toa(j);
% 检查间隔是否在容差范围内
if abs(interval - pri) <= tolerance
% 更新序列长度
if dp(j) + 1 > dp(i)
dp(i) = dp(j) + 1;
prev(i) = j;
end
end
end
% 更新最长序列信息
if dp(i) > max_len
max_len = dp(i);
max_idx = i;
end
end
% 检查序列是否满足最小长度要求
if max_len >= min_length
found = true;
seq_indices = [];
current = max_idx;
% 回溯重建序列
while current > 0
seq_indices = [current, seq_indices];
current = prev(current);
end
else
found = false;
seq_indices = [];
end
end
function CDIF_GUI()
% CDIF算法主界面
% 提供参数设置和结果展示功能
fig = figure('Name', 'CDIF脉冲序列分析', 'NumberTitle', 'off', ...
'Position', [200, 100, 1000, 700], 'MenuBar', 'none', ...
'Resize', 'on');
% 参数控制面板
controlPanel = uipanel(fig, 'Title', '参数控制', ...
'Position', [0.02, 0.02, 0.96, 0.96], ...
'FontSize', 14, 'FontWeight', 'bold');
% 默认参数值
defaultParams = struct(...
'filename', 'PDW1.txt', ... % 数据文件名
'max_level', 2, ... % 最大分析层级
'a', 0.4, ... % 门限参数a
'tolerance', 0.01, ... % 容差
'min_pulse_sequence', 5, ... % 最小脉冲序列长度
'min_total_pulses', 0 ... % 最小总脉冲数
);
% 文件选择控件
uicontrol(controlPanel, 'Style', 'text', 'String', '数据文件:', ...
'Units', 'normalized', 'Position', [0.05, 0.85, 0.15, 0.05], ...
'HorizontalAlignment', 'left', 'FontSize', 12);
fileEdit = uicontrol(controlPanel, 'Style', 'edit', ...
'String', defaultParams.filename, ...
'Units', 'normalized', 'Position', [0.20, 0.85, 0.45, 0.05], ...
'FontSize', 12);
uicontrol(controlPanel, 'Style', 'pushbutton', 'String', '浏览...', ...
'Units', 'normalized', 'Position', [0.70, 0.85, 0.15, 0.05], ...
'FontSize', 12, ...
'Callback', @(src,evt) browseFile(fileEdit));
% 参数输入控件
params = fieldnames(defaultParams);
paramControls = struct();
paramControls.filename = fileEdit;
paramYPos = 0.75; % 初始Y坐标
paramSpacing = 0.08; % 控件间距
% 创建参数控件
for i = 2:length(params)
paramName = params{i};
paramValue = defaultParams.(paramName);
% 参数标签
uicontrol(controlPanel, 'Style', 'text', ...
'String', [replace(paramName, '_', ' '), ':'], ...
'Units', 'normalized', 'Position', [0.05, paramYPos, 0.25, 0.05], ...
'HorizontalAlignment', 'left', 'FontSize', 12);
% 整数参数使用编辑框
if ismember(paramName, {'max_level', 'min_pulse_sequence', 'min_total_pulses'})
paramControls.(paramName) = uicontrol(controlPanel, 'Style', 'edit', ...
'String', num2str(paramValue), ...
'Units', 'normalized', 'Position', [0.35, paramYPos, 0.15, 0.05], ...
'Tag', paramName, 'FontSize', 12);
else
% 浮点参数使用编辑框+滑块
paramControls.(paramName) = uicontrol(controlPanel, 'Style', 'edit', ...
'String', num2str(paramValue), ...
'Units', 'normalized', 'Position', [0.35, paramYPos, 0.15, 0.05], ...
'Tag', paramName, 'FontSize', 12);
% 添加滑块
uicontrol(controlPanel, 'Style', 'slider', ...
'Min', 0, 'Max', 1, ...
'Value', paramValue, ...
'Units', 'normalized', 'Position', [0.55, paramYPos, 0.30, 0.05], ...
'Tag', [paramName, 'Slider'], ...
'Callback', @(src,evt) sliderCallback(src, paramName, paramControls.(paramName)));
end
paramYPos = paramYPos - paramSpacing; % 下移位置
end
% 运行分析按钮
uicontrol(controlPanel, 'Style', 'pushbutton', 'String', '运行分析', ...
'Units', 'normalized', 'Position', [0.35, 0.05, 0.30, 0.08], ...
'FontWeight', 'bold', 'FontSize', 14, ...
'Callback', @(src,evt) runAnalysis(fig, paramControls));
% 文件浏览回调函数
function browseFile(editControl)
[file, path] = uigetfile('*.txt', '选择数据文件');
if file
set(editControl, 'String', fullfile(path, file));
end
end
% 滑块回调函数
function sliderCallback(src, paramName, editControl)
value = get(src, 'Value');
set(editControl, 'String', num2str(value));
end
% 运行分析回调函数
function runAnalysis(fig, paramControls)
% 获取参数值
filename = get(paramControls.filename, 'String');
max_level = str2double(get(paramControls.max_level, 'String'));
a = str2double(get(paramControls.a, 'String'));
tolerance = str2double(get(paramControls.tolerance, 'String'));
min_pulse_sequence = str2double(get(paramControls.min_pulse_sequence, 'String'));
min_total_pulses = str2double(get(paramControls.min_total_pulses, 'String'));
% 验证参数有效性
if isnan(max_level) || max_level < 1 || max_level > 10
errordlg('最大层级必须为1-10之间的整数', '参数错误');
return;
end
if isnan(a) || a < 0 || a > 1
errordlg('门限参数a必须在0-1范围内', '参数错误');
return;
end
% 删除现有结果面板(如果存在)
if ishandle(findobj(fig, 'Tag', 'resultPanel'))
delete(findobj(fig, 'Tag', 'resultPanel'));
end
try
% 运行CDIF分析
[all_sequences, all_pri, remaining_toa, all_seq_cdif_data] = ...
optimized_CDIF(filename, max_level, a, tolerance, min_pulse_sequence, min_total_pulses);
% 创建结果面板
resultPanel = uipanel(fig, 'Title', '分析结果', ...
'Position', [0.02, 0.02, 0.96, 0.96], ...
'Units', 'normalized', ...
'Tag', 'resultPanel', ...
'FontSize', 14, 'FontWeight', 'bold');
% 添加返回按钮
uicontrol(resultPanel, 'Style', 'pushbutton', 'String', '返回控制面板', ...
'Units', 'normalized', 'Position', [0.01, 0.01, 0.15, 0.04], ...
'FontSize', 12, ...
'Callback', @(src,evt) delete(resultPanel));
% 创建结果表格
resultTable = uitable(resultPanel, 'Units', 'normalized', ...
'Position', [0.02, 0.75, 0.96, 0.23], ...
'ColumnName', {'序列ID', 'PRI (μs)', '脉冲数量', '分析层级'}, ...
'ColumnFormat', {'numeric', 'numeric', 'numeric', 'numeric'}, ...
'ColumnWidth', {220, 220, 250, 200}, ...
'Tag', 'resultTable', ...
'FontSize', 12);
% 显示结果摘要
summaryStr = sprintf('提取序列总数: %d | 剩余脉冲数: %d', ...
length(all_sequences), length(remaining_toa));
uicontrol(resultPanel, 'Style', 'text', ...
'Units', 'normalized', ...
'Position', [0.02, 0.70, 0.96, 0.05], ...
'String', summaryStr, ...
'FontSize', 14, 'FontWeight', 'bold', ...
'HorizontalAlignment', 'left');
% 更新结果表格数据
if ~isempty(all_sequences)
resultData = cell(length(all_sequences), 4);
for i = 1:length(all_sequences)
resultData{i,1} = i; % 序列ID
resultData{i,2} = all_pri(i); % PRI
resultData{i,3} = length(all_sequences{i}); % 脉冲数量
% 查找分析层级
level_found = 0;
for lvl = 1:length(all_seq_cdif_data)
if lvl <= length(all_seq_cdif_data) && ...
~isempty(all_seq_cdif_data{lvl}) && ...
any([all_seq_cdif_data{lvl}.seq_id] == i)
resultData{i,4} = lvl;
level_found = 1;
break;
end
end
if ~level_found
resultData{i,4} = '未知';
end
end
else
resultData = {};
end
set(resultTable, 'Data', resultData);
% 创建图形面板 - 使用选项卡
tabGroup = uitabgroup(resultPanel, 'Units', 'normalized', ...
'Position', [0.02, 0.05, 0.96, 0.65]);
% CDIF分析结果选项卡
cdifTab = uitab(tabGroup, 'Title', 'CDIF分析结果');
% 序列脉冲统计选项卡
pulseTab = uitab(tabGroup, 'Title', '序列脉冲统计');
% 创建CDIF分析结果图
if ~isempty(all_seq_cdif_data)
% 计算实际有数据的层级
valid_levels = sum(~cellfun(@isempty, all_seq_cdif_data));
if valid_levels > 0
% 计算网格布局(每行最多2列)
grid_cols = min(2, valid_levels);
grid_rows = ceil(valid_levels / grid_cols);
level_counter = 1;
for lvl = 1:length(all_seq_cdif_data)
if ~isempty(all_seq_cdif_data{lvl})
% 创建坐标轴
ax = subplot(grid_rows, grid_cols, level_counter, 'Parent', cdifTab);
set(ax, 'Tag', ['axes', num2str(lvl)], 'FontSize', 12);
% 绘制该层级的CDIF结果
plot_combined_cdif_gui(all_seq_cdif_data{lvl}, lvl, ax);
level_counter = level_counter + 1;
end
end
end
else
% 无CDIF数据时显示提示
uicontrol(cdifTab, 'Style', 'text', 'String', '未找到CDIF分析数据', ...
'Units', 'normalized', 'Position', [0.3, 0.5, 0.4, 0.1], ...
'FontSize', 14, 'FontWeight', 'bold');
end
% 创建序列脉冲统计图
if ~isempty(all_sequences)
axHist = axes('Parent', pulseTab, 'FontSize', 12);
% 获取序列ID和脉冲数量
seqIds = 1:length(all_sequences);
pulseCounts = cellfun(@length, all_sequences);
% 绘制条形图
bar(axHist, seqIds, pulseCounts, 'FaceColor', [0.3, 0.6, 0.9]);
% 添加数值标签
for i = 1:length(seqIds)
text(axHist, seqIds(i), pulseCounts(i)+0.1, num2str(pulseCounts(i)), ...
'HorizontalAlignment', 'center', 'FontSize', 12);
end
title(axHist, '序列脉冲数量统计', 'FontSize', 14);
xlabel(axHist, '序列ID', 'FontSize', 12);
ylabel(axHist, '脉冲数量', 'FontSize', 12);
grid(axHist, 'on');
set(axHist, 'XTick', seqIds);
else
% 无有效序列时显示提示
uicontrol(pulseTab, 'Style', 'text', 'String', '未找到有效序列', ...
'Units', 'normalized', 'Position', [0.3, 0.5, 0.4, 0.1], ...
'FontSize', 14, 'FontWeight', 'bold');
end
catch ME
% 错误处理
errordlg(sprintf('分析错误: %s', ME.message), '分析错误');
end
end
% CDIF结果绘图函数
function plot_combined_cdif_gui(cdif_data, level, ax)
axes(ax); % 设置当前坐标轴
cla(ax); % 清除原有内容
% 获取最大PRI范围和最大直方图值
max_pri_len = max(arrayfun(@(x) length(x.hist), cdif_data));
max_hist_val = max(arrayfun(@(x) max(x.hist), cdif_data));
% 创建颜色映射
colors = lines(length(cdif_data));
hold(ax, 'on');
% 绘制所有序列的直方图
for i = 1:length(cdif_data)
data = cdif_data(i);
x = 1:length(data.hist);
% 绘制直方图
plot(ax, x, data.hist, 'Color', colors(i, :), 'LineWidth', 1.5, ...
'DisplayName', sprintf('序列%d (PRI=%.1fµs)', data.seq_id, data.pri));
% 找到最接近实际PRI的索引位置
[~, idx] = min(abs(x - data.pri));
peak_value = data.hist(idx);
% 标记检测到的PRI
plot(ax, x(idx), peak_value, 'o', 'MarkerSize', 8, ...
'MarkerFaceColor', colors(i, :), 'MarkerEdgeColor', 'k', ...
'HandleVisibility', 'off');
end
% 绘制统一的门限曲线
if ~isempty(cdif_data)
x_thresh = 1:length(cdif_data(1).threshold);
plot(ax, x_thresh, cdif_data(1).threshold, 'k--', 'LineWidth', 1.5, ...
'DisplayName', '最优门限');
end
hold(ax, 'off');
% 添加图例和标签
title(ax, sprintf('层级 %d CDIF分析', level), 'FontSize', 14);
xlabel(ax, 'PRI (\mu s)', 'FontSize', 12);
ylabel(ax, '累积计数', 'FontSize', 12);
legend(ax, 'show', 'Location', 'best', 'FontSize', 10);
grid(ax, 'on');
% 设置坐标轴范围
xlim(ax, [1, min(max_pri_len, 100000)]); % 限制X轴范围
% 动态设置Y轴范围
if max_hist_val > 0
ylim(ax, [0, max_hist_val * 1.2]); % 基于数据设置Y轴
else
ylim(ax, [0, 10]); % 默认范围
end
% 设置坐标轴字体大小
set(ax, 'FontSize', 12);
end
end
function [all_sequences, all_pri, remaining_toa, all_seq_cdif_data] = optimized_CDIF(filename, max_level, a, tolerance, min_pulse_sequence, min_total_pulses)
% CDIF算法核心实现
% 读取数据并执行CDIF分选算法
% 读取数据
data = load(filename);
toa_original = data(:,4);
toa_original = sort(toa_original); % 排序到达时间
remaining_toa = toa_original; % 剩余脉冲
% 计算总时间范围和最大PRI
T_total = max(toa_original) - min(toa_original);
absolute_max_pri = 1000000; % 1000ms
PRI_max = min(T_total/2, absolute_max_pri);
% 存储结果
all_sequences = {}; % 所有分选出的序列
all_pri = []; % 各序列的PRI值
sequence_counter = 1; % 序列计数器
all_seq_cdif_data = cell(1, max_level); % 各层级的CDIF数据
% 主循环:处理所有序列
while length(remaining_toa) >= min_total_pulses
% 提取下一个序列
[sequence, pri, level, remaining_toa, level_hists] = extract_next_sequence(...
remaining_toa, PRI_max, a, tolerance, ...
min_pulse_sequence, max_level);
if ~isempty(sequence)
% 保存序列信息
all_sequences{end+1} = sequence;
all_pri(end+1) = pri;
% 保存CDIF数据
for lvl = 1:length(level_hists)
level_data = level_hists{lvl};
if lvl <= max_level
if isempty(all_seq_cdif_data{lvl})
all_seq_cdif_data{lvl} = struct(...
'seq_id', sequence_counter, ...
'hist', level_data.hist, ...
'threshold', level_data.threshold, ...
'pri', pri);
else
all_seq_cdif_data{lvl}(end+1) = struct(...
'seq_id', sequence_counter, ...
'hist', level_data.hist, ...
'threshold', level_data.threshold, ...
'pri', pri);
end
end
end
sequence_counter = sequence_counter + 1;
else
break; % 未找到新序列时退出
end
end
end
% 提取下一个序列
function [sequence, pri, level, remaining_toa, level_hists] = extract_next_sequence(...
toa, PRI_max, a, tolerance, min_pulse_sequence, max_level)
level_hists = {}; % 存储各层级直方图
cumulative_hist = []; % 累积直方图
T_total = max(toa) - min(toa); % 当前脉冲流的总时间
% CDIF分析循环 (从1级到max_level)
for current_level = 1:max_level
% 计算当前级别的直方图
[level_hist, thresholds] = compute_level_hist(toa, current_level, PRI_max, T_total, a);
% 累积到前一级的直方图
if isempty(cumulative_hist)
cumulative_hist = level_hist;
else
% 确保直方图长度一致
max_len = max(length(cumulative_hist), length(level_hist));
cumulative_hist(end+1:max_len) = 0;
level_hist(end+1:max_len) = 0;
cumulative_hist = cumulative_hist + level_hist;
end
% 保存当前层级数据
level_data.hist = cumulative_hist;
level_data.threshold = thresholds;
level_hists{end+1} = level_data;
% 寻找候选PRI(高于门限)
candidate_indices = find(cumulative_hist > thresholds);
% 过滤无效PRI候选值
candidate_indices(candidate_indices < 10) = []; % 过滤过小的PRI
candidate_indices(candidate_indices > PRI_max) = []; % 过滤过大的PRI
if ~isempty(candidate_indices)
% 按显著性排序(直方图值降序)
[sorted_values, sort_idx] = sort(cumulative_hist(candidate_indices), 'descend');
candidate_pri = candidate_indices(sort_idx);
% 尝试提取序列
for i = 1:length(candidate_pri)
tolerance_val = candidate_pri(i) * tolerance;
[sequence, new_toa] = extract_sequence(toa, candidate_pri(i), tolerance_val, min_pulse_sequence);
if ~isempty(sequence)
pri = candidate_pri(i);
level = current_level;
remaining_toa = new_toa;
return; % 成功提取序列后返回
end
end
end
end
% 未找到序列
pri = [];
level = [];
sequence = [];
remaining_toa = toa;
level_hists = {};
end
% 计算层级直方图
function [level_hist, thresholds] = compute_level_hist(toa, level, PRI_max, T_total, a)
% 初始化直方图
level_hist = zeros(1, ceil(PRI_max));
% 检查是否有足够脉冲计算当前层级
if length(toa) > level
% 计算当前级别的dTOA(到达时间差)
dtoa = toa(level+1:end) - toa(1:end-level);
% 过滤有效值(在1和PRI_max之间)
valid_indices = (dtoa >= 1) & (dtoa <= PRI_max);
dtoa = dtoa(valid_indices);
% 统计直方图
for i = 1:length(dtoa)
idx = min(ceil(dtoa(i)), length(level_hist)); % 计算索引
if idx > 0
level_hist(idx) = level_hist(idx) + 1; % 增加计数
end
end
end
% 计算最优门限函数 D_{cdif} = a * T / t
t = 1:length(level_hist);
thresholds = a * T_total ./ t;
% 处理除零和无效值
thresholds(isinf(thresholds) | isnan(thresholds)) = max(level_hist);
thresholds(t == 0) = max(level_hist);
% 确保门限不低于最小值
min_threshold = 3; % 最小门限值
thresholds(thresholds < min_threshold) = min_threshold;
end
% 提取序列函数
function [sequence, remaining] = extract_sequence(toa, pri, tolerance_val, min_length)
sequence = [];
remaining = toa;
% 检查是否有足够脉冲
if length(toa) < min_length
return;
end
best_sequence = []; % 最佳序列
best_length = 0; % 最佳序列长度
% 尝试不同的起点(最多尝试20个起点)
for start_idx = 1:min(20, length(toa))
current_sequence = toa(start_idx); % 当前序列
current_time = toa(start_idx); % 当前时间
last_index = start_idx; % 最后索引
lost_count = 0; % 丢失脉冲计数
total_missed = 0; % 总丢失脉冲数
% 向前搜索
for j = (start_idx+1):length(toa)
expected_time = current_time + pri; % 期望到达时间
% 检查当前脉冲是否在期望时间附近
if abs(toa(j) - expected_time) <= tolerance_val
% 添加脉冲到序列
current_sequence(end+1) = toa(j);
current_time = toa(j);
last_index = j;
lost_count = 0; % 重置丢失计数
% 检查是否可能丢失脉冲
elseif toa(j) > expected_time + tolerance_val
% 计算可能丢失的脉冲数
missed_count = floor((toa(j) - expected_time) / pri);
% 检查是否在容差范围内
next_expected = expected_time + missed_count * pri;
if abs(toa(j) - next_expected) <= tolerance_val
% 添加脉冲到序列
current_sequence(end+1) = toa(j);
current_time = toa(j);
last_index = j;
lost_count = lost_count + missed_count;
total_missed = total_missed + missed_count;
else
% 如果脉冲差距太大,可能不是同一个序列
if lost_count >= 2
break;
end
end
end
end
% 检查序列质量
if length(current_sequence) >= min_length
% 计算序列持续时间
duration = current_sequence(end) - current_sequence(1);
% 序列质量标准:
% 1. 序列持续时间至少为2倍PRI
% 2. 丢失脉冲比例不超过50%
if duration >= 2 * pri && (total_missed / length(current_sequence)) <= 0.5
if length(current_sequence) > best_length
best_sequence = current_sequence;
best_length = length(current_sequence);
end
end
end
end
% 验证序列长度
if best_length >= min_length
sequence = best_sequence;
% 从原始TOA中移除序列
[~, idx] = ismember(sequence, toa);
remaining = toa;
remaining(idx) = [];
end
end
分析上述代码的设计思路