Building a 'dreamcatcher' LED display

This post outlines how to construct a dreamcatcher that also functions as an LED display. For this design, we'll use a "charlieplexing" layout to drive many LEDs with few pins. There is a version of the charlieplexing layout that works well with the spiral pattern used for our dreamcatcher. The construction approach is similar to the paper LED marquee project.

 Step 0: Materials

  • Willow branches, tied and dried around a small-medium sized kitchen pot to hold a circular shape
  • LEDs. If using N driving pins, then at N*(N-1) LEDs plus a few spares. I use 110 here. Bright LEDs in clear packaging are best. I also prefer ones with a wide viewing angle.
  • glass "bugle" (long thin) and "seed" (small, round) beads
  • Bare copper or brass wire, intermediate guage: small enough to thread through beads easily
  • Soldering tools
  • Scrap paper and cardboard, scissors, thumbtack, hobby knife, printer
  • Arduino and hookup wires


Step 1: Prepare the "circuit board"

For this project, I opted for a pattern based on 110 LEDs controlled by 11 pins. I used this template, made by the Fibonacci_layout.ipynb iPython notebook, available on Github. This pattern is based on the golden ratio, and is adjusted so that the density of LEDs is approximately uniform (with some distortion near the center. )

Tape the template to some scrap cardboard (cereal boxes seem to work well), and use a push-pin or thumbtack to puncture holes for the LEDs.


Step 2: Add LEDs

We will affix the LEDs to the board, and then thread wire and beads through them to make electrical connections. I used round nosed pliers to shape the LED leads into loops.

One problem I had with previous attempts at LED bead weaving was damage to the LEDs during soldering, due to heat and mechanical stress. To fix this, I added glass seed beads as spacers. Spacer beads allow a bit more distance between the solder point and the LED itself, and dissipate some heat and mechanical stress.

Add a spacing seed bead and shape the top loop first (I kept the anodes on the top). Add another spacing bead to the other lead, insert the LED into the "board", and shape the lead on the back. It is also possible (and probably easier, to be honest) to wrap the LED leads around the wires as you solder them, although I have not tried this approach.

Step 3: Wire up circuit with beads

We'll use medium-gauge bare copper or brass wire to hook up the LEDs. To make things beautiful, and to insulate the driving wires to prevent shorts, we'll wrap the wire in glass bugle and seed beads.
  • Use a wire that is thin enough to thread through the beads easily, but thick enough that it won't break from fatigue.
  • Avoid excessive force; this could crack the glass beads or damage the LEDs.
  • Leave 2-3 mm clearance around each LED lead, to make sure there is space to solder properly.
I found it necessary to carefully pull the wire through the beads with pliers, as it did not slide easily. Using thinner wire seemed to help.

Prepare the reverse similarly.

Step 4: Solder and electrical test

Solder the LEDs to the wires. With this specific template, the driving lines for the front and for the back meet at the center and the perimeter. Solder these together as well.

Remember to use the correct current-limiting resistors to avoid burning out the (painstakingly assembled) LEDs. The resistor calculator here is nice.

All working! (almost)

Step 5: Mounting

Remove the cardboard support carefully to avoid damaging the LED circuit. I peeled away the paper with pliers, 1-2 millimeters at a time. The patience is worth it, since it is difficult to repair damage at this stage. (That said, I did break a few solder connections during this step, but they were easy enough to fix)

Using short pieces of copper wire, tie several willow branches together to form a circle. I used branches that had been formed in a rough circle by tying them around a kitchen pot as they dried. A better shape was possible by tying several branches together and tightening things incrementally.

