Sumerics is built upon YAMP and can therefore parse the same statements as YAMP. A simple example is
3 + 2^3
which is evaluated to 11. YAMP recognizes if operators need to be evaluated from left to right or right to left. Therefore statements like
2^2^2^2
get the right result - which is the same as typing
2^(2^(2^2))
since the power operator gets evaluated from right to left. Sumerics knows all arithmetic (+, -, *, /, ...) and logic (==, ~=, > < <=, >=) operators and can even execute factorial statements. The statement
4! == 4 * 3 * 2
results in 1, which is equivalent to true. Imaginary numbers are built in as well and have been
assigned to the constant i. It is also possible to stick the i directly to numbers, like
|4 + 3i|
which evaluates the absolute value of the complex number (4, 3) and results in 5. The same can be written with a function, i.e.
abs(4 + 3i)
Whitespaces and new lines are always being ignored. The same is true for tabs and other unsignificant symbols.
A matrix can be written by starting with square brackets. The following statement creates a (row) vector consisting of the numbers 2, 8, 5, 9i and 0.
[2, 8, 5, 9i, 0]
We can produce a column vector by just transposing the row vector:
[2, 8, 5, 9i, 0].'
However, if we initially wanted a column vector then we could also just have initialized the vector like
[2; 8; 5; 9i; 0]
It is also possible to adjungate the vector by using
[2, 8, 5, 9i, 0]'
If we want to get the absolute value of the vector (like the L2-norm), then we could again write
|[2, 8, 5, 9i, 0]|
or we use the abs() function. Creating a full matrix can be done by combining row ; and
column , operators, i.e.
[1, 2, 3; 4, 5, 6; 7, 8, 9]
This is a 3x3 matrix. In matrix environments it is sometimes also possible to use whitespaces and newlines as column and row seperators, like
[1 2 3 4]
Please note that negative values like -1 should be separated by commas or brackets.
Most of the time one needs a vector with a certain spacing. If we just want to create a vector from 1 to 9 with a spacing of 1, then the following command will certainly help us:
1:9
This gives us a column vector like [1; 2; 3; 4; 5; 6; 7; 8; 9]. We can do the same things as with
the matrices (since the range operator just gives us a matrix), i.e.
(1:9)'
adjungates (which is in this case equivalent to transposes) the generated vector. Changing the spacing can be done by specifying another value in the middle. An example would be
1:2:9
which as the same as [1; 3; 5; 7; 9], i.e. all odd entries from 1 to 9. The range operator is quite
smart and recognizes patterns like
9:1
This statement does not make sense with a spacing of 1. In this case the spacing will be set to -1. A popular choice is to use the range operator like
0:0.01:2*pi
The query will be evaluated to a vector that contains all elements from 0 to 2π with a spacing of 0.01. If we combine this we can make queries like
x = 0:0.01:2*pi y = sin(x)
Functions can be used in various ways. There are two kinds of functions: Functions with one and only one
argument and functions with various (0 to many) arguments. Most functions have different behaviors
depending on the kind of argument(s) they are receiving. All standard functions (sin(),
cos(), ...) are functions of the first kind. Those functions usually react to scalar input
like
sin(pi/2) cos(pi/4) tan(0.1)
by returning a scalar value. If we insert a matrix like
sin([pi/2, pi, pi/4]) cos(0:0.1:1) tan([0, 0.5, 1])
then we will get a matrix back. In this case the function has been applied on each member of the given matrix. Functions of the second class show a different behavior. In general there is no fixed pattern for those functions. Popular examples of such functions are
rand(10, 5) //generates a 10 x 5 random matrix with values 0..1 sort([-5, 2, 9, 0, 29]) //sorts the given vector(s) pwd() //prints the current working directory
Each of those three functions works differently. While the rand() function does also supply
overloads for calling the function without any argument (resulting in a scalar) or one argument
(resulting in a n x n matrix, where n is the argument), sort() just has this one possible call.
The pwd() function accepts no argument at all!
A quite mighty concept is the usage of variables as functions. A variable that represents a matrix can be used as a function, where the arguments can be seen as indices. This allows us to do the following things:
x = rand(10); x5 = x(5) x23 = x(2, 3) xi = x(4:6, 4:6) x1all = x(:, 1) x1to3second = x(6:end, 1:3)
So what is happening there exactly? First of all we are generating a 10 x 10 random matrix and storing
the result in the variable x. Now we store the fifth element of the matrix in the variable
x5. The fifth element is equivalent to row number 5, column number 1, since YAMP treats rows
before columns.
The variable x23 then stores the element in row 2, column 3 of the matrix x. Now
the variable xi gets a 3 x 3 submatrix of x, the one going from the rows 4 to 6
and columns 4 to 6. The variable x1all stores the first column vector of the matrix, i.e. all
rows and just one column (column index 1). Finally the last variable stores the second half, i.e. rows 6
to 10 of the first 3 columns of x. This results in a 5 x 3 matrix.
The special macro end can be used within matrix indices to denote the length of the corresponding
dimension. A simple example:
x = rand(5, 2); x(2:end, 1)//end = 5 x(7:end)//end = 10 x(2:4, 1:end)//end = 2
If you want to write really simply expressions (i.e. functions) in YAMP you can create so called lambda expressions. Basically you just have to tell how the incoming variables (arguments) should be called and what you actually want to do. Lambda expressions do not allow you to make variables optional, so in the end you have to specify each named variable or you cannot invoke your own function.
Let's define a really simple lambda expression:
f = x => x.^2
This function just squares the input (element-wise, i.e. vectors can be squared as well!). We can test this with the following calls:
f(2)//4 f([1,2;3,4])//1,4;9,16
If our own function should receive more arguments we can just seperate them by colons. Here we have to use brackets, to group those arguments. Let's consider an example:
g = (x, y, z) => x .* y + z.^2 h = (x, y) => x' * y
Writing those brackets is just a matter of taste. The first declaration will create a function in the
variable g that can be used like g(1, 2, 3) or with matrices that have the
same dimensions.
The second example can also be used with scalars or matrices that have the same dimension.
Currently there are many different kinds of plots available. The most basic one is a simple 2D plot.
The function you would most probably want to call for this is plot(). There are also
special cases of this function with some plot properties already pre-set. Let's have a look at some
samples:
plot(1:100, rand(100, 3)) semilogy(1:10, 2.^(1:10)) x = 2.^(1:10); semilogx(x, sqrt(x)) loglog(x, x.^3)
The first one is the standard plot function, which will plot 3 series with 100 points each. Therefore
we are setting the x-vector to values with 1 to 100, while the y-values are generated by a uniform
random distribution. In the next 2 plot commands (semilogy() and semilogx())
we are plotting with the y-axis or the x-axis set to logarithmic scaling. Finally by using the
loglog() function we can get a plot with logarithmic x and y axis.
Another possibility for a 2D plot is the special case of a so-called polar (or radial) plot. In this
case the x-axis is periodic with a certain periodicity (usually 2π, but also 360 or something similar
could be used). Using such a plot is mostly useful if one wants to display functions which have a kind
of periodicity in their argument. This can be used to illustrate the differences between trigonometric
functions as well as behaviors for more complex functions like bessel() or the famous
Lissajous curves.
x=0:pi/100:2*pi; polar(x, sin(x)) polar(x, [cos(x), sin(x)]) polar(x, sin(x + pi / 4)) polar(x, sin(x) .* cos(x))
Finally another very useful type of plot is a contour plot. In this kind of plot one can easily spot regions, which have the same value (of a matrix). Usually the input data should be a square matrix, but it does not have to be necessarily. One can now either specify a certain number of levels (which will be the different plateaus, which will be shown in the plot by lines and different colors) or specify the levels exactly.
contour(rand(10)) contour(rand(10), 5) contour(rand(10), [0.1 0.3 0.8 1.0])
All plots share some properties like the title of the plot or if the labels should actually be shown.
Those properties can be changed. Some plots do have some special properties. The contour plot for
instance has a property called ColorPalette, which defines the color palette that should
be used.
In general all properties of a plot can be changed by using the set() function. Without
specifying a plot by using a variable, the last generated plot will be considered for the changes. Here
are two simple examples:
a=plot(1:10, rand(10,1))
b=plot(1:10, sin(0.1:0.1:1))
set("title", "Plot with sinus!")
set(a, "title", "Plot with random stuff")
So the set() function requires a string as the property to change and then another argument.
In case of the title property the other argument happens to be a string. However, this is
not general. Let's have a look at some other examples:
plot(1:10, rand(10,1))
set("gridlines", 1) //here is also "on" allowed
set("showlegend", "off") //here is also 0 allowed
set("minx", 0)
set("maxx", 100)
If we mistype the property we will get a list of all possible properties. If we use the wrong type for the property's value then we will also receive some help on what type to use.
Properties such as the minx and maxx can also be set in one statement. The
following example demonstrates this:
plot(0:0.01:1, exp(0:0.01:1))
set("xrange", [-1, 1])
set("yrange", [-3, 3])
Here we use a vector with 2 elements to specify the minimum and the maximum. In the example we set the x-axis to go from -1 to 1 and the y-axis to be shown from -3 to 3. This does not have any affect on the plot values, but just on the display of the plot. If we do not specify the ranges, then YAMP does automatically set the ranges to show all points of the plot. However, this might not be the view you would like to have.
Every plot contains one or more series. In case of the contour plot there will be one and only one series. Series also have properties like the plot, where they are contained in. The only difference in setting those properties is that the index of the series has to be specified. Let's consider the following example:
plot(1:10, rand(10,3)) //3 series! set(1, "color", "red") //changes the color series #1 set(2, "color", "rgb(100, 200, 100)") //changes the color series #2 set(3, "color", "#123AB2") //changes the color series #3 set(:, "lines", "on") //shows the lines on all series set(1:2, "symbol", "none") //sets the symbol to none for series #1 and #2
Colors can be specified in three different ways. One is to use a known color name (like red, blue, green or also ones like forestgreen, steelblue etc.). The other two possibilities are not new to anyone who is used to style webpages or stylesheets. We have the hexadecimal syntax (6 hex. digits) and the rgb color type with values of 0-255 for each color.
Besides the additional number (or matrix of numbers) before the property (and after the optional plot variable) nothing is different from the plot's properties. We also get some help if we mistype some name or use the wrong type.
The property symbol is interesting, because it is a kind of enumeration and does not accept
an arbitrary string. If we do enter a string that is not supported, we will get an error message, which
lists all strings that are allowed. In case of the symbol property we are currently limited
to the following strings: None, Circle, Square, Diamond, Triangle, Cross, Plus, Star.
This experiment shows an experiment that can easily be done to show the capabilities of the gyrometer sensor.
This experiment aims to show the working power of the compass sensor by rotating the Ultrabook™ up to 360 degrees.
This experiment deals with the three inclinometer sensors which are responsible for detecting changes in the angles.
We rotate a standard office chair and invoke the gyro() function by pressing the enter key at an arbitrary point in time. We could successfully position the UltraBook™ perpendicular to its x-y plane. Therefore the rotation only affected the z-coordinate, i.e. the x-y plane. All other axis have not been rotated (not even slightly) in this experiment.
We fully rotate the UltraBook™ by using our hands. In this case the rotation is not uniform, i.e. at some time the rotation has been performed faster than at other times. Nevertheless we can see that the compass angle performs a full rotation, from 0 to 360 degrees. The compass, orientation and gyrometer sensors are all quite closely related.
The inclinometer is another angle aware sensor. In this experiment we incline the UltraBook™ by lifting the front. In the end we are able to observe some shift in the responsible inclinometer sensor over time. Again this experiment has not been performed with a constant velocity, which is the reason why the line is not straight in the plot.
Accurate position measurement via integration of the accelerometer sensor.
N = 50; dt = 0.1; measurement = timeseries(acc, N, dt); time = measurement(:,1); accelerations = measurement(:, 2:4)'; velocities = int(accelerations)(:, 1:N) * dt; positions = int(velocities)(:, 1:N) * dt; plot(time, [accelerations', velocities', positions']); set(1:3, "label", "Acceleration"); set(4:6, "label", "Velocity"); set(7:9, "label", "Position");
Comparison of accuracy of the positions derived from gps() and acc().
N = 50;
dt = 0.1;
start = gps();
measurement = timeseries(acc, N, dt);
end = gps();
accelerations = measurement(:, 2:4)';
velocities = int(accelerations) * dt;
positions = int(velocities) * dt;
delta_gps = |end - start|;
delta_acc = |positions(1:2, N)|;
printf("delta_gps is {0}\ndelta_acc is {1}", delta_gps, delta_acc)
Differentiation of gyrometer data (angular velocity) to get angular acceleration.
N = 50; dt = 0.1; measurement = timeseries(gyro, N + 1, dt); time = measurement(1:N, 1); angular_velocities = measurement(:, 2:4)'; angular_acceleration = diff(angular_velocities) / dt; angular_positions = int(angular_velocities) * dt; plot(time, [angular_acceleration', angular_velocities(:, 1:N)', angular_positions(:, 1:N)']); set(1:3, "label", "Acceleration"); set(4:6, "label", "Velocity"); set(7:9, "label", "Position");
Position measurement with orientation corrected using a lambda expression
N = 50; dt = 0.1; measf = () => orient() * acc(); measurement = timeseries(measf, N, dt); time = measurement(:,1); accelerations = measurement(:, 2:4)'; velocities = int(accelerations)(:, 1:N) * dt; positions = int(velocities)(:, 1:N) * dt; plot(time, [accelerations', velocities', positions']); set(1:3, "label", "Acceleration"); set(4:6, "label", "Velocity"); set(7:9, "label", "Position");
Accuracy comparison with orientation corrected using a lambda expression
N = 50;
dt = 0.1;
start = gps();
measf = () => orient() * acc();
measurement = timeseries(measf, N, dt);
end = gps();
accelerations = measurement(:, 2:4)';
velocities = int(accelerations) * dt;
positions = int(velocities) * dt;
delta_gps = |end - start|;
delta_acc = |positions(1:2, N)|;
printf("delta_gps is {0}\ndelta_acc is {1}", delta_gps, delta_acc)
A collection of sample scripts to download.
Sumerics is available on the Intel AppUp® store and provides an unique experience with the latest generation of Ultrabooks™.
The problem is the following: using advanced numerical applications like Matlab is really benefical if one's sitting behind a desktop PC or working on a numerical problem. Once the application is reduced to a small screen without a mouse or keyboard it gets nearly impossible to control. This is where Sumerics jumps in.
The app provides a similar syntax as Matlab. It is built around complex numbers and matrices and embraces the sensor capabilities that the latest generation of Intel® Ultrabooks™ offer us. With the app you can just do standard numerical stuff like solving systems of linear equations, inverting matrices or solving eigenvalue problems.
The function plotter is also capable of understanding touch commands like panning and zooming. The possibility of viewing 3D surface meshgrid and line plots lets you explore multi-parameter functions by using the touchscreen.