如何在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
相关产品推荐
相关产品推荐

