forked from swcarpentry/matlab-novice-inflammation
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy path04-func.html
181 lines (174 loc) · 14 KB
/
04-func.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="generator" content="pandoc">
<title>Software Carpentry: Programming with MATLAB</title>
<link rel="shortcut icon" type="image/x-icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" type="text/css" href="css/bootstrap/bootstrap.css" />
<link rel="stylesheet" type="text/css" href="css/bootstrap/bootstrap-theme.css" />
<link rel="stylesheet" type="text/css" href="css/swc.css" />
<link rel="alternate" type="application/rss+xml" title="Software Carpentry Blog" href="http://software-carpentry.org/feed.xml"/>
<meta charset="UTF-8" />
<!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
<!--[if lt IE 9]>
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body class="lesson">
<div class="container card">
<div class="banner">
<a href="http://software-carpentry.org" title="Software Carpentry">
<img alt="Software Carpentry banner" src="img/software-carpentry-banner.png" />
</a>
</div>
<article>
<div class="row">
<div class="col-md-10 col-md-offset-1">
<h1 class="title">Programming with MATLAB</h1>
<h2 class="subtitle">Creating Functions</h2>
<div id="learning-objectives" class="objectives panel panel-warning">
<div class="panel-heading">
<h2><span class="glyphicon glyphicon-certificate"></span>Learning Objectives</h2>
</div>
<div class="panel-body">
<ul>
<li>Explain a Matlab function file.</li>
<li>Define a function that takes parameters.</li>
<li>Test a function.</li>
<li>Explain what a call stack is, and trace changes to the call stack as functions are called.</li>
<li>Set default values for function parameters.</li>
<li>Know why we should divide programs into small, single-purpose functions.</li>
</ul>
</div>
</div>
<p>If we only had one data set to analyze, it would probably be faster to load the file into a spreadsheet and use that to plot some simple statistics. But we have twelve files to check, and may have more in future. In this lesson, we’ll learn how to write a function so that we can repeat several operations with a single command.</p>
<p>Let’s start by defining a function <code>fahr_to_kelvin</code> that converts temperatures from Fahrenheit to Kelvin:</p>
<pre class="sourceCode matlab"><code class="sourceCode matlab"><span class="co">% file fahr_to_kelvin.m</span>
function ktemp = fahr_to_kelvin(ftemp)
ktemp = ((ftemp - <span class="fl">32</span>) * (<span class="fl">5</span>/<span class="fl">9</span>)) + <span class="fl">273.15</span>;
end</code></pre>
<p>A Matlab function <em>must</em> be saved in a text file with a <code>.m</code> extension. The name of that file must be the same as the function defined inside it. The name must start with a letter and cannot contain spaces. So, you will need to save the above code in a file called <code>fahr_to_kelvin.m</code>.</p>
<p>The first line of our function:</p>
<pre><code>function ktemp = fahr_to_kelvin(ftemp)</code></pre>
<p>is called the <em>function definition</em>, and it declares that we’re writing a function named <code>fahr_to_kelvin</code>, that accepts a single parameter, <code>ftemp</code>, and outputs a single value, <code>ktemp</code>. Anything following the function definition line is called the <em>body</em> of the function. The keyword <code>end</code> marks the end of the function body, and the function won’t know about any code after <code>end</code>.</p>
<p>Just as we saw with scripts, functions must be <em>visible</em> to MATLAB, i.e., a file containing a function has to be placed in a directory that MATLAB knows about. The most convenient of those directories is the current working directory.</p>
<p>We can call our function from the command line like any other MATLAB function:</p>
<pre class="sourceCode matlab"><code class="sourceCode matlab">fahr_to_kelvin(<span class="fl">32</span>)</code></pre>
<pre class="output"><code>ans = 273.15</code></pre>
<p>When we pass a value, like <code>32</code>, to the function, the value is assigned to the variable <code>ftemp</code> so that it can be used inside the function. If we want to return a value from the function, we must assign that value to a variable named <code>ktemp</code>—in the first line of our function, we promised that the output of our function would be named <code>ktemp</code>.</p>
<p>Outside of the function, the names <code>ftemp</code> and <code>ktemp</code> don’t matter, they are only used by the function body to refer to the input and output values.</p>
<p>Now that we’ve seen how to turn Fahrenheit to Kelvin, it’s easy to turn Kelvin to Celsius.</p>
<pre class="sourceCode matlab"><code class="sourceCode matlab"><span class="co">% file kelvin_to_celsius.m</span>
function ctemp = kelvin_to_celsius(ktemp)
ctemp = ktemp - <span class="fl">273.15</span>;
end</code></pre>
<p>Again, we can call this function like any other:</p>
<pre class="sourceCode matlab"><code class="sourceCode matlab">kelvin_to_celsius(<span class="fl">0.0</span>)</code></pre>
<pre class="output"><code>ans = -273.15</code></pre>
<p>What about converting Fahrenheit to Celsius? We could write out the formula, but we don’t need to. Instead, we can <a href="reference.html#function-composition">compose</a> the two functions we have already created:</p>
<pre class="sourceCode matlab"><code class="sourceCode matlab"><span class="co">% file fahr_to_celsius.m</span>
function ctemp = fahr_to_celsius(ftemp)
ktemp = fahr_to_kelvin(ftemp);
ctemp = kelvin_to_celsius(ktemp);
end</code></pre>
<p>Calling this function,</p>
<pre><code>kelvin_to_celsius(0.0)</code></pre>
<p>we get, as expected:</p>
<pre><code>ans = -273.15</code></pre>
<p>This is our first taste of how larger programs are built: we define basic operations, then combine them in ever-large chunks to get the effect we want. Real-life functions will usually be larger than the ones shown here—typically half a dozen to a few dozen lines—but they shouldn’t ever be much longer than that, or the next person who reads it won’t be able to understand what’s going on.</p>
<div id="concatenating-in-a-function" class="challenge panel panel-success">
<div class="panel-heading">
<h2><span class="glyphicon glyphicon-pencil"></span>Concatenating in a function</h2>
</div>
<div class="panel-body">
<ol style="list-style-type: decimal">
<li>In Matlab, we concatenate strings by putting them into an array or using the <code>strcat</code> function:</li>
</ol>
<p><sub>~</sub> {.matlab} disp([‘abra’, ‘cad’, ‘abra’]) <sub>~</sub> <sub>~</sub> {.output} abracadabra <sub>~</sub></p>
<p><sub>~</sub> {.matlab} disp(strcat(‘a’, ‘b’)) <sub>~</sub> <sub>~</sub> {.output} ab <sub>~</sub></p>
<p>Write a function called <code>fence</code> that takes two parameters, <code>original</code> and <code>wrapper</code> and appends <code>wrapper</code> before and after <code>original</code>:</p>
<p><sub>~</sub> {.matlab} disp(fence(‘name’, ’<em>’)) <sub>~</sub> <sub>~</sub> {.output} </em>name* <sub>~</sub></p>
<ol style="list-style-type: decimal">
<li>If the variable <code>s</code> refers to a string, then <code>s(1)</code> is the string’s first character and <code>s(end)</code> is its last. Write a function called <code>outer</code> that returns a string made up of just the first and last characters of its input:</li>
</ol>
<p><sub>~</sub> {.matlab} disp(outer(‘helium’)) <sub>~</sub> <sub>~</sub> {.output} hm <sub>~</sub></p>
</div>
</div>
<p>Let’s take a closer look at what happens when we call <code>fahr_to_celcius(32.0)</code>. To make things clearer, we’ll start by putting the initial value 32.0 in a variable and store the final result in one as well:</p>
<pre class="sourceCode matlab"><code class="sourceCode matlab">original = <span class="fl">32.0</span>;
final = fahr_to_celcius(original);</code></pre>
<p>The diagram below shows what memory looks like after the first line has been executed:</p>
<p>Once we start putting things in functions so that we can re-use them, we need to start testing that those functions are working correctly. To see how to do this, let’s write a function to center a dataset around a particular value:</p>
<pre class="sourceCode matlab"><code class="sourceCode matlab">function out = center(data, desired)
out = (data - mean(data)) + desired
end</code></pre>
<p>We could test this on our actual data, but since we don’t know what the values ought to be, it will be hard to tell if the result was correct, Instead, let’s create a matrix of 0’s, and then center that around 3:</p>
<pre class="sourceCode matlab"><code class="sourceCode matlab">z = zeros(<span class="fl">2</span>,<span class="fl">2</span>);
center(z, <span class="fl">3</span>)</code></pre>
<pre class="output"><code>ans =
3 3
3 3</code></pre>
<p>That looks right, so let’s try out <code>center</code> function on our real data:</p>
<pre class="sourceCode matlab"><code class="sourceCode matlab">data = csvread(<span class="st">'inflammation-01.csv'</span>);
centered = center(data(:), <span class="fl">0</span>)</code></pre>
<p>It’s hard to tell from the default output whether the result is correct–this is often the case when working with fairly large arrays–but, there are a few simple tests that will reassure us.</p>
<p>Let’s calculate some simple statistics:</p>
<pre class="sourceCode matlab"><code class="sourceCode matlab">disp([min(data(:)), mean(data(:)), max(data(:))])</code></pre>
<pre class="output"><code>0.00000 6.14875 20.00000</code></pre>
<p>And let’s do the same after applying our <code>center</code> function to the data:</p>
<pre class="sourceCode matlab"><code class="sourceCode matlab">disp([min(centered(:)), mean(centered(:)), max(centered(:))])</code></pre>
<pre class="output"><code>-6.1487e+00 -2.2962e-14 1.3851e+01</code></pre>
<p>That seems almost right: the original mean was about 6.1, so the lower bound from zero is now about -6.1. The mean of the centered data isn’t quite zero–we’ll explore why not in the challenges–but it’s pretty close. We can even go further and check that the standard deviation hasn’t changed:</p>
<pre class="sourceCode matlab"><code class="sourceCode matlab">std(data(:)) - std(centered)</code></pre>
<pre class="output"><code>5.3291e-15</code></pre>
<p>The difference is very small. It’s still possible that our function is wrong, but it seems unlikely enough that we should probably get back to doing our analysis. We have one more task first, though: we should write some <a href="reference.html#documentation">documentation</a> for our function to remind ourselves later what it’s for and how to use it.</p>
<pre class="sourceCode matlab"><code class="sourceCode matlab">function out = center(data, desired)
<span class="co">% Center data around a desired value.</span>
<span class="co">%</span>
<span class="co">% center(DATA, DESIRED)</span>
<span class="co">%</span>
<span class="co">% Returns a new array containing the values in</span>
<span class="co">% DATA centered around the value.</span>
out = (data - mean(data)) + desired;
end</code></pre>
<p>Comment lines immediately below the function definition line are called “help text”. Typing <code>help function_name</code> brings up the help text for that function:</p>
<pre class="sourceCode matlab"><code class="sourceCode matlab">help center</code></pre>
<pre class="output"><code>Center data around a desired value.
center(DATA, DESIRED)
Returns a new array containing the values in
DATA centered around the value.</code></pre>
<div id="testing-a-function" class="challenge panel panel-success">
<div class="panel-heading">
<h2><span class="glyphicon glyphicon-pencil"></span>Testing a function</h2>
</div>
<div class="panel-body">
<ol style="list-style-type: decimal">
<li><p>Write a function called <code>rescale</code> that takes an array as input and returns an array of the same shape with its values scaled to lie in the range 0.0 to 1.0. (If L and H are the lowest and highest values in the input array, respectively, then the function should map a value v to (v - L)/(H - L).) Be sure to give the function a comment block explaining its use.</p></li>
<li><p>Run <code>help linspace</code> to see how to use this function to generate regularly-spaced values. Use arrays like this to test your <code>rescale</code> function.</p></li>
<li><p>Write a function <code>run_analysis</code> that accepts a filename as parameter, and displays the three graphs produced in the previous lesson, i.e., <code>run_analysis('inflammation-01.csv')</code> should produce the corresponding graphs for the first data set. Be sure to give your function help text.</p></li>
</ol>
</div>
</div>
<p>We have now solved our original problem: we can analyze any number of data files with a single command. More importantly, we have met two of the most important ideas in programming:</p>
<ol style="list-style-type: decimal">
<li><p>Use arrays to store related values, and loops to repeat operations on them.</p></li>
<li><p>Use functions to make code easier to re-use and easier to understand.</p></li>
</ol>
<p>We have one more big idea to introduce, and then we will be able to construct a better ‘heat map’, like the one we initially used to display our first data set.</p>
</div>
</div>
</article>
<div class="footer">
<a class="label swc-blue-bg" href="http://software-carpentry.org">Software Carpentry</a>
<a class="label swc-blue-bg" href="https://github.com/swcarpentry/matlab-novice-inflammation">Source</a>
<a class="label swc-blue-bg" href="mailto:[email protected]">Contact</a>
<a class="label swc-blue-bg" href="LICENSE.html">License</a>
</div>
</div>
<!-- Javascript placed at the end of the document so the pages load faster -->
<script src="http://software-carpentry.org/v5/js/jquery-1.9.1.min.js"></script>
<script src="css/bootstrap/bootstrap-js/bootstrap.js"></script>
</body>
</html>