Attach the LED bead dreamcatcher to the willow loop using wire ties. Space these evenly around the circumference, one for each driving line (I'm using 11). Leave the ties loose at first. Once all are in place, slowly and incrementally tighten them in a star pattern, as you would a lug nut. This should further pull the willow loop into a circular shape. Do not over-tighten, and be careful not to damage the circuit.

Run insulated wire around the willow loop to connect each of the driving lines. Old Ethernet cables are an excellent source of twisted pair copper wire, and that's what I used here. Another useful trick for cable management twisting two strings together to form a larger rope. One nice thing about charlieplexing is how few driving lines it uses: all 110 LEDs here can be driven with a single cable.

Step 6: Software

Once everything is hooked up to the Arduino (pro mini in this case), you can start to play around with programming. In this case I got a bit lazy, and hastily ported some old game of life code, with some added zooming and rotation. It's not quite right, but looks nice.

Not bad for $5.50
  • LEDs: $1 from Ebay;
  • Pro-mini compatible: $2 from Ebay.
  • Beads: $1.50 from Ebay
  • Copper wire: $1 from Ebay
  • Willow branches: free
  • Cardboard, paper, insulated wire: recycled
  • Soldering and crafting supplies: already available.

Building a 'papercraft' LED marquee

Long, dark winter nights demand some tinkering and crafts. Arduino LED projects are fun, but custom circuit boards might not always be in the budget. Thankfully, discrete LEDs can be found on Ebay for less than 1¢ apiece, and cardboard circuits are a thing. Can we build a scrolling marquee display with nothing more than some LEDs, cardboard, and paper?




We'll lay out and solder our LED marquee on cardboard, and build some dividers to separate pixels, and print a little screen on top to diffuse the light.

We will use a "Charlieplexing" layout to control many LEDs using only a few pins. This can be a difficult to lay out by hand. Thankfully, there is a trick: if we're willing to tilt the grid diagonally, we can use a pattern that is easy to layout and assemble. The code to drive the display gets a bit confusing, but one can always manually map the LED locations one-by-one, if push comes to shove.

Past project links


Step 0: Gather materials

I recommend bright LEDs, since the paper diffuser blocks some light. "Super bright" LEDs inside a clear packaging should work. "Hat top" wide-angle LEDs are nice because they cast light in all directions, making it easier to get a good display even if all the LEDs aren't quite aligned.

Other materials include a soldering kit and wire snips, as well as paper crafting supplies: scissors, tape, paper, scrap cardboard, and a hobby knife. We'll also use a pin to punch holes in the cardboard for the LEDs. Oh! and an Arduino, jumper wires, and current limiting resistors as well, of course.
  • LEDs (110 in this build), scrap wire, current-limiting resistors, and an Arduino
  • Soldering station, wire snips, low-temperature solder
  • Paper crafting tools: scissors, tape, x-acto knife, push pin
  • Scrap cardboard, paper, pen, printer


Step 1: Prepare circuit (card)board

First, we'll need to design our layout. We'll use a diagonal version of charlieplexing, to simplify soldering. Design files for this project are on github. I used this template.

For "diagonal multiplexing", we'll have the cathodes on the front of the board, zigzagging diagonally, and the anodes on the reverse, zigzagging the other way. The lines wrap around at the edges. This can be a bit confusing at first, so reading through the blog post and working through some layouts by hands might be helpful!

For the cardboard, we want something stiff but not to thick. Cereal boxes are perfect. Tape the template to cardboard, or draw the pattern by hand. Use a thumb-tack or push-pin to poke one hole in the cardboard for each LED (just one hole as we'll wire up the other pins on the front).

After punching holes for the LED leads, trace the circuit on the reverse, for reference when soldering.

Step 2: Solder LEDs

I wired up the anodes (positive, +, usually the long wire) on the reverse, and the cathodes (negative, -, usually near the flat edge of the LED) in the front. It doesn't matter whether the anodes or cathodes are on the front/back, but it does matter that all LEDs go the same way. Be careful not to switch any!

Without a rigid PCB, the LEDs get a bit wobbly, which makes soldering tricky. I soldered the LEDs one row at a time, soldering both the front and the back of the board, so that the previously-soldered LEDs are held stiffly in place.

Test the LEDs as you go, making sure that they light up as expected. It's easier to correct fixes before the whole matrix is soldered in to place. I accidentally put some lights in backwards, and also damaged some from mechanical stress when soldering. A couple mistakes are not so bad!

Try to minimize mechanical stress and overheating, as this can damage LEDs. A temperature-controlled soldering station and low-temperature solder may help. 

Step 3: Test circuit

After step 2, you may want to pause and test that all LEDs are working well. If your following this example, you should have 11 control lines controlling a 5x22 LED matrix.

You'll need to write some code to scan the LEDs. Scanning them one at a time (at first) is useful. When testing, use current limiting resistors, and calculate the resistance correctly for the color of LEDs you used. To be conservative, I used 330Ω resistors. It is very sad to burn out all your LEDs after spending all that time soldering them. This online resistor calculator is handy.

To get a brighter display, you might want to consider row-column driving, rather than lighting the LEDs one at a time. This is a bit out-of-spec in a charlieplexing setup, since each pin on the Arduino is only technically supposed to source or sink 40mA of current. So far, I haven't had any issues with it.

Once everything is working well, you can consider lowering the current resistors to match the peak current of the LEDs. Most LEDs can handle extra current briefly. If you're scanning a multiplexed display rapidly, LEDs will be on only a fraction of the time. Lowering the current limiting resistor increases the power, and the brightness, of the display. Still, take care not burn out the display!

Step 4: Build case

We need to build a case for the LED matrix, to help confine and diffuse the light, and give everything a polished look (or as polished as can be, for a paper marquee).

To divide the light between LEDs, I cut thin strips of cardboard. These should be only slightly taller than the LEDs themselves, to avoid absorbing excess light. These strips then supported a paper overlay, which helps diffuse the light and blacks out any regions except for the "pixels".

The paper dividers leak light, and the paper overlay absorbs too much, so things are dimmer and fuzzier than on a proper LED marquee, but it looks ok in indoor lighting.


Step 5: Software

Now that we have our "papercraft" LED marquee, we can play around with programming it. I enjoyed designing various bitmap fonts, and hooking up to the serial port on a computer to print outputs from the terminal.

This display is a bit tricky to code for, owing to the unusual LED layout. If all else fails, you can store the anode/cathode pins for each light in a look-up-table. To start, try lighting up the LEDs one at a time. Once this is working well, you may want to try row-column scanning.

In charlieplexing, we use the same pins to source and sink current. Arduino pins are limited to 40mA, enough for 4-5 LEDs. In practice, you can drive more, but they will dim slightly. This is out of spec for the Atmega*8 chips, but I've never had an issue. One benefit of the unusual layout, which is a bit scrambled, is that it's somewhat rare to need more than 4-5 LEDs on each driving line, for scrolling text.

To get a smooth and bright display, you might want to write groups of pins directly by writing to the PORT and DDR registers. To make this even faster, its worth storing the required PORT/DDR register states directly, and using a small timer interrupt routine to rotate through the configurations for each scan-line of the display. For best results, you may need to turn off internal pull-up resistors, since these can source enough current to dimly light LEDs. 

If you end up with dead LEDs, you may need to mask them in your driving software so that they do not turn on. In a charlieplexed grid, a dead LED can force current through the other LEDs, leading to artifacts. 

I eventually affixed an Arduino pro mini for a more stand-alone solution. At the moment, I've hooked it up to battery power and set it to scroll some poetry.


LED multiplexing layouts for hand-crafting

Have you ever wanted to build a LED matrix display using hand-crafting methods, such as sewing, weaving, or papercraft? Designing and fabricating complex LED projects by hand, while making use of limited input-output (i/o) pins on microcontrollers/Arduino, is challenging.

Previous posts have covered how to organize LED matrix displays using "Charlieplexing", which simplifies printed circuit board (PCB) assembly and makes efficient use of i/o pins. But, what if we don't want to go through the hassle of ordering a custom PCB, or what if we want to work with individual LEDs in a craft project? Cost is also a factor: a cardstock "papercraft" display could be built from a cheap Arduino-compatible board and bulk LEDs for under $5 on Ebay, far cheaper than even the cheapest LED scrolling marquees.

LED multiplexing involves attaching multiple LEDs sharing a common anode (+ side) or cathode (- side) arrangement. Only one row or column is active at a time, and rows/columns are scanned rapidly so that all lights may appear to be on.
Carlieplexing is similar, but uses the same set of microcontroller pins for the anodes and the cathodes. Grid locations where the anode and cathode are now the same pin are excluded (blacked out LEDs, right, below). A previous post covered how to make the best use of the layout space for Charlieplexing LED matrices.

For hand-crafted projects, we'd like a way to build multiplexed layouts as simply as possible, without extra "wires" tracing throughout the project. This can be done by using a diagonal slice of the charlieplexing grid layout, which allows the driving lines to wrap around the edges of the project:

This diagonal layout is unconventional, and at first might not seem to lend itself to projects that need a rectangular grid, for example to display text. The geometry is flexible, however, and allows for distortion and rearrangement of the LED positions.

For example, individual rows can be shifted to create a rectangular layout (a), and the grid may be stretched to create a hexagonal grid (b), which is convenient for tiling red, green, and blue LEDs for a full-color display (but see caveats about mixing different color LEDs in the example project, below).  Since the layout is periodic in the long axis, it can be wrapped onto polar (c) or cylindrical coordinates (d), creating some fun possibilities!

Test project: LED bead weaving

To illustrate this layout approach, I've built a small woven display using a "bead weaving" approach. Individual LEDs are strung on a copper wire, which is decorated with glass beads for insulation and stiffness.

For this design, I first determined the layout geometry on paper, and mounted the LEDs in cardboard for stability when soldering, clipping the cardboard away once the project was complete. It's hard to replace damaged LEDs, so take care when assembling and testing the project.

If mixing different color LEDs, ensure that the lowest forward voltage is no less than half the highest forward voltage, otherwise the current might "skip" higher-voltage LEDs by passing through two low-voltage ones. Check the maximum instantaneous current ratings for your LEDs, and be sure to add current-limiting resistors.

I made several mistakes in this assembly, including forgetting to leave gaps in the beads to allow for soldering, and soldering at a temperature high enough to damage the LEDs. Be careful not to overheat the LEDs: without the added mechanical stability of a PCB, melting or softening of the plastic can damage the chip inside.

Additional projects using this design and layout approach include a paper scrolling marquee, and a light-up dreamcatcher.

To construct: (A) Design the layout grid on stiff cardboard. Use round-nose pliers to form the LED leads into loops, (just the cathodes at first). Place the LEDs in the cardboard layout, then form the loops for the anodes other side. Thread copper wire through the project to connect the LEDs, optionally attaching glass beads for insulation and aesthetics, and solder. (B) This example project uses 6 control lines to drive 5 columns of colored LEDs.  (C) Finished project; (some LEDs were damaged in assembly). The Arduino source code scans each light one-at-a-time.



Dissociation between sustained single-neuron spiking β-rhythmicity and transient β-LFP oscillations in primate motor cortex

Some of my thesis work has just been published!

Rule et al. 2017 explores the neurophysiology of beta (β) oscillations in primates, especially how single-neuron activity relates to population activity reflected in local field potentials (a.k.a. "brain waves").

β (~20 Hz) oscillations occur in frontal cortex. We've known about them for about a century, but still don't understand how they work or what they do. β-wave activity is related to "holding steady", so to speak.

β is dysregulated in Parkinson's, in which movements are slowed or stopped. β is also reduced relative to slow-wave activity (θ) in ADHD, a disorder associated with motor restlessness and hyperactivity.

I looked at β oscillations during movement preparation, where β seems to play a role in stabilizing a planned movement. We found that single neurons had very little relationship to the β-LFP brain waves. However! This appears to be for a good reason: the firing frequencies of neurons store information about the upcoming movement, and so are diverse and cannot lock to a single frequency.

Anyone who's played in an orchestra knows that when notes are just slightly out of tune, you get interference patterns called beats. The same thing is happening in the brain, where many neurons firing at slightly different "pitches" cause β-LFP fluctuations, even though the underlying neural activity is constant.

This result provides a new explanation for how β-waves can appear as "transients" during motor steady-state: the fluctuations are cased by "beating", rather than changes in the β activity in the individual neurons. This differs from the prevailing theory for the origin of β transients in more posterior brain regions.

Optogenetic Stimulation Shifts the Excitability of Cerebral Cortex from Type I to Type II: Oscillation Onset and Wave Propagation

A new paper by Stewart Heitmann et al. could help us understand what happens when we stimulate cerebral cortex in primates using optogenetics. Modeling how the brain responds to stimulation is important for learning how to use this new technology to control neural activity.

Optogenetic stimulation elicits gamma (~50 Hz) oscillations, the amplitude of which grows with the intensity of light stimulation. However, traveling waves away from the stimulation site also emerge.

It's difficult to reconcile oscillatory and traveling-wave dynamics in neural field models, but Heitmann et al. arrive at a surprising and testable prediction: the observed effects can be explained by paradoxical recruitment of inhibition at low levels of stimulation, which changes cortex from a wave-propagating medium to an oscillator. (Excitation later overwhelms inhibition, giving rise to the observed gamma oscillations.)


Wilson-Cowan neural fields in WebGL

Update: Dropbox no longer serves live pages from their public folders, so hosting has moved to Github. Basic WebGL example have moved to the "webgpgpu" repository, including the psychedelic example pictured to the left. Additional neural field models are hosted at the "neuralfield" repository

WebGL offers a simple way to write portable general-purpose GPU (GPGPU) code with visualization. The Github repository WebGPGPU walks through a series of examples to bring up a port of Wilson-Cowan neural field equations in WebGL.

The Wilson-Cowan equations are a mean-field approximation of neural activity under the assumption that spiking is asynchronous, and that observations are averaged over a large number of uncorrelated neurons. Wilson-Cowan neural fields have been used to describe visual hallucinations, flicker phosphines, and many other wave phenomena in the brain.

The Wilson-Cowan simulation demo is rudimentary at the moment, but contains a couple presets and rich and diverse dynamics are possibly by varying parameters. For entertainment, there is also an example of a full-screen pattern forming system mapped to (approximate) retinal coordinates using the log-polar transform.

Other cool WebGL implementations pattern-forming systems include the Gray-Scott reaction diffusion equations by pnmeila and Felix Woitzel's reaction diffusion and fluid dynamics simulations. Robin Houston's reaction diffusion implementation is also a good reference example for learning WebGL coding, and Robter Muth's smoothlife implementation is mesmerizing. The hope is that the examples in the WebGPGPU project provide a walk-through for how to build similar simulations in WebGL, something that is not immediately obvious if following existing WebGL tutorials.

Technical notes

I've avoided using extensions like floating point textures that aren't universally supported. Hopefully the examples in WebGPGPU will run on most systems, but compatibility issues likely remain.

Most of the examples store floating point values in 8-bit integers. This works for the firing rate version of the Wilson-Cowan equations because the firing rate is bounded between 0 and 1, so fixed precision is adequate. There are some caveats here. For example, how floating point operations are implemented, and how floats are rounded when being stored in 8-bit values, are implementation dependent. These simulations a quite sensitive to parameters and rounding errors, so different implementations can lead to different emergent dynamics. A partial workaround is to manually control how floats are quantized into 8-bit values. Floats can also be stored in 16 or 32 bit fixed-point precision, at the cost of performance. My understanding is that the default precision for fast floating point operations on the GPU is fairly low, such that 16 bits can capture all of the available precision for the [0,1] range.

The quantization of state variables can lead to numerical errors if the integration step size is too small relative to the timescales of the system. In short, if states are changing too slowly, their increments becomes smaller than 1/256, and numerical accuracy degrades because state changes are rounded-out. Moving to 16-bit precision lessens this issue, but at a cost of an approximately 2-fold slowdown, and so is not implemented except in one example.

Working with the WebGL library feels quite clumsy, because in essence the API exposes the GPU as a state machine. WebGPGPU includes some libraries that hide a lot of the boilerplate and expose a more functional interface for GPU shaders (kernels). For simulations on a grid, there is additional boilerplate to gain access to single pixes. One must tile the viewport with polygons, provide a default fragment shader, and set the viewport and canvas sizes to match the on-screen size. WebGPGPU hides this difficulty, but also walks through this process in the early examples to make it clear what is really happening.

Passing parameters to shaders involves a fair amount of overhead in Javascript, which becomes prohibitive for shaders with a large number of parameters. However, compiling shaders has relatively little Javascript overhead. In practice it is faster to include scalar parameters as #defines rather than pass them as uniforms. WebGPGPU contains some routines to phrase shader compilation as a sort of 'partial evaluation'.

This is a work in progress.


Numerically stable Viterbi algorithm in Python for hidden markov model state inference

The Python demonstration of the Viterbi algorithm on Wikipedia is numerically unstable for moderate to large problem sizes. This implementation is phrased in terms of log probabilities, and so has better numerical properties. Please reuse, creative commons.

def hmm_viterbi(Y,logP,logA,logB):
    See https://en.wikipedia.org/wiki/Viterbi_algorithm

    Y : 1D array
        Observations (integer states)
    logP : array shape = (nStates ,)
        1D array of priors for initial state
        given in log probability
    logA : array (nStates,nStates)
        State transition matrix given in log probability
    logB : ndarray K x N
        conditional probability matrix
        log probabilty of each observation given each state
    K = len(logP)         # Number of states
    T = len(Y)            # Number of observations
    N = np.shape(logB)[1] # Number of states
    Y = np.int32(Y)

    assert np.shape(logA)==(K,K)
    assert np.shape(logB)==(K,N)

    # The initial guess for the first state is initialized as the
    # probability of observing the first observation given said 
    # state, multiplied by the prior for that state.
    logT1 = np.zeros((K,T),'float') # Store probability of most likely path
    logT1[:,0] = logP + logB[:,Y[0]]

    # Store estimated most likely path
    T2 = np.zeros((K,T),'float')

    # iterate over all observations from left to right
    for i in range(1,T):
        # iterate over states 1..K (or 0..K-1 with zero-indexing)
        for s in range(K):
            # The likelihood of a new state is the likelihood of 
            # transitioning from either of the previous states.
            # We incorporate a multiplication by the prior here
            log_filtered_likelihood = logT1[:,i-1] + logA[:,s] + logB[s,Y[i]]
            best = np.argmax(log_filtered_likelihood)
            logT1[s,i] = log_filtered_likelihood[best]
            # We save which state was the most likely
            T2[s,i] = best

    # At the end, choose the most likely state, then
    # Iterate backwards over the data and fill in the state estimate
    X     = np.zeros((T,) ,'int'  ) # Store our inferred hidden states
    X[-1] = np.argmax(logT1[:,-1])
    for i in range(1,T)[::-1]:
        X[i-1] = T2[X[i],i]
    return X