Blog Post 5 - Refresher
May 5, 2026
It’s been a while since I’ve posted. During my hiatus of sorts, I’ve been figuring out what college to go to, which includes lots, and lots, and lots of tours. In total, I think I’ve been on UMD’s campus for the purpose of touring over 9 times, and over 4 times for UVA.
As far as my research is concerned, I have been using this time to draft the code for experiment 2, though it isn’t in a very functional state right now. It occurred to me that I never explained the structure and different parts of my code, so I figured I could explain this while I’m still debugging my code.
From an overarching view, my code functions through several programs working in conjunction. For my parameters and presets, I have two “YAML” files, which essentially are human readable files that store data assigned to variable names (something like this:
n_neurons: 100
excitatory_ratio: 0.83).
My program can then read this and turn the text into actual workable variables. The first YAML file I have designed is for biological parameters, which include variables such as gain, noise magnitude and firing rate of the neurons. The second is for the overall configuration of the network, including variables such as then number of neurons, number of trials per experiment, and random number generator seed.
The next big part of my program is “network.py.” Instead of putting all the experimental procedure and complicated analytics within this program, I decided to only include the network and its functionalities, and have the other programs (which I will explain next) interact with the network and draw out any data necessary. After importing and converting the YAML file variables from earlier, I have an initialization method called “___init___()” which takes these variables and creates a matrix W, ensuring Dale’s Law and zeroing out self connections. I then tweak it to have a certain spectral radius (I introduced this when I was messing with exp1). This is it for the network itself.
Next, I have a method that “reads” the current network state and neuron values and returns them for interpretation. This is pretty simple: I just return two arrays, one called Pool and the other B, of the neurons in the network.
The last important method in the network program is the simulate() method. This handles the core of the update function of the network, and is called thousands of times for each experiment. After counting the number of steps it must take per trial, it initializes itself, accounts for any external input, and then uses an Euler-Maruyama integration to calculate the change in each neuron. Most of the time that each experiment takes happens here. I then apply saturation bounds, and record changes.
Finally, we have analysis.py, which works together with each of the experiment programs to carry out the procedure. In this program, I have a section of code that is responsible for each of the experiments. For example, for experiment 1, analysis.py was responsible for calculating the divergence between two trials, fitting sections of this divergence to a linear growth phase, and attempting linear regression. On the other hand, exp1.py was responsible for calling analysis.py and then formatting results into graphical and numerical forms.
As you can see, a majority of the heavy lifting is done by analysis.py, and the reason for this is that I wanted to keep exp1.py as clean and readable as possible so anyone parsing my code can understand my procedure relatively easily. If they then want to dig deeper, they can through analysis.py and network.py.
This about sums up how my entire project functions. There are other programs, such as utils.py which helps generate sequences of random and biased noise for experiment 2, but these are mostly irrelevant to the greater architecture. I hope this helps you somewhat understand the structure of my code, and I’ll report back with results about experiment 2 and what I’ve done to make it work in the next post. Thank you for reading!

Leave a Reply
You must be logged in to post a comment.