15-883: Advice for MATLAB Programmers

Computational Models of Neural Systems

Over the years I've found that many students in 15-883 learned programming without learning good programming habits. This causes problems when they tackle more complex assignments like the 15-883 modeling project, because the lack of good habits leads to disorganized code that no one can understand or debug.

This document introduces some basic rules that everyone should follow when coding their modeling project. Ignore this advice at your peril.

1. Decompose your program into simple parts.

Don't try to cram everything into one function. Write a function just for setting up your currents. Write another function just for setting up your pyramidal cells. Write another function for calculating spike statistics. And so on.

2. Every function goes in its own file.

In MATLAB, every function should go in a separate file whose name matches the function name. This allows functions to be called from the MATLAB Command Window so they can be debugged.

Also, do not use MATLAB Live files (.mlx files) for this assignment, because they are not human readable outside of MATLAB. Only use regular .m files, which are text files.

3. Use global variables for constants and major data structures.

Constants such as the number of cells and number of time steps in the simulation should be defined as global variables so they can be referenced anywhere in your code. Do not pass them as arguments. Similarly, major data structures such as the collection of cells you're simulating should be globals so they can be accessed and updated from wherever necessary.

The declare_globals script suggested in the project instructions is a convenient way to ensure that every function has access to all the global variables it needs, and relieves you of the need to repeat all your global declarations in every function. Note that declare_globals must be a script, not a function.

4. Use appropriate data structures.

MATLAB provides structure objects with named fields. If you're not familiar with this type of data structure, take a few minutes to learn about it. Each current is represented as a structure with fields such as tau_rise, tau_fall, G, etc. Each pyramidal cell is represented by a structure with fields such as V (for the membrane voltage), last_spike_time, and state. Since we have multiple pyramidal cells, they will live in an array of structs.

If you are tempted to just stick everything in a bunch of separate arrays named tau_rise, tau_fall, etc., you are not following good programming practice, and Santa will surely put you on his "naughty" list.

5. Follow function specifications exactly.

If you are told to write a function updateGamma(p,t), then your function should take exactly those arguments and nothing else. Any other variables your function needs to reference should be declared as globals.

6. Never put constants in your code.

A constant like 500 should never appear in your code. Assign it to a global variable such as num_time_steps and then use that variable in your code.

There are only two exceptions to this rule. First, it's okay to write a constant when you're assigning it to a variable, e.g., "num_time_steps = 500;" is fine. Second, it's okay to use common constants such as 0 to initialize a sum, or 1 as the starting index of a for loop or the numerator of a fraction. But it's not okay to use 1 in other than these very common contexts. For example, if you're using 1 as a capacitance value, assign it to a variable called Capacitance and use that instead.

7. Use meaningful variable names.

Keep in mind that other people must be able to read your code. If you want to keep track of a cell's last spike time, don't use a cryptic name like "lt" or "lstspk". Use "last_spike_time" or "lastSpikeTime".

Avoid generic names like "answer", "result", or "x". Use a name that accurately describes what you're computing.

8. Do not needlessly duplicate code. Use abstraction instead.

A cell's membrane voltage is the result of multiple currents. Do not write a separate expression to calculate each current; that bloats the code and makes it harder to spot errors. Instead, use a for loop to iterate over all the currents and calculate them one at a time. That way the code will only contain a single call to your conductance calculation function, inside the for loop. This is why the currents should be described in a struct array instead of using a separate variable to hold each current.

9. Clean up your messes.

While developing your program you may end up with old functions you no longer use, old code that is commented out, and print statements added for debugging. Get rid of all this clutter before submitting your code.