Testing is a very important step in the process of development a system, component or software. In this article we are going to focus on software (model based design) testing. Depending on the methodology of running a test case, software testing falls into two categories:
- manual testing: where the test engineer defines and runs the test case (test scenario) and checks the results
- automated testing: where the test engineer defines the test cases but they are run and the results checked automatically by a script
Nowadays, automated testing is widely spread in the engineering and software development companies for several reasons. Compared with a manual test, an automated test allows you to run a lot of test cases in a short time, reproduce exactly the same scenario if needed and check large batch of data (results) automatically.
Scilab and Xcos allows you to run automatic tests on Xcos model using Scilab scripts. In this article we are going to explain how you can:
- set the parameters of Xcos blocks using Scilab functions
- run automatically Xcos models from Scilab
- save and check the result of the Xcos model against other data
As an example we are going to use the bilinear interpolation function from previous article and compare its results against the predefined interpolation function which comes with Xcos. In this example, the Xcos model is the reference model, which means that it holds the truth (we trust the results), and the bespoke Scilab function for bilinear interpolation is the object under test.
The principle of the test automation is depicted in the image below.
From a Scilab script we are going to generate test pairs of (xp, yp) points. These points are going to be fed to both the Scilab function and the Xcos model. At the end we are going to check if the zp points have the same value for both calculation methods. This way we are making sure that our created bilinear interpolation works well for a large set of input points.
The Xcos model uses two constant inputs, both set to zero, which are placeholders for the (xp, yp) points.
The Saturation
block are used to limit the input points to the MIN and MAX of the axes. If we are not doing the saturation, if the x or y points are outside the axes limits, the Interp 2
block will perform an extrapolation which is not desired.
The result of the Xcos model are saved in the Scilab workspace under the name zpt_out
.
The Scilab function which implements the bilinear interpolation algorithm is displayed below.
function [P]=f_interp2d(x, y, z, xp, yp) // Check if x axis is monotonically increasing for i=1:length(x) // Axis is not monotonically increasing if i>1 && x(i) <= x(i-1) //disp("Axis x is not monotonically increasing") break; end end // Find x1 and x2 coordinates for i=1:length(x) // Point xp is outside range if xp < x(1) || xp > x(length(x)) //disp("Point xp is out or range"); if xp < x(1) xp = x(1); else xp = x(length(x)); end end // Point x is the first point in the axis if xp == x(1) x1 = x(1); x1_idx = 1; x2 = x(2); x2_idx = 2; break; end // Point x is the last value in the axis if xp == x(length(x)) x1 = x(length(x)-1); x1_idx = length(x)-1; x2 = x(length(x)); x2_idx = length(x); break; end // Point x is in between first and last point of the axis if xp >= x(i) && xp <= x(i+1) x1 = x(i); x1_idx = i; x2 = x(i+1); x2_idx = i+1; break; end end // Check if y axis is monotonically increasing for i=1:length(y) // Axis is not monotonically increasing if i>1 && y(i) <= y(i-1) //disp("Axis y is not monotonically increasing") break; end end // Find y1 and y2 coordinates for i=1:length(y) // Point yp is outside range if yp < y(1) || yp > y(length(y)) //disp("Point yp is out or range"); if yp < y(1) yp = y(1); else yp = y(length(y)); end end // Point y is the first point in the axis if yp == y(1) y1 = y(1); y1_idx = 1; y2 = y(2); y2_idx = 2; break; end // Point y is the last value in the axis if yp == y(length(y)) y1 = y(length(y)-1); y1_idx = length(y)-1; y2 = y(length(y)); y2_idx = length(y); break; end // Point y is in between first and last point of the axis if yp >= y(i) && yp <= y(i+1) y1 = y(i); y1_idx = i; y2 = y(i+1); y2_idx = i+1; break; end end Q11 = z(y1_idx, x1_idx); Q12 = z(y2_idx, x1_idx); Q21 = z(y1_idx, x2_idx); Q22 = z(y2_idx, x2_idx); R1 = Q11*((x2-xp)/(x2-x1)) + Q21*((xp-x1)/(x2-x1)); R2 = Q12*((x2-xp)/(x2-x1)) + Q22*((xp-x1)/(x2-x1)); P = R1*((y2-yp)/(y2-y1)) + R2*((yp-y1)/(y2-y1)); endfunction
The function is saved as a Scilab function in a separate *.sci
file. The function does some consistency check of the input data before doing the actual bilinear interpolation:
- check if both x and y axes are monotonically increasing
- check if the xp and yp points are between the minimum and maximum values of the axes
The Scilab bilinear interpolation function has 5 input parameters and 1 output:
- x-axis
- y-axis
- z-map
- xp coordinate
- yp coordinate
- zp interpolation result
For further information on the bilinear interpolation algorithm read this article Bilinear (2-D) interpolation with algorithm and calculator.
The Scilab script
implementing the test automation is displayed below.
clc(); exec("f_interp2d.sci"); x = [1;2;3;4;5]; y = [1;2;3;4]; z(4,:) = [41,42,43,44,45]; z(3,:) = [31,32,33,34,35]; z(2,:) = [21,22,23,24,25]; z(1,:) = [11,12,13,14,15]; xpt = 1:0.1:5; ypt = 1:0.1:4; scs_interp2d = xcosDiagramToScilab("interp2d.zcos"); xcos("interp2d.zcos") scs_interp2d.objs(2).graphics.exprs = "xp"; xcosUpdateBlock(scs_interp2d.objs(2)) scs_interp2d.objs(9).graphics.exprs = "yp"; xcosUpdateBlock(scs_interp2d.objs(9)); errCnt = 0; for i=1:length(xpt) for j=1:length(ypt) xp = xpt(i); yp = ypt(j); zp_scilab(i,j) = f_interp2d(x,y,z,xp,yp); xcos_simulate(scs_interp2d,4); zp_xcos(i,j) = zpt_out.values($); if abs(zp_scilab(i,j) - zp_xcos(i,j)) > 0.1 errCnt = errCnt + 1; end end end disp("Done!") figure(0) surf(x,y,z), xgrid(); hf0 = gcf(),ha0 = gca(); hf0.background = -2; ha0.x_label.font_size = 2, ha0.x_label.font_foreground = 5; ha0.y_label.font_size = 2, ha0.y_label.font_foreground = 5; ha0.z_label.font_size = 2, ha0.z_label.font_foreground = 5; title("x-engineer.org","FontSize",2,"Color","blue"); figure(1) surf(xpt,ypt,zp_scilab'),xgrid(); hf1 = gcf(),ha1 = gca(); hf1.background = -2; ha1.x_label.font_size = 2, ha1.x_label.font_foreground = 5; ha1.y_label.font_size = 2, ha1.y_label.font_foreground = 5; ha1.z_label.font_size = 2, ha1.z_label.font_foreground = 5; title("x-engineer.org","FontSize",2,"Color","blue"); figure(2) surf(xpt,ypt,zp_xcos'), xgrid(); hf2 = gcf(),ha2 = gca(); hf2.background = -2; ha2.x_label.font_size = 2, ha2.x_label.font_foreground = 5; ha2.y_label.font_size = 2, ha2.y_label.font_foreground = 5; ha2.z_label.font_size = 2, ha2.z_label.font_foreground = 5; title("x-engineer.org","FontSize",2,"Color","blue");
Let’s explain it line by line.
First we clear the Scilab console calling the function clc()
. This is not mandatory but is useful in order to spot easily any warning or error messages. Next we load the Scilab bilinear interpolation function with the exec()
function.
The next lines deal with the definition of the axes x
, y
and map z
data.
The interpolation points are defined as vectors in the variables xpt
and ypt
. The nested FOR loop defined later in the script will cycle through all these points and call the Xcos model and Scilab bilinear interpolation function.
Next step is to load the Xcos diagram into the Scilab workspace. This is required in order to have access to the model parameters in the Scilab environment. To load the Xcos model into the Scilab workspace we use the function xcosDiagramToScilab()
.
Next we open the Xcos model calling the xcos()
function.
The next piece of code modifies the Constant
block from the Xcos model and sets the value from 0
and 0
to xp
and yp
. When the nested FOR loop will run, xp
and yp
variables will be modified in the Scilab workspace and the Xcos model will read from there.
scs_interp2d.objs(2).graphics.exprs = "xp"; xcosUpdateBlock(scs_interp2d.objs(2)) scs_interp2d.objs(9).graphics.exprs = "yp"; xcosUpdateBlock(scs_interp2d.objs(9));
We also define an error counter variable errCnt
which will count how many differences there are between the Xcos and Scilab interpolation functions.
The nested FOR loop will perform the following operations:
- cycle throught the
xpt
andypt
arrays and assign values toxp
andyp
- call the Scilab bilinear interpolation function and return the result into the
zp_scilab
matrix - call and run the Xcos model and return the result into the
zp_xcos
matrix - check if the difference between the two interpolation methods exceeds
0.1
, if yes, increment the error counter
After the nested FOR loop is executed, the Done!
message is displayed in the Scilab console and the results of the interpolation functions are plotted into surf plots for comparison.
The results show that the Scilab implementation of the bilinear interpolation is correct, there are no difference in the result compare with the Xcos model. The error counter variable errCnt
remains 0
throughout the simulation.
Also, if we look in the Scilab workspace at the size of the zp
variables, they contain 41 x 31
elements, which means that the model was run 1271 times. This shows the capability of this method for test automation.