
%手动选取峰值区间，需提前输入峰值个数
%自动识别峰波区间，但需要手动选择峰间距
%使用findpeaks函数寻找峰值点，可去除不需要的峰值点
%去除峰波区间进行插值获取基线
%基线校正后的电流数据在y_new，电压数据在x_raw
clear all;
clc;

%% 选择Excel文件,注意文件后缀是.csv
[file, path] = uigetfile('*.xlsx', '选择Excel文件');

if isequal(file, 0)
    disp('未选择任何文件');% 检查用户是否取消选择
else
    % 构建文件路径
    filepath = fullfile(path, file);
    % 读取Excel文件中的数据到data
    data = xlsread(filepath);
end

%% 电压x,电流y初值，初始参数选择
x_raw= data(:, 1);
y_raw= data(:, 2);

windowSize=input('滤波窗口长度选择，不处理选1，建议（5-11）：');%滑动平均参数选择

% 使用smoothdata函数进行滑动平均处理
y_raw1= smoothdata(y_raw, 'movmean', windowSize);
x_raw1=x_raw;%不处理

y=y_raw1;
x=x_raw1;


%% 手动/自动查找峰值
disp('是否自动识别峰值区间');
reply1= input('自动识别选1/手动选取选2：--> ');

%手动选择峰值区间
if reply1 == 2
    peaknumber=input('需要处理的峰值个数：');%峰值个数选择
    n=peaknumber;%峰值个数

    figure(1)
    plot(x, y);
    xlabel('电压');
    ylabel('电流');
    title('点击两个点获取峰波区间的电压范围（从左到右）');
    hold on;

    for i = 1:n

    % 从图中获取两个点的位置
    points = ginput(2);

    % 提取两个点的 x 坐标
    x1(i) = points(1, 1);
    x2(i) = points(2, 1);

    % 根据 x 坐标获取对应的索引
    left_idx(i) = find(x >= x1(i), 1, 'first');
    right_idx(i) = find(x >= x2(i), 1, 'first');

    % 打印位置范围
    disp(['位置范围：', num2str(x_raw(left_idx(i))), ' 到 ', num2str(x_raw(right_idx(i)))]);

    end

elseif reply1 == 1

    % 绘制曲线和峰值
    figure(1);
    plot(x, y);
    title('最小峰距参数选择');
    xlabel('电压');
    ylabel('电流');
    hold on;

    minPeakDistance=input('相邻峰最小间距设置（建议峰值点多0.1,峰值点少0.3）：');%最小峰距参数选择
    minPeakHeight = 0;%峰值最低高度
    [peaks, locs, widths, proms] = findpeaks(y, x, 'MinPeakHeight', minPeakHeight, 'MinPeakDistance', minPeakDistance);

    % 寻找峰区间
    % 遍历每个峰值
    for i = 1:length(peaks)
        % 当前峰值的位置和高度
        peak_pos = find(x >= locs(i), 1, 'first');%找到峰值对应的位置
    
        % 寻找左侧峰谷
        left_idx(i) = peak_pos - 1;
       while left_idx(i) > 3 && y(left_idx(i)) >= y(left_idx(i)-3)  %边界条件&判断条件，-3原因是提高容错性
             left_idx(i) = left_idx(i) - 1;
       end
             leftBound(i) = x(left_idx(i)-1);  %弥补-3，提高准确率
    
       % 寻找右侧峰谷
             right_idx(i) = peak_pos + 1;
       while right_idx(i) < length(y)-4 && y(right_idx(i)) >= y(right_idx(i)+3)  %边界条件&判断条件,+3原因是提高容错性
             right_idx(i) = right_idx(i) + 1;
       end
             rightBound(i) = x(right_idx(i)+1);  %弥补+3，提高准确率

             line([x(left_idx(i)), x(right_idx(i))], [y(left_idx(i)), y(right_idx(i))], 'Color', 'g', 'LineStyle', '--');%显示波形区间
       end

   % 绘制曲线和峰值
   plot(locs, peaks, 'ro');
   hold on;
   %legend('Original Data','peak value','peak range');
   %legend('Location', 'best');
   title('识别峰值与峰区间');
   hold off;

   %去掉不要的峰值点
   rows_to_remove=input('输入不需要的峰值(从左到右)，格式为[x,y]：');%滑动平均参数选择

   left_idx(rows_to_remove) = [];  % 去除指定行的数据
   right_idx(rows_to_remove) = [];  % 去除指定行的数据

else
    disp('未知的命令数值');
    return;
end

%% 基线插值

%去除峰波区间
for i = 1:length(left_idx)
    % 在原始数据中将区间内的数据值设置为 NaN
    x(left_idx(i):right_idx(i)) = NaN;
    y(left_idx(i):right_idx(i)) = NaN;
end
x = x(~isnan(x));% 去除NAN值
y = y(~isnan(y));

Intertype=input('线性插值选1，样条插值选2，最近邻插值选3（建议2）：');%插值方法选择
% 对数据进行插值
if Intertype == 1
    % 线性插值
    yInterpolated = interp1(x, y, x_raw, 'linear');

elseif Intertype == 2
    % 样条插值
    yInterpolated = interp1(x, y, x_raw, 'spline');

elseif Intertype == 3
    % 最相邻插值
    yInterpolated = interp1(x, y, x_raw, 'nearest');

else
    disp('未知的命令数值');
    return;
end

% 绘制原始数据和插值后的曲线
figure(2);
plot(x_raw, y_raw1, 'b-', 'DisplayName', 'Original Data');
hold on;
plot(x_raw, yInterpolated, 'r-', 'DisplayName', 'baseline');
xlabel('电压');
ylabel('电流');
title('原始曲线与基线');
legend('Location', 'best');
hold on;

%% 基线校正
y_new=y_raw1-yInterpolated;% 基线校正

%寻找峰值
num_peaks = length(peaks);
disp('峰值信息（从左到右）：');

for i = 1:length(left_idx);
    peakdata_y=y_new(left_idx(i):right_idx(i));
    peakdata_x=x_raw(left_idx(i):right_idx(i));
    [max_peak, max_index] = max(peakdata_y);%区间内最大的峰值点

    peak_info(i, 1) = max_peak; % 峰值大小
    peak_info(i, 2) = peakdata_x(max_index); % 峰值对应的坐标值

    % 显示多个峰值的大小和对应的坐标值
    disp(['峰波', num2str(i), '：峰值大小=', num2str(peak_info(i, 1)), ', 峰值电压=', num2str(peak_info(i, 2))]);
end

%输出校正后的峰值以及位置图像
figure(3);
plot(x_raw, y_new, 'r-', 'DisplayName', 'baseline correction');
hold on;
%plot(peak_info(:, 2), peak_info(:, 1), 'ro', 'MarkerSize', 10);
xlabel('电压');
ylabel('电流');
title('基线校正后的曲线');
legend('Location', 'best');
