Cat Proximity MATLAB Program

by cowmanpoke in Circuits > Computers

4019 Views, 6 Favorites, 0 Comments

Cat Proximity MATLAB Program

cat_proximity.png
cat_5.png
Boston University's engineering program has all engineering freshmen take Engineering Computation, a class teaching the programming language MATLAB (short for Matrix Laboratory). MATLAB is a C based language that is very easy (compared to most languages) and is spectacular at data manipulation and matrix related tasks (hence the name). However, it can also be used as a "general use" language, hence this Instructable.

I finished a lab early once and decided that the most efficient use of my time was to make a program that simulated the Cat proximity XKCD, it being one of my favorites. The program prompts the user for a distance to a cat in feet, and then give the adjusted intelligence and statement inanity level (x% of normal intelligence, statement is y% inane) as well as plotting the point of both on a graph based on the one in the comic. There is also a built in limit for both extremely close and far distances.

This Instructable will show step-by-step what the program does as well as giving the code in full with my original comments. It also gives the output given by the computer for some example inputs.

Programming experience is not necessary to run the program, since I give it to you. It will help understand what's happening, however. The best source for clearing up confusion concerning what a function does or how to use it is the MATLAB website. So grab a cat and get started!

Intro and "easy" Answers

cat_25.png
cat_0.png
FYI, "easy" answers mean that the distance entered is either too close or too far to get a graphical representation, working on the assumption that if you're too far from a cat (I chose 20 feet), you will not be very affected and if you're too close (less than 1 foot), you're brain is pretty much completely mush.

Here is the code we will be using for this part (in italics):

d = abs(input('Enter proximity to cat in feet: '));

if d < 1

    fprintf('\nThis close to a cat, your intelligence is negligible\nand the inanity of your statements is at a high.\n')

    disp('(YOU''RE A KITTY!)')

elseif d >= 20

        fprintf('\nThis far from a cat, your intelligence is not adversely affected\nand the inanity of your statements is at a minimum.\n')

else
...(continued)

And here is the line-by-line explanation:

d = abs(input('Enter proximity to cat in feet: '));
Two things are being done here. The first is that, using the input function, a number is being entered. Then, the absolute value is taken using the abs function and this changed number is saved as d. The absolute value is taken because -5 feet from a cat is still 5 feet.
In most programming languages, you must always end a line of a statement (like x = 5) with a semicolon. In MATLAB, you do not but if you don't, the result will be shown. Semicolons suppress the result. So:
1) x = 5
    x =
          5
2) x = 5;

       (nothing)

if d < 1

    fprintf('\nThis close to a cat, your intelligence is negligible\nand the inanity of your statements is at a high.\n')

    disp('(YOU''RE A KITTY!)')

If the distance is less than one foot, It displays the message "This close to a cat, your intelligence is negligible and the inanity of your statements is at a high." and then afterward "(You're a kitty!)", referencing the alt-text of the XKCD comic. The fprintf function is used first because the sentence is too long for one line and fprintf allows you to add newline characters easily with \n. Putting in \n anywhere will make the rest of the sentence go to the next line. There are three in this statement. Notice how there is no space in between 'negligible' '\n' and 'and'. It also doesn't matter how long the line runs in the code. Unless you go to the next line, MATLAB treats it as one statement. But without the newline characters, hen you run the function, some text will be cut off.
Next the disp function is used for the "(You're a kitty!)" because is is simpler to use and the sentence fits on one line.
Please note:
- There are two sets of parentheses because the disp function uses one set to work and the meesage itself is in parentheses, i.e. the message is (YOU'RE A KITTY) not YOU'RE A KITTY.
- Because the disp function works by displaying all text in between the two 'single quotes', you can't use a single wuote in the word "you're", as that will end the function. For this reason, you must use two single quotes (NOT a double quote) to display a single quote when the program is run.

elseif d >= 20

        fprintf('\nThis far from a cat, your intelligence is not adversely affected\nand the inanity of your statements is at a minimum.\n')


elseif
is a variation of else. Whereas else works in an if statement to include anything not already tried by the if statement, elseif is more particular and still has requirements.
Put more simply: if asks a question. If the situation applies, the inside of the if statement is done and the program leaves the if statement. If it does not apply, the program goes to the next option in the if statement. This can either be else or elseif. If it's else, then the program runs what's inside no matter what, and then leaves. If it's elseif (a combination of else and if), the the program checks the new condition. Using elseif is the same as using else, and then inside that else statement putting a new if statement. elseif is just faster.
Anyhoo, the elseif asks if d is greater than or equal to (>=) 20. If it is, it displays a new message similar to how it did before, again using fprintf.

else...
This part of the program runs if the distance is between the two bounds of 1 and 20. It contains the bulk of the code and involves "real" work by the computer, not "easy answers".
We ride!

Real Work - Preparing to Plot

else
    intelligence = 100/d -5;
    inanity = -100/d +105;
    x = 20:-1:.01;
    y = 100*(1./x);


We start with the else from the last slide, in order to include all "d"'s between 1 and 20.
Your intelligence level is defined as 100/d -5, and your inanity level as -100/d +105. The constants were added after trial and error gave me a graph that looked like the one in the comic. If you find a better function than what I used, feel free to use it.

One way that the plot function (next slide) works in MATLAB is that you can give it x values and y values and have MATLAB match them up to make a line. For instance, you could make the x values from 0 to 10 in increments of 1 and the y values from 1 to 100 in increments of 10 and get a straight line.
In this case, we are making the x values from 20 to .01 (yes, backwards) in increments of -.1 (because we're going backwards) by saying x = 20:-1:.01 (first_value:increments:last_value gives a vector) and the y equal to 100 times one over the x values, y = 100*(1./x). Looking back, y = 100./x would also work. In this case, the y values are a function of the x values.

Two things to note:
1) The smaller the increments, the more accurate and "curvy" the graph
2) The period before the divided by sign (./) is important. For two normal values, value1/value2 is fine but because x has many values, the ./ tells MATLAB to divide by each value and make a vector of all the new values.

