# Interpolating numerical function of many variables

2 views (last 30 days)
erictoleratesMATLAB on 20 Jan 2023
Hi everyone,
I'm attempting to develop a lookup function/table based on a set of data.
This data describes the measured airflow through a fan as a function of the fan's PWM command and the position of various ducts in the system (airflow = f(PWM,Vent 1 position, Vent 2 position, Vent 3 position, Vent 4 position). This data only exists for configurations where each duct is either open or closed at 100%.
There are 4 ducts, (V, D, F, and S) and I have the airflow values at each combination of ducts open/closed and each PWM command. Assume that when the direction says something like 'V+F+D', all 3 ducts are open at 100%, and if a duct isn't specified (like S in this example) it is fully closed at 0%.
I would like the ability to specify something like (V open at 40%, S open at 20%, D fully closed, F open at 100%, PWM command = 50) and have the output be an interpolated airflow at this set of door conditions. I'm getting stuck trying to format the data in a way that makes the problem solvable. Any advice and tips would be appreciated!
Please find some sample data attached.
Here's what I have so far, but I haven't figured out how to interpolate at vent states I don't yet have data for.
pwm_values = [0, 24, 34, 44, 64, 85]; % [Val out of 85]
duct_openings = {'Off', 'V', 'F', 'D', 'S', 'V+F', 'V+S', 'V+D', 'F+S', 'F+D', 'S+D', 'V+F+S', 'V+F+D', 'V+D+S', 'F+D+S', 'V+F+D+S'};
airflow_matrix = [0 0 0 0 0 0;
0 80.05 96.175 112.6 146.65 171.55;
0 85.75 104.2 122.875 157.975 176.65;
0 92.575 111.1 130.975 165.175 183.625;
0 53.8 64.525 72.85 87.325 97.6;
0 100.975 126.775 154.075 213.55 240.4;
0 80.875 100.975 122.125 160.075 182.125;
0 95.575 121.75 146.875 193.6 226;
0 81.55 101.275 119.725 159.4 179.65;
0 102.55 132.25 160.525 208.825 232.75;
0 93.55 116.725 142.15 1680.4 194.95;
0 106.825 137.95 171.925 226.675 252.175;
0 114.4 147.925 184.525 243.55 271.075;
0 102.55 132.25 160.525 210.775 236.8;
0 97.45 128.425 156.325 210.775 236.8;
0 116.5 150.775 188.125 248.275 276.4;
];
% Create meshgrid of known vals
[X,Y] = meshgrid(pwm_values, 1:size(airflow_matrix,1));
% Transpose to format for griddedInterpolant
X = X';Y = Y';airflow_matrix = airflow_matrix';
% Create lookup entity
F = griddedInterpolant(X,Y,airflow_matrix,'linear');
% Define the PWM value and duct opening combination to test
pwm = 84;
duct_combination = 'V+D+S';
interp_airflow = F([pwm, find(strcmp(duct_openings,duct_combination))])
Torsten on 21 Jan 2023
Edited: Torsten on 21 Jan 2023
For example: What if the opening percentages for the ducts are V=50%,D=50%,F=100%,S=75% and PWM = 34?
And you are optimistic that you can capture such complicated interactions that might occur by percentage openings using a simple interpolation ?
Ok. But then you will have to define V, D, F, S and PWM as independent variables.
What would be an adequate model to get a correlation airflow = f(V,D,F,S,PVM) ?
You have measurements that take interactions between V, D, F and S into account. Thus the model should contain terms
V, D, F, S, V*F, V*S, V*D, F*S, F*D, S*D, V*F*S,V*F*D,V*D*S.
A third-order polynomial of the form
p0*V + p1*D + p2*F + p3*S + p02*V*F + p03*V*S + p01*V*D + p23*F*S + p21*F*D + p31*S*D + p023*V*F*S + p021*V*F*D + p013*V*D*S
comes to mind with coefficients p0,p1,...,p013 to be determined from your measurement data.
But how to integrate PVM here ?

