You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在MATLAB中用scatteredInterpolant保留数据的垂直突变?

解决MATLAB中含气液突变的散乱点插值问题

方法1:自动微调重复点避免合并

思路

针对每个气液分界的重复(x,y)点,将液相点的x坐标轻微偏移,并用同y下相邻液相点的线性插值结果填充偏移点的数值——既消除了scatteredInterpolant会自动合并的重复点,又能保留突变的陡度。

代码实现

% 构造示例数据
data = table(...
    [1;2;3;3;4;5;1;2;3.1;3.1;4;5;1;2;3.3;3.3;4;5], ...
    [2;2;2;2;2;2;3;3;3;3;3;3;4;4;4;4;4;4], ...
    [10;11;10.5;200;202;203;9;9.9;10.8;195;199;201.5;8.9;9.5;10.2;185;191;199], ...
    categorical(["liquid";"liquid";"liquid";"gaseous";"gaseous";"gaseous";...
                "liquid";"liquid";"liquid";"gaseous";"gaseous";"gaseous";...
                "liquid";"liquid";"liquid";"gaseous";"gaseous";"gaseous"]), ...
    'VariableNames', {'x','y','values','state'});

delta = 1e-4; % 自定义x偏移量,数值越小突变越陡
processed_data = data;

% 按y分组处理每个气液分界点
y_groups = unique(data.y);
for y = y_groups
    y_data = data(data.y == y, :);
    y_data_sorted = sortrows(y_data, 'x');
    
    % 找出当前y下的重复x值(气液分界点)
    [unique_x, ~, idx] = unique(y_data_sorted.x);
    duplicate_x = unique_x(histcounts(idx) > 1);
    
    for x0 = duplicate_x
        liquid_row = y_data_sorted((y_data_sorted.x == x0) & (y_data_sorted.state == "liquid"), :);
        if ~isempty(liquid_row)
            % 获取当前y下液相中x小于x0的最后一个点
            liquid_points = y_data_sorted(y_data_sorted.state == "liquid", :);
            prev_idx = find(liquid_points.x < x0, 1, 'last');
            if ~isempty(prev_idx)
                prev_x = liquid_points.x(prev_idx);
                prev_v = liquid_points.values(prev_idx);
                % 线性插值计算偏移点的数值
                new_x = x0 - delta;
                new_v = prev_v + (liquid_row.values - prev_v) * (new_x - prev_x)/(x0 - prev_x);
                
                % 替换原始液相点
                processed_data(processed_data.x == x0 & processed_data.y == y & processed_data.state == "liquid", :) = ...
                    table(new_x, y, new_v, categorical("liquid"), 'VariableNames', {'x','y','values','state'});
            end
        end
    end
end

% 创建插值函数
F = scatteredInterpolant(processed_data.x, processed_data.y, processed_data.values, 'linear');

% 测试插值效果
test_x = linspace(2.5, 3.5, 100);
test_y = 3*ones(size(test_x));
test_v = F(test_x, test_y);

plot(test_x, test_v, '-b', 'LineWidth', 1.2);
hold on;
plot(data.x(data.y==3), data.values(data.y==3), 'ro', 'MarkerSize', 6);
xlabel('x'); ylabel('流体属性值');
title('y=3处的插值结果');
hold off;

方法2:分状态插值+气液界面拟合(更符合物理逻辑)

思路

将液相、气相数据分开构建插值函数,先拟合气液界面的x随y变化的关系,查询时根据点的位置选择对应状态的插值结果;还可自定义过渡区,实现平滑的陡升效果而非完全垂直突变。

代码实现

% 构造示例数据(同方法1)
data = table(...
    [1;2;3;3;4;5;1;2;3.1;3.1;4;5;1;2;3.3;3.3;4;5], ...
    [2;2;2;2;2;2;3;3;3;3;3;3;4;4;4;4;4;4], ...
    [10;11;10.5;200;202;203;9;9.9;10.8;195;199;201.5;8.9;9.5;10.2;185;191;199], ...
    categorical(["liquid";"liquid";"liquid";"gaseous";"gaseous";"gaseous";...
                "liquid";"liquid";"liquid";"gaseous";"gaseous";"gaseous";...
                "liquid";"liquid";"liquid";"gaseous";"gaseous";"gaseous"]), ...
    'VariableNames', {'x','y','values','state'});

% 提取气液界面点
interface_points = [];
y_groups = unique(data.y);
for y = y_groups
    y_data = data(data.y == y, :);
    x0 = unique(y_data.x(histcounts(y_data.x) > 1));
    interface_points = [interface_points; y, x0];
end
interface_points = interface_points(~isnan(interface_points(:,2)), :);

% 拟合气液界面x(y)(线性拟合,若界面复杂可换散乱点插值)
p = polyfit(interface_points(:,1), interface_points(:,2), 1);
x_interface = @(y) polyval(p, y);

% 分别创建液相、气相插值函数
liquid_data = data(data.state == "liquid", :);
F_liquid = scatteredInterpolant(liquid_data.x, liquid_data.y, liquid_data.values, 'linear');

gaseous_data = data(data.state == "gaseous", :);
F_gaseous = scatteredInterpolant(gaseous_data.x, gaseous_data.y, gaseous_data.values, 'linear');

% 定义带平滑过渡的混合插值函数
delta = 0.01; % 过渡区宽度,数值越小突变越陡
F_mixed = @(x,y) arrayfun(@(xi,yi) ...
    if xi < x_interface(yi) - delta
        F_liquid(xi,yi)
    elseif xi > x_interface(yi) + delta
        F_gaseous(xi,yi)
    else
        % 过渡区线性混合
        frac = (xi - (x_interface(yi)-delta))/(2*delta);
        F_liquid(xi,yi)*(1-frac) + F_gaseous(xi,yi)*frac
    end, x, y);

% 测试插值效果
test_x = linspace(2.5, 3.5, 100);
test_y = 3*ones(size(test_x));
test_v = F_mixed(test_x, test_y);

plot(test_x, test_v, '-b', 'LineWidth', 1.2);
hold on;
plot(data.x(data.y==3), data.values(data.y==3), 'ro', 'MarkerSize', 6);
plot(x_interface(3), F_liquid(x_interface(3),3), 'go', 'MarkerSize', 8, 'DisplayName', '气液界面');
legend;
xlabel('x'); ylabel('流体属性值');
title('y=3处的混合插值结果');
hold off;

关于groupsummary的说明

groupsummary用于分组统计(如求均值、求和),无法保留气液分界的双值特性,完全不适合你的场景,无需尝试使用。

内容的提问来源于stack exchange,提问作者ManyQuestions

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 04:24:55