Real Work - Base Plot

plot(x,-y+105, 'r')
    axis([1 20 0 100])
    hold on

    plot(x,y-5, 'b')
    legend('Intelligence', 'Inanity of Statements', 'location', 'best')
    hold on


plot does what it does and plots the x and y values. Again, the constant for the y values is to make he graph look nice. The 'r' means I want to first graph, Intelligence, to be in red. The 'b' means I want to secod graph, Inanity, to be blue (black would be 'k').

axis lets me control what the boundaries of the graph are, again so the graph looks nice. The way it works is axis([x-min, x-max, y-min, y-max]).

hold on means I want the graph to stay so the things I graph next will be on this graph and not a new one.

legend('Intelligence', 'Inanity of Statements', 'location', 'best') makes a legend. It will automatically make the first term for the first graph made, the second for the second, etc. The second part, "'location', 'best'", has MATLAB pick the best location for the legend to make it look all shiny. You could also specify the location, such as 'East'.



You now have the graph in the XKCD comic. Now we're going to graph where you are on the graph.

Real Work - How Stupid You Are: Your Intelligence/Inanity Points

plot(d,intelligence, 'bo')
    hold on
    plot(d, inanity, 'ro')
    xlabel('Human proximity to cat (feet)')
    ylabel('Magnitude')



plot(...) Here wer'e plotting a single point. 'd' is the distance from the cat (remember from before?) and intellifenge and inanity were calculated before. 'bo' makes a blue o shape. You could also have done 'b*' for a * as the point.

_label() makes a label on the _ axis, where _ is x or y.

Real Work - Text

    fprintf('\nAt this range:\n\nYour intelligence is %d%% of the norm\nYour statements are %d%% inane\n', floor(inanity),
    ceil(intelligence))
end



fprintf is what it was before. All the \n make it look nicer. 

%d%% is because %d is an actual value while %% makes one %. Making only one % would make MATLAB think you were making a variable (like when you use %d).

end ends the else statement we've been in for most of the program.
Basically:

Get a value.
If it's too low, do something.
If it's too high, do something.
If it's just right, do this really long thing.
end

Full Code (original W/ Comments)

cat_proximity.png
cat_5.png
cat_5_window.png
% Tribute to xkcd #231

% returns intelligence and inanity of statements based on proximity to cat

% intelligence = m*x+b and red

% inanity =  -m*x+b and blue

d = abs(input('Enter proximity to cat in feet: '));

if d < 1

    fprintf('\nThis close to a cat, your intelligence is negligible\nand the inanity of your statements is at a high.\n')

    disp('(YOU''RE A KITTY!)')

elseif d >= 20

        fprintf('\nThis far from a cat, your intelligence is not adversely affected\nand the inanity of your statements is at a minimum.\n')

else

    intelligence = 100/d -5;

    inanity = -100/d +105;

    x = 20:-1:.01;

    y = 100*(1./x);
 

    % intelligence

    plot(x,-y+105, 'r')

    axis([1 20 0 100])

    hold on

    % inanity

    plot(x,y-5, 'b')

    legend('Intelligence', 'Inanity of Statements', 'location', 'best')

    hold on

    %inanity point

    plot(d,intelligence, 'bo')

    hold on

    %intelligence point

    plot(d, inanity, 'ro')

    xlabel('Human proximity to cat (feet)')

    ylabel('Magnitude')

    fprintf('\nAt this range:\n\nYour intelligence is %d%% of the norm\nYour statements are %d%% inane\n', floor(inanity), ceil(intelligence))

end