erictoleratesMATLAB on 25 Jan 2023
Hi everyone!
Thank you for your thoughtful answers and responses to my question. I figured out a good solution to this particular problem that address all the key points I originally wanted.
I started by formulating the problem as a matrix problem, attempting to fit a function (CMH) of 5 variables (Door 1, Door 2, Door 3, Door 4, PWM) to the lowest order polynomial that I could reasonably expect to implement (The end goal is to implement this fucntion in C for another personal project).
I treated door 1 (V) as , door 2 (F) as , D as , S as , PWM as and CMH as . I then looped over each CMH value in my matrix, and for that value of CMH () I record the values of each input . When a door position is open, we record it as 1. When the door is closed, we record it at 0. Doing this records every known door state + PWM and the corresponding CMH. The end result is a matrix that looks something like this (the picture is truncated of course, the matrix is much larger):
I then used fitlm to test a bunch of fits, and pick the one that matches the data best with relatively easy implementation. Here are the results:
Here's the code so anyone can try this themselves if they have a similar problem.
% Goal: To obtain airflow = f(PWM,V,D,F,S)
% Where:
% - PWM = PWM Command
% - V = Vent Position (between 0 and 1)
% - F = Foot Position (between 0 and 1)
% - D = Defrost Position (between 0 and 1)
% - S = Seat Position (between 0 and 1)
% - CMH = Measured Airflow through blower [CMH]
clear;close all;clc
%% Hard Code values to be fit
airflow_matrix = [0 0 0 0 0 0
0 93.4 114.9 136.8 182.2 215.4
0 101 125.6 150.5 197.3 222.2
0 110.1 134.8 161.3 206.9 231.5
0 58.4 72.7 83.8 103.1 116.8
0 121.3 155.7 192.1 271.4 307.2
0 94.5 121.3 149.5 200.1 229.5
0 114.1 149 182.5 244.8 288
0 95.4 121.7 146.3 199.2 226.2
0 123.4 163 200.7 265.1 297
0 111.4 142.3 176.2 227.2 246.6
0 129.1 170.6 215.9 288.9 322.9
0 139.2 183.9 232.7 311.4 348.1
0 123.4 163 200.7 267.7 302.4
0 116.6 157.9 195.1 267.7 302.4
0 142 187.7 237.5 317.7 355.2
];
PWM_array = [0, 24, 34, 44, 64, 85];
duct_openings = {'Off', 'V', 'F', 'D', 'S', 'V+F', 'V+S', 'V+D', 'F+S', 'F+D', 'S+D', 'V+F+S', 'V+F+D', 'V+D+S', 'F+D+S', 'V+F+D+S'};
%% Now we try to save them in a productive format
x1 = []; % V
x2 = []; % F
x3 = []; % D
x4 = []; % S
x5 = []; % PWM
CMH = [];% CMH
for i = 2:numel(duct_openings)
% for j = 2:6
for j = 1:numel(PWM_array)
x1 = [x1 contains(duct_openings{i},'V')];
x2 = [x2 contains(duct_openings{i},'F')];
x3 = [x3 contains(duct_openings{i},'D')];
x4 = [x4 contains(duct_openings{i},'S')];
x5 = [x5 PWM_array(j)];
CMH = [CMH airflow_matrix(i,j)];
end
end
% Configure the independent variables into a useful representation
indep_vars = [x1' x2' x3' x4' x5'];
% full_matrix = [x1' x2' x3' x4' x5' CMH'];
%% Now let's try to fit a model to this data
%% Let's test this fit in a way actually usable in C. It'll have to be hardcoded,
% so reducing the precision of the coefficients is top priority.
% Truncated from mdl.Coefficients.Estimate to have only 5 digits. This was
% determined as an acceptable precision for maintaining prediction accuracy.
truncated = [-21.03
11.326
0
32.222
-0.790
3.5869
0.0383
-25.16
8.0716
0.8849
-24.70
-4.286
0.9407
1.2133
0.8871
0.0972
0
19.155
0
0
-0.022
];
% Let's create our fit function using our hard coded values
fit_function = @(x1,x2,x3,x4,x5) truncated(1).*1 + truncated(2).*x1 + truncated(3).*x2 + truncated(4).*x3 + truncated(5).*x4 + truncated(6).*x5 + truncated(7).*x1*x2 + truncated(8).*x1*x3 + truncated(9).*x1*x4 + truncated(10).*x1*x5 + truncated(11).*x2*x3 + truncated(12).*x2*x4 + truncated(13).*x2*x5 + truncated(14).*x3*x4 + truncated(15).*x3*x5 + truncated(16).*x4*x5 + truncated(17).*x1.^2 + truncated(18).*x2.^2 + truncated(19).*x3.^2 + truncated(20).*x4.^2 + truncated(21).*x5.^2;
%% Let's compare the set of predictions to the actual data
x1_test = []; % V
x2_test = []; % F
x3_test = []; % D
x4_test = []; % S
x5_test = []; % PWM
CMH_Predicted = [];% CMH
CMH_Predicted_C = [];
for i = 2:numel(duct_openings)
% for j = 2:6
for j = 1:numel(PWM_array)
x1_test = contains(duct_openings{i},'V');
x2_test = contains(duct_openings{i},'F');
x3_test = contains(duct_openings{i},'D');
x4_test = contains(duct_openings{i},'S');
x5_test = PWM_array(j);
pred = feval(mdl, x1_test,x2_test,x3_test,x4_test, x5_test);
pred = min(365, max(0, pred));
C_pred = fit_function(x1_test,x2_test,x3_test,x4_test, x5_test);
C_pred = min(365, max(0, C_pred));
CMH_Predicted = [CMH_Predicted pred];
CMH_Predicted_C = [CMH_Predicted_C C_pred];
end
end
%% Plot comparison
figure;
err = CMH_Predicted-CMH;
neg = (err<0).*err;
pos = (err>=0).*err;
errorbar(1:numel(CMH),CMH, neg,pos,'LineStyle','none','Color','red');hold on
plot(1:numel(CMH),CMH,'db',1:numel(CMH_Predicted),CMH_Predicted,'dr');title(sprintf("RMSE: %0.2f",rms(err)))
xlabel("Num");ylabel("CMH");grid minor;legend("Prediction Error","Data","Prediction");
fprintf("RMSE: %0.2f\n",rms(err))
% figure;plot(mdl);grid minor;improvePlot
%% Plot comparison using a lower fidelity fit (keeping less data points)
figure;
err2 = CMH_Predicted_C-CMH;
neg = (err2<0).*err2;
pos = (err2>=0).*err2;
errorbar(1:numel(CMH),CMH, neg,pos,'LineStyle','none','Color','red');hold on
plot(1:numel(CMH),CMH,'db',1:numel(CMH_Predicted_C),CMH_Predicted_C,'dr');title(sprintf("RMSE: %0.2f",rms(err2)))
xlabel("HVAC Config Index [-]");ylabel("Blower Airflow Prediction [CMH]");grid minor;legend("Prediction Error","Data","Prediction");
fprintf("RMSE: %0.2f\n",rms(err2))
% figure;plot(mdl);grid minor;improvePlot
%% Plot the 2 fits against eachother
figure;
plot(1:numel(CMH),CMH,'dg',1:numel(CMH_Predicted),CMH_Predicted,'db',1:numel(CMH_Predicted_C),CMH_Predicted_C,'dr');title("Comparing High vs Low Precision Data Fit")
xlabel("Num");ylabel("CMH");grid minor;legend("Real Data","High Precision Fit","Low Precision Fit","Prediction");

Sulaymon Eshkabilov on 21 Jan 2023
You should consider here some sort of unit compatibe value for U, S, D, V. In other words, 100% (and 80%, 60%, 40%, 20%) open U corresponds to ??% of S opening, ??? % D and ??% of V or vice verse 100% open S corresponds to ?% of U, ?% D, ?%V. So then you shall be able to compute V+F, V+S, V+F+D, etc., make up the states of PWM.