Coding For Inspiration


The following is a personal reflection on a couple of good days playing with bynase. Study it with my original notes to see how much liberty I take with my programming problems and how this enables inspiration. -- WardCunningham

Let's think for a moment where the inspiration in BiologicallyInspired computing might take place. Our goal is to change computing not biology. So we program.

RichardGabriel has pointed out that to become a poet one must write many poems, thousands in fact. He argues, and I agree, that programming is no less demanding. We'll look at my own unfinished work and hope to see a trace of inspiration from coding.

We examine notes from two mornings of day dreaming about code I was about to write. These notes constitute a rare record as I usually do this sort of thinking in my head. Like day dreams, my notes wander from idea to idea, from problem to solution to solution refined to related problem. I'm always thinking about how each solution will work within the "biological" constrains I've imposed.

I was considering how I might write a program that would detect the rate at which morse code was sent. I had already decided that I'd devote a separate chip to detect the rate and then output the rate in BynaseProtocol so that it could be manipulated before it was used elsewhere. I write the program three times, each time in more detail.

	if > 2 x then 
		x ..= mark / 3
	if < 2 x then
		x ..= mark

My first pseudo-code used a made-up operator, ..= , which stood for average the new value into a running sum somehow. This got me thinking about how that averaging might work. I needed a longer time constant than I was getting with even eight filters in ValueFilterMeter. Each stage in ValueFilterMeter had kept 1/2 of an old value and added 1/2 of the new. I needed a much larger reservoir of old. That meant more than eight bits.

	x' = (x - 1/256 x) + 1/256 a

Now I'm thinking about what might be easy with the instructions at hand. Grabbing the high eight bits of a sixteen bit number is easy and, if used as lower bits, is like dividing by 256. This codes out nicely into four instructions (with typo corrected).

	xl = xl - xh
	xh = xh - 0 - borrow
	xl = xl + a
	xh = xh + 0 + carry

But does it work? The trouble with collapsed code like this is that when it doesn't work, there's not much to study. I chose to simulate instead. I wrote the perl program that would match the borrow and carry that connect the pieces of my "big reservoir" and watched it fill. (This lead to a conversation with my brother as to why exp(-1) makes a good goal. I thought .707 was the engineering tradition, but that constant has to do with sine waves, not this kind of filter.)

I wrote the code for the FilterTransform which worked first time except that it seemed to run 10x faster than expected. I eventually wrote a 24-bit version exploiting what I now saw as the pattern in the instructions. This one was really slow, with a time constant approaching a minute or so. Then I discovered my mistake: I was calling the calculation way too often. With this corrected, 16-bits was pleanty slow. Ultimately this turned out to be a great way to adjust the filter's timeconstant.

I really enjoyed patching around various signals into this filter, including its own output. This made a great latch, much more stable than the cross-coupled NegativeTransform that I'd played with before. Of course this is due to the filter taking the sampling noise out of the signals at the cost of latching speed.

The filter responded so well in feedback configurations that I spent the next morning daydreaming about networks of just filters. I realize I need input isolation to get the diffusion effects I want. I'm thinking I'll have these filters driving ServoMotor(s) which will wave gracefully like amber grain.

The cross-connecting turned out to be too hard to draw with ascii graphics so I used scratch paper instead (lost?). I'm then sidetracked into an exercise of cutting and pasting ascii graphics because it should be easy to exploit the circuit regularity and get big pictures for free.

	

But wait, Bynase has some intrinsic isolation that I've yet to really exploit. I imagine for a moment that my chips don't have separate inputs and outputs, pi and po, but instead have two input/outputs I call px. This would work, no?

	

I'm liking this a lot. I start thinking that I should make all the chips work this way. I redesign the bynase kernel and try coding up the dual-px filter which turns into a three or five instruction program depending on how I want my diffusion to work. Note here that I forgot I would have to call into bynase, where all the work is done.

	main:
		mov px1,px1f
		add px1,px2f	; sum filter outputs, not inputs
		asr px1
		mov px2,px1	; same output on px2 as px1
		rjmp main

Two months elapse before I get around to implementing this over the Memorial Day weekend, 2006. This is the test setup:

    knob --> filter <--> filter <-- knob

Some observations:

  • The knobs were signaling at a rate 1/4 the filters and this was way too slow for the two-way filter to even see the knobs. I took the idle out of the knob loop measured them runing about 5% faster than the filter when things started working as expected.

  • Its very hard to tell what is going on by watching the signals going both ways on a single wire. I had a scope sync coming out of the knob code and that cleared up the picture a little, but not enough. The filters had a led output that echoed their output signal and that was indespensable for understanding the circuit.

I had trouble keeping track of everything that was going on at once. One TV was not enough. I tried hooking up the ScribblerProject, which was interesting, but not informative. Audio worked better setup like this:

    knob -+-> filter <-+-> filter <-+- knob
          +-> tone     +-> tv       +-> tone

This made some strange music. I'm still trying to find a way to describe it.

 

Last edited May 28, 2006
Return to WelcomeVisitors