m8ta
you are not logged in, login. new entry
text: sort by
tags: modified
type: chronology
{455} is owned by tlh24 ehanson.{319} is owned by tlh24.{231} is owned by tlh24.{469} is owned by tlh24.{433} is owned by tlh24.{555} is owned by tlh24 ryohei.{602} is owned by tlh24 ana.{509} is owned by tlh24.{589} is owned by tlh24.{561} is owned by tlh24 ryohei.{547} is owned by tlh24 ryohei.{560} is owned by tlh24 ryohei.{564} is owned by tlh24 ryohei.{562} is owned by tlh24 ryohei.{563} is owned by tlh24 ryohei.{556} is owned by tlh24 ryohei.{549} is owned by tlh24.{543} is owned by tlh24.{541} is owned by tlh24.{534} is owned by tlh24.{535} is owned by tlh24.{524} is owned by tlh24.{492} is owned by tlh24.{518} is owned by tlh24.{517} is owned by tlh24.{512} is owned by tlh24.{510} is owned by tlh24.{508} is owned by tlh24.{499} is owned by tlh24.{490} is owned by tlh24.{461} is owned by tlh24.{391} is owned by tlh24.{430} is owned by tlh24.{453} is owned by tlh24.{89} is owned by tlh24 ana.{421} is owned by tlh24.{436} is owned by tlh24.{399} is owned by tlh24.{426} is owned by tlh24.{424} is owned by tlh24.{423} is owned by tlh24.{408} is owned by tlh24.{346} is owned by tlh24.{380} is owned by tlh24.{395} is owned by tlh24.{396} is owned by tlh24.{406} is owned by tlh24.
[0] Ashe J, Force and the motor cortex.Behav Brain Res 87:2, 255-69 (1997 Sep)[1] Cabel DW, Cisek P, Scott SH, Neural activity in primary motor cortex related to mechanical loads applied to the shoulder and elbow during a postural task.J Neurophysiol 86:4, 2102-8 (2001 Oct)[2] Cheney PD, Fetz EE, Functional classes of primate corticomotoneuronal cells and their relation to active force.J Neurophysiol 44:4, 773-91 (1980 Oct)[3] Evarts EV, Relation of pyramidal tract activity to force exerted during voluntary movement.J Neurophysiol 31:1, 14-27 (1968 Jan)[4] Evarts EV, Activity of pyramidal tract neurons during postural fixation.J Neurophysiol 32:3, 375-85 (1969 May)[5] Humphrey DR, Schmidt EM, Thompson WD, Predicting measures of motor performance from multiple cortical spike trains.Science 170:959, 758-62 (1970 Nov 13)[6] Thach WT, Correlation of neural discharge with pattern and force of muscular activity, joint position, and direction of intended next movement in motor cortex and cerebellum.J Neurophysiol 41:3, 654-76 (1978 May)[7] Wetts R, Kalaska JF, Smith AM, Cerebellar nuclear cell activity during antagonist cocontraction and reciprocal inhibition of forearm muscles.J Neurophysiol 54:2, 231-44 (1985 Aug)[8] Georgopoulos AP, Ashe J, Smyrnis N, Taira M, The motor cortex and the coding of force.Science 256:5064, 1692-5 (1992 Jun 19)[9] Kalaska JF, Cohen DA, Hyde ML, Prud'homme M, A comparison of movement direction-related versus load direction-related activity in primate motor cortex, using a two-dimensional reaching task.J Neurosci 9:6, 2080-102 (1989 Jun)[10] Li CS, Padoa-Schioppa C, Bizzi E, Neuronal correlates of motor performance and motor learning in the primary motor cortex of monkeys adapting to an external force field.Neuron 30:2, 593-607 (2001 May)[11] Sergio LE, Kalaska JF, Systematic changes in directional tuning of motor cortex cell activity with hand location in the workspace during generation of static isometric forces in constant spatial directions.J Neurophysiol 78:2, 1170-4 (1997 Aug)[12] Sergio LE, Kalaska JF, Systematic changes in motor cortex cell activity with arm posture during directional isometric force generation.J Neurophysiol 89:1, 212-28 (2003 Jan)[13] Taira M, Boline J, Smyrnis N, Georgopoulos AP, Ashe J, On the relations between single cell activity in the motor cortex and the direction and magnitude of three-dimensional static isometric force.Exp Brain Res 109:3, 367-76 (1996 Jun)[14] Maier MA, Bennett KM, Hepp-Reymond MC, Lemon RN, Contribution of the monkey corticomotoneuronal system to the control of force in precision grip.J Neurophysiol 69:3, 772-85 (1993 Mar)[15] Hepp-Reymond M, Kirkpatrick-Tanner M, Gabernet L, Qi HX, Weber B, Context-dependent force coding in motor and premotor cortical areas.Exp Brain Res 128:1-2, 123-33 (1999 Sep)[16] Smith AM, Hepp-Reymond MC, Wyss UR, Relation of activity in precentral cortical neurons to force and rate of force change during isometric contractions of finger muscles.Exp Brain Res 23:3, 315-32 (1975 Sep 29)[17] Cooke JD, Brown SH, Movement-related phasic muscle activation. II. Generation and functional role of the triphasic pattern.J Neurophysiol 63:3, 465-72 (1990 Mar)[18] Almeida GL, Hong DA, Corcos D, Gottlieb GL, Organizing principles for voluntary movement: extending single-joint rules.J Neurophysiol 74:4, 1374-81 (1995 Oct)[19] Gottlieb GL, Latash ML, Corcos DM, Liubinskas TJ, Agarwal GC, Organizing principles for single joint movements: V. Agonist-antagonist interactions.J Neurophysiol 67:6, 1417-27 (1992 Jun)[20] Corcos DM, Agarwal GC, Flaherty BP, Gottlieb GL, Organizing principles for single-joint movements. IV. Implications for isometric contractions.J Neurophysiol 64:3, 1033-42 (1990 Sep)[21] Gottlieb GL, Corcos DM, Agarwal GC, Latash ML, Organizing principles for single joint movements. III. Speed-insensitive strategy as a default.J Neurophysiol 63:3, 625-36 (1990 Mar)[22] Corcos DM, Gottlieb GL, Agarwal GC, Organizing principles for single-joint movements. II. A speed-sensitive strategy.J Neurophysiol 62:2, 358-68 (1989 Aug)[23] Gottlieb GL, Corcos DM, Agarwal GC, Organizing principles for single-joint movements. I. A speed-insensitive strategy.J Neurophysiol 62:2, 342-57 (1989 Aug)[24] Ghez C, Gordon J, Trajectory control in targeted force impulses. I. Role of opposing muscles.Exp Brain Res 67:2, 225-40 (1987)[25] Sainburg RL, Ghez C, Kalakanis D, Intersegmental dynamics are controlled by sequential anticipatory, error correction, and postural mechanisms.J Neurophysiol 81:3, 1045-56 (1999 Mar)[26] Georgopoulos AP, Kalaska JF, Caminiti R, Massey JT, On the relations between the direction of two-dimensional arm movements and cell discharge in primate motor cortex.J Neurosci 2:11, 1527-37 (1982 Nov)[27] Ashe J, Georgopoulos AP, Movement parameters and neural activity in motor cortex and area 5.Cereb Cortex 4:6, 590-600 (1994 Nov-Dec)[28] Caminiti R, Johnson PB, Urbano A, Making arm movements within different parts of space: dynamic aspects in the primate motor cortex.J Neurosci 10:7, 2039-58 (1990 Jul)[29] Caminiti R, Johnson PB, Galli C, Ferraina S, Burnod Y, Making arm movements within different parts of space: the premotor and motor cortical representation of a coordinate system for reaching to visual targets.J Neurosci 11:5, 1182-97 (1991 May)[30] Matsuzaka Y, Picard N, Strick PL, Skill representation in the primary motor cortex after long-term practice.J Neurophysiol 97:2, 1819-32 (2007 Feb)[31] Fu QG, Suarez JI, Ebner TJ, Neuronal specification of direction and distance during reaching movements in the superior precentral premotor area and primary motor cortex of monkeys.J Neurophysiol 70:5, 2097-116 (1993 Nov)

{644} hide/ edit[17] /
Given proper implementation of fixed-point sine and cosine, we present the C portion of our microstepping controller below, hopefully commented to a sufficient extent to make it intelligible and to document the logic behind our design.

#include <msp430x54x.h>
#define INCR 1
#define PI2 (12868) //we use a 11 bit fixed-point representationf of motor angles.  
	// 12867 = 2*pi*2^11.  
#define TIMER_SCL	128
#define SHUTTER_CLOSED 	0 //defines used in the state-machine control of the shutter. 
#define SHUTTER_OPEN	1
#define SHUTTER_SMALL	2

	//Start of Stepper Motor Program
	//ME270 Project

short theta1 = 0; //the MSP430 is a 16-bit processor. 
short theta2 = 0; //hence, most datatypes should be 'short' for efficiency.
short theta1_v = 0; //we cannot control the poition of the stepper motors directly, 
short theta2_v = 0; // since we only have 3 bits of control from the parallel port. 
// also, direct position control of postion would cause the stepper to miss steps 
// smooth position change and limited acceleration is guaranteed by controlling the velocity. 

short shutter_state = 0; // none of the steppers have encoders, 
	// so we keep track of the shutter position here.  
short shutter_cmd ;  //this is set in ISR (interupt service routine) 
	// and read, and acted upon, in the main loop. 

short qsin(short i){
	//i goes from  0 pi/2 base 11 or... 
	// 0 to 3217
	short cube, fifth, result; 
	cube = mply_11(i,i);
	cube = mply_11(cube, i); 
	fifth = cube; 
	fifth = mply_11(fifth, i);
	fifth = mply_11(fifth, i); 
	//our approximation to sine based on taylor series: 
	//original: sin(x) = x - x^3/3! + x^5/5!
	//sin(x) = x - x^3/(8+32+128) + x^5/128 
	result = i - 
		((cube >> 3) + (cube >> 5) + (cube >> 7)) + (fifth >> 7);
	//result is base 11.  need it to be base 7. (0 to 127)
	result = result >> 4; 
	if(result > TIMER_SCL) result = TIMER_SCL; 
	return (short)result; 
}

// this is an even more simplified version of sin - 
// made in an attempt to make the microstepping smoother. 
// it turned out to not matter very much.  to get very smooth stepping , 
// may have to develop an inverse model of the nonlinear stepper motors 
// ** quantitatively **
short qsin2(short i){
	//i goes from  0 pi/2 base 11 or... 
	// 0 to 3217
	short cube, result; 
	cube = mply_11(i,i);
	cube = mply_11(cube, i); 
	//our approximation to sine based on taylor series: 
	//original: sin(x) = x - x^3/3! + x^5/5!
	//sin(x) = x - x^3/(8+32+128) + x^5/128 
	result = i - (cube >> 3) ;
	//result is base 11.  need it to be base 7. 
	result = result >> 4; 
	if(result > TIMER_SCL) result = TIMER_SCL; //maximum..
	return (short)result; 
}

short isin(short i){
	// i is base 2^11
	//but we accept 0 to 2*pi or 12867
	if(i >= 0 && i < 3217) return qsin(i); 
	else if(i >= 3217 && i < 6434) return qsin(6434 - i); 
	else if(i >= 6434 && i < 9651) return -1*qsin(i - 6434); 
	else if(i >= 9651 && i < 12867) return -1*qsin(12867 - i); 
	else return 0; 
}

short icos(short i){
	// i is base 2^11
	//but we accept 0 to 2*pi or 12867
	if(i >= 0 && i < 3217) return qsin(3217 - i); 
	else if(i >= 3217 && i < 6434) return -1*qsin(i - 3217); 
	else if(i >= 6434 && i < 9651) return -1*qsin(9651 - i); 
	else if(i >= 9651 && i < 12867) return qsin(i - 9651); 
	else return 0; 
}

//this interrupt is triggered by the parallel port. 
//because we only have 3 lines and need 8 commands, 
//after triggering (0 to 1 transition on PORT2.0 ), 
//the control program on the PC will either hold the pin up 
// (indicating a velocity step command) or drop it (indicating shutter/stop cmd). 

#pragma vector=PORT2_VECTOR
__interrupt void port2_ISR (void)
{
	//need to read the two pins to figure out which axis to change.
	short k; 
	for(k=0; k<8; k++){
		P9OUT ^= 0x4;	
	}
	switch(P2IN & 0x7){
		case 1: theta1_v += INCR;  break; 
		case 3: theta1_v -= INCR;  break; 
		case 5: theta2_v += INCR;  break; 
		case 7: theta2_v -= INCR;  break; 
		case 0: shutter_cmd = SHUTTER_CLOSED; break; 
		case 2: shutter_cmd = SHUTTER_SMALL; break; 
		case 6: shutter_cmd = SHUTTER_OPEN; break; 
		case 4: theta1_v = 0; theta2_v = 0; break;
	}
	P2IFG = 0; //clear the interupt. 
}

#pragma vector=TIMER1_A0_VECTOR 
__interrupt void timera1_ISR (void)
{
	return; //if this vector is not here and the interupt is enabled, then the proc will crash! 
}
// have to integrate the velocity at a consistent rate, 
// hence we pushed integration as well as the sine/cosine computation 
// into this timer interrupt. 
#pragma vector=TIMER1_A1_VECTOR 
__interrupt void timera11_ISR (void)
{
	short ps, pc; 
	P1OUT ^= 0xFF; //toggle P1 to indicate the update rate. (the led is there)
	TA1CTL = 0x0004; //reset counter
	TA1CTL = 0x0112; //turn back in interrupts.	

	theta1 += theta1_v; 
	theta2 += theta2_v;
	
	if(theta1 > PI2) theta1 -= PI2; 
	if(theta1 < 0) theta1 += PI2; 

	if(theta2 > PI2) theta2 -= PI2; 
	if(theta2 < 0) theta2 += PI2; 

	ps = isin(theta1)+TIMER_SCL;
	pc = icos(theta1)+TIMER_SCL;

	TA0CCR1 = ps; //update the counter (PWM output) registers. 
	TA0CCR4 = pc;

	ps = isin(theta2)+TIMER_SCL;
	pc = icos(theta2)+TIMER_SCL;
	
	TA0CCR2 = ps; 
	TA0CCR3 = pc;
	P1OUT ^= 0xFF; //toggle P1 to indicate the update rate. (the led is there)
	return;
}

//delay is used in moving the shutter. 
// too short, and the stepper motor controlling the shutter will skip steps! 
void delay(short time){
	short k; 
	short j = 0; 
	for(k=0; k<time; k++){
		j++; 
		j++; 
	}
}

void delay_long(short time){
	short k,j,f; 
	for(k=0; k<time; k++){
		f = 0; 
		for(j=0; j<100; j++){
			f++; 	
		}
	}
}

// ideally, we would ramp the shutter velocity up and down to maximize speed 
// and minimize time - constant velocity works fine and fast. 
#define SHUTDLY	1600
void shutter_ccw(void){
	P9OUT = 0x1; 
	delay(SHUTDLY); 
	P9OUT = 0x3; 
	delay(SHUTDLY); 
	P9OUT = 0x2; 
	delay(SHUTDLY); 
	P9OUT = 0x0; 
	delay(SHUTDLY); 	
}

void shutter_cw(void){
	P9OUT = 0x2; 
	delay(SHUTDLY); 
	P9OUT = 0x3; 
	delay(SHUTDLY); 
	P9OUT = 0x1; 
	delay(SHUTDLY); 
	P9OUT = 0x0; 
	delay(SHUTDLY); 	
}

void shutter_open(void){
	short i; 
	if(shutter_state == SHUTTER_CLOSED){
		//I was quite pleased to discover that the three shutters states
		// are exactly 5 full steps apart! 
		for(i=0; i<5; i++){ 
			shutter_ccw(); 	
		}

	}
	if(shutter_state == SHUTTER_SMALL){
		for(i=0; i<5; i++){
			shutter_cw(); 	
		}
	}
	shutter_state = SHUTTER_OPEN; 
}
void shutter_close(void){
	short i; 
	if(shutter_state == SHUTTER_OPEN){
		for(i=0; i<5; i++){
			shutter_cw(); 	
		}
	}
	if(shutter_state == SHUTTER_SMALL){
		for(i=0; i<10; i++){
			shutter_cw(); 	
		}
	}
	shutter_state = SHUTTER_CLOSED; 
}
void shutter_small(void){
	short i; 
	if(shutter_state == SHUTTER_OPEN){
		for(i=0; i<5; i++){
			shutter_ccw(); 	
		}
	}
	if(shutter_state == SHUTTER_CLOSED){
		for(i=0; i<10; i++){
			shutter_ccw(); 	
		}
	}
	shutter_state = SHUTTER_SMALL; 
}

void main (void){
	//SR = 0x02;
	short t1, t2, ps, pc; 
	short k; 
	WDTCTL = WDTPW + WDTHOLD; //stop the watchdog timer.
	// UCSCTL = Universal clock system control (registers). 
	// sets the core clock of the device. 
	_bis_SR_register(SCG0);
	//SR = SR | 0x40 ;
	// setup the digitally controlled oscillator. 
	UCSCTL0 = 0x0700; //DCO = 5, MOD = 0
	UCSCTL1 = 0x0060; //DCORSEL = 3, middle freq. 
	UCSCTL2 = 0x101F; //FLL (frequency locked loop); doesnt matter here.
	UCSCTL4 = 0x0333; //select DCOCLK for all clock sources 
	UCSCTL0 = 0x0900; //DCO = 9, MOD = 0
		// DCO = internal high-frequency oscillator). 
	//UCSCTL5 = 0x0000; 

	// setup timer A (for controlling PWM outputs)
	TA0CCR0 = TIMER_SCL*2+1; //Timer A end pulse
	TA0CCR1 = TIMER_SCL; //Timer A start pulse
	TA0CCR2 = TIMER_SCL; //Timer A start pulse
	TA0CCR3 = TIMER_SCL; //Timer A start pulse
	TA0CCR4 = TIMER_SCL; //Timer A start pulse
	TA0CTL = 0x0110; //TASSEL = ACLK; input divider=1; MCx = count up mode; 
	TA0CCTL0 = 0x0040; //sets the mode of the output: here=2, toggle/reset.
		// (produces pulses at 8Khz). 
	TA0CCTL1 = 0x00C0; //output mode: toggle/set. 
	TA0CCTL2 = 0x00C0; // same
	TA0CCTL3 = 0x00C0; // same
	TA0CCTL4 = 0x00C0; // same

	//setup timer B (for controlling theta & velocity updates). 
	TA1CCR0 = 10000; //Timer A end pulse
	TA1CCR1 = 5000; //Timer A start pulse
	TA1CCR2 = 5000; //Timer A start pulse	
	TA1CTL = 0x0004;
	TA1CTL = 0x0112; //TASSEL = ACLK; input divider=1; MCx = count up mode; 
	TA1CCTL0 = 0x0050; //sets the mode of the output: here=2, toggle/reset.
		// (produces pulses at 8Khz). 
	TA1CCTL1 = 0x00C0; //output mode: toggle/set. 
	TA1CCTL2 = 0x00C0; // same
	
	P1DIR = 0x03; //P1.0 and P1.1 to output. (the LED)
	P1SEL = 0x00;
	P1OUT = 0; 
		
	P8DIR = 0xFF; //for some reason Port 1 does not work for the dev board --  
	P8SEL = 0x7F; //hence, we switched over to Port 8, which also is connected 
	// to the timers. 
	// the P8SEL register selects the timer output as opposed to general purpose IO. 
	
	//setup port2 (computer command via parallel port) interrupt. 
	P2DIR = 0; //all inputs. 
	P2IFG = 0;
	P2IE = 0x01; //enable interupts on P2.0
	P2IES = 0; // low to high edge detect. 
	_bis_SR_register(GIE | SCG0 );  //enable interrupts, dont go to sleep.
	
	P9DIR = 0x07; 
	
	//test the shutter. first move all the way to the limit.
	// since we do not know the initial position.
	for(k=0; k<30; k++){
		shutter_cw(); 
	}
	shutter_ccw();  //step one out so we don't hit the limits later.
	shutter_state = SHUTTER_CLOSED; //this is where the init will leave it
	while(1){
		//now just sit here waiting for a shutter command from the 
		// parallel port ISR.  
		if(shutter_state != shutter_cmd){
			switch(shutter_cmd){
				case SHUTTER_OPEN: shutter_open(); break; 
				case SHUTTER_CLOSED: shutter_close(); break; 
				case SHUTTER_SMALL: shutter_small(); break;
			} 	
		}
	}
}

We has some problem getting Port1 to work, hence had to use Port8 to get the PWM signals out -- see below. Note the shutter does not need to be microstepped and instead can be controlled as per a conventional stepper motor. The pins used are marked in yellow; pin 57 is a simple pulse output.

Note that each PWM signal is generated from the same timer counter, hence they are synchronous (this is of course not necessary). Below are some examples of two phases of one motor output; in real life, of course, the PWM ratio continually changes.

Below is the development board being probed to produce the plots above.

We then used the pinouts of the NXP microcontrollers, intuited last time by probing their on-line function (specifically the auto-calibration sequence upon startup), to wire up a harness for external control of the H-bridges. Below is a picture of that (we removed the original microcontrollers to prevent contention), and the associated wiring labels.

The next task was to make a 5V to 3.2V regulator (the MSP430 only runs at 3.2V, max), nothing major just a LM317. See below.

Finally, everything was wired together. The 3.2 V supply was jumpered, as the MSP430 USB programmer provided its own power. (Amazingly, the ultra low power MSP430 could run on power from the parallel port, too!)

A level translator is needed to properly interface the 3.2V MSP430 to the 5V parallel port - we canibalized a spare JTAG adapter for this purpose. It was this that limited us to only 3 bits of control.

And that, minus the difficulty we had getting the compiler working properly, is the entirety of the microcontroller part of the project.

{648} hide/ edit[0] /

{369}
hide / edit[7] / print
ref: notes-3000 tags: darpa 2007 misha report oscillations old notes date: 02-16-2012 17:50 gmt revision:7 [6] [5] [4] [3] [2] [1] [head]

We have found the following types of neurons during acute intraoperative recrodings from the subthalamic nucleus (STN) of awake parkinson's patients. During the surgeries the patients opened and closed their hand, instrumented through a virtual-reality data glove, in order to move a cursor to randomly presented targets in a 1-dimensional field.

It is thought that the STN controls the gating and timing of movements, and this gate/relay is implicated in the pathological oscillatory loop seen in Parkinson's disease. Therefore, it is not surprising that we have found cells that are tuned to both movement initiation and simultaneously tuned to oscillatory features of the behavior.

Below the probability of firing, (red = high, blue = low) is plotted vs time (x-axis) and y (target gating signal). The target gating signal is 1 400 ms around the appearance of a new target to the right of the cursor, -1 when the target appears to the left of the cursor, and 0 everywhere else; 1 corresponds to the top of the graph, and -1 to the bottom. This probability was caluclated in sliding 50ms lags across the x axis to illuminate any fixed temporal relationships; that is, if a neuron had a high probability of firing 500 ms before target appearance, the image would be red @ a lag of 0.5 (on the x axis) and 1 on the y axis. This method is a nonparametric, minimal-assumption way of looking at the correlations between behavior and neural firing. It is only assumed that the relationship between neural firing times and behavior is stationary, e.g. it does not evolve with time; this is a relatively safe assumption given the recording are generally short.

This plot shows a neuron which fires preferentially when a target appears and the patient moves to the left (again, in this graph: y = -1 indicates target appears to the left, + 1 target to the right, and 0 otherwise). Note that there is noticable oscillations, due to the fact that the patient's behavior was very periodic, with a period of around 2 seconds. The neuron was inhibited around the instant of target apperance, independent of direction, as indicated by the blue regions at y = -1 and 1 around lag 0.

This plot shows a neuron which is inhibited just before target apperance (in this plot, y = 1 400ms around target appearance, independent of direction). That is, the neuron stops firing upon sucessful completion of a movement. This neuron shows no pathological oscillatory tuning; therefore, it might be assumed that not all of the STN is incapacitated by Parkinson's disease.

Here is another example of a neuron that does not show oscillatory firing behavior. In this graph, y = 1 when the patient is opening or closing his hand (equivalently the cursor velocity exceeds a threshold); y = 0 otherwise. This neuron is therefore inhibited during periods of movement. Note that around a lag of 2.5 seconds, the neuron has a higher probability of firing (the red region), possibly indicating positive firing upon successful completion of a movement.

Another example of a neuron that is tuned to thresholded cursor velocity, though this time, the firing rate becomes positive just around the instant of movement. Note here there is evidence of highly periodic behavior, as seen in the green/yellow regions spaced about 1.6 seconds apart along y=1. The region at lag = 1.6 secons corresponds to the movement following target acquisition, hence exhibits a higher firing rate.

This neuron, like the one above, fires strongly whenever the hand moves. Interestingly, there appeared to be no directional information in either of these cells.

Finally, we discovered that there appears to be error-correlated firing within the STN. The neuron shown above is selectively inhibited around periods where the cursor and target positions differ. In the plot above y=1 indicates the absolute value of the target position - the cursor position exceeds a threshold of 20% of the total range (this is subtly different from the target apperance signal, as the patient can over shoot or under shoot the target position with the cursur, upon which this signal will be 1.

{383}
hide / edit[13] / print
ref: notes-3000 tags: old notes date: 02-16-2012 17:50 gmt revision:13 [12] [11] [10] [9] [8] [7] [head]

what do we need to do to finish up with the human data??

  1. segment data? need to eliminate noise!!
    1. tim = manual (dan has a manual segmenting program too).
    2. dan = automatic, 2sec windows are located based on correlation to analog variables. idea: BLAST DNA search.
      1. assume stationarity?
    3. what about excluding sections or windows of data based on ISI distribution?
      1. neurons are not around long enough to make broad assumptions about stationarity.
  2. decide what to look for; or: what type of neurons are we looking for?
    1. gating neurons. req:
      1. should fire before, 400-600ms prior; min 100ms before movement.
    2. error feedback neurons.
    3. oscillatory neurons / two broad classes of neurons.
  3. can also look at intrinsic properties of the neurons themselves, e.g. oscillatory activity. However, we do not really have a control?
    1. might need a video of the patient to show that they were not moving (some other) part of their body?
  4. What about VIM?
  5. Can we predict target hit & target change?
    1. what algorithms can be used to predict things like:
      1. initiation of movement
      2. target hit
      3. target change
    2. which analog variable is best predicted by our dataset?
    3. how about resorting then predict? need some way of eliminating the crappy, noisy on-line sorting that I did.
  6. With what time lag are these cells correlated to kinesthetic movements? e.g. what are the dynamics of response?
  7. or rather, can some part of the behavior be reconstructed? we'd need at least:
      1. start
      2. stop
      3. direction
      4. force or magnitude.
    1. i might guess that the simpler (binary) analog variables will be better predicted, eg. start/stop.
  8. might want to look at the delay between STN activity and target appearance .. unfortunately, we do not have a control.

for future cases:

  1. EMG recording to see if STN/VIM are tuned to active or passive movements.
    1. problem: artifact from surface EMG may excessively contaminate the signal.
  2. larger movements, perhaps the whole arm.
  3. we looked for 'effort' cells (as in the monkeys) - should we try this again? (the one time we tried this, the patient became rather frustrated)
    1. a more fundamental question: are the cells in the STN/ VIM under voluntary control? most likely.
  4. if subcortical cells cannot do it all (e.g. motor prothesis), what can they do? It is a rather invasive procedure.
  5. should look for changes in cortical LFP and or firing properties in response to DBS.
  6. fix the ECoG recording there must be a reason why people are doing differential EEG.. though perhaps most new machines are referential.
  7. try a BIS monitor. (already in the OR, but need to determine how to get the data out)
    1. some of the neurons only fire when the patient is awake (and vice-vercia) (sleep-wake states.. that might be an interesting study.)

{188}
hide / edit[1] / print
ref: neuro notes-0 tags: STN globus_pallidus striatum diagram basal_ganglia date: 01-26-2012 17:16 gmt revision:1 [0] [head]

http://www.gpnotebook.co.uk/cache/-1248198589.htm (bitrotted)

  • note that the loop around both preserves sign, more or less, provided you take into account the D2 receptor along the 'indirect' pathway
  • this has some glaring flaws: the globus pallius external projects to the globus pallidus internal, cortex projects to STN, thalamus projects to striatum, etc.

http://www.portfolio.mvm.ed.ac.uk/studentwebs/session1/group71/john.htm

  • has a good diagram of the neurotransmitters involved in the motor selection pathway. need to understand the kinetics of the dopamine receptor family

{348}
hide / edit[4] / print
ref: notes-0 tags: clementine operant conditioning 041707 pyramidal tract tlh24 date: 01-06-2012 03:12 gmt revision:4 [3] [2] [1] [0] [head]

It appears that operant/feedback training of one neuron (channel 29, in SMA region) works fine (not great, but fine). In the experiment performed prior to visiting Seattle, on April 10 2007, I was not convinced that the neuron was controlling anything. Now, it is apparent that the monkey has some clue as to what he is doing. Today I made a simple change: I made the filtering function sum (all spikes) 1/12 * x*(x-1)^2, where x = time - time_of_spike. In comparison to a butterworth filter, this has no rebound oscillation & makes the estimation of firing rate much more transparent. It averages over approximately 500ms ~= lowcut of 1.5hz? I see no reason to change this filtering function much, as it works fine. Spikes were binned at 100hz as input to this function, but that should be equivalent to binning at 1khz etc.

Next time, i want to do 2d, where channel 62 controls the Y-axis. really should try to determine the approximate tunings of these cells. I'm somewhat concerned as this channel seems to have a much lower mean firing rate than channel 29. According to the literature, PTNs have high firing rates and strong tuning...

for reference, here is the channel used for the one-neuron BMI, recorded April 10. It has not changed much in the last 7 days.

{285}
hide / edit[13] / print
ref: notes-0 tags: motor control BMI M1 date: 01-06-2012 03:11 gmt revision:13 [12] [11] [10] [9] [8] [7] [head]

with: {277}

  • Correlations have been described between neuronal activity and the static and dynamic forces and torques generated across single joints
  • or by the whole arm
  • or by precision pinch [14,15,16]
  • or there are strong correlations to muscle activity [17,18,19,20,21,22,23,24,25]
  • or there is strong correlations to kinematic parameters
  • these kinematic parameters are dependent on location in the external workspace [10][28,29]
  • kinematic tuning can be subserved by training! [30]
  • distance to target representation [31]

____References____

{607}
hide / edit[4] / print
ref: notes-2000.09 tags: BMI recording technology Chapin Nicolelis battery Wolf date: 01-06-2012 03:09 gmt revision:4 [3] [2] [1] [0] [head]

from the book "Neural Prostheses for Restoration of Sensory and Motor Function" edited by John Chapin and Karen Moxon.

Phillip Kennedy's one-channel neurotrophic glass electrode BMI (axons apparently grew into the electrode, and he recorded from them)

Pat Wolf on neural amplification / telemetry technology

battery technology for powering the neural telemetry

{222}
hide / edit[4] / print
ref: neuro notes-0 tags: clementine thesis electrophysiology fit predictions tlh24 date: 01-06-2012 03:07 gmt revision:4 [3] [2] [1] [0] [head]

ok, so i fit all timestamps from clem022007001 & timarm_log_070220_173947_k.mat to clementine's behavior, and got relatively low SNR for almost everything - despite the fact that I am most likely overfitting. (bin size = 7802 x 1491) the offset is calibrated @ 2587 ms + 50 to center the juice artifact in the first bin. There are 10 lags. There are 21 sorted units.

same thing, but with only the sorted units. juice prediction is, of course, worse.

now, for file clem022007002 & timarm_log_070220_175636_k.mat. first the unsorted:

and the sorted:

{249}
hide / edit[5] / print
ref: notes-0 tags: sorting SNR correlation coefficient expectation maximization tlh24 date: 01-06-2012 03:07 gmt revision:5 [4] [3] [2] [1] [0] [head]

Description: red is the per-channel cross-validated correlation coeifficent of prediction. Blue is the corresponding number of clusters that the unit was sorted into, divided by 10 to fit on the same axis. The variable being predicted is cartesian X position. note 32 channels were dead (from PP). The last four (most rpedictive) channels were: 71 (1 unit), 64 (5 units), 73 (6 units), 67 (1 unit). data from sql entry: clem 2007-03-08 18:59:27 timarm_log_20070308_185706.out ;Looks like this data came from PMD region.

Description: same as above, but for the y-axis.

Description: same as above, but for the z-axis.

Conclusion: sorting seems to matter & have a non-negligible positive effect on predictive ability.

{175}
hide / edit[1] / print
ref: BMI notes-0 tags: spike filtering rate_estimation BME 265 Henriquez date: 01-06-2012 03:06 gmt revision:1 [0] [head]

http://hardm.ath.cx:88/pdf/BME265_final.pdf

{210}
hide / edit[14] / print
ref: notes-2007 tags: clementine BMI robot kinarm timarm 032807 date: 01-06-2012 00:07 gmt revision:14 [13] [12] [11] [10] [9] [8] [head]

  1. http://m8ta.com/tim/clementine.MOV -- opens with totem, MJPG compressor.
  2. http://m8ta.com/tim/timarm_servocontroller.JPG
  3. http://m8ta.com/tim/images/spikeInformation_shuffled.jpg
    1. shuffled information distribution -- high significance level ;)
  4. kinarm.
    1. http://www.hardcarve.com/tim/kinarm.JPG
    2. http://www.hardcarve.com/tim/kinarm2.JPG
    3. http://www.hardcarve.com/tim/kinarm3.JPG
  5. robot svg or timarm png
    1. http://www.hardcarve.com/tim/timarm/timarm_side.jpg
    2. http://m8ta.com/tim/robotPulleyDetail.png
  6. bmi predictions clem 032807
      1. x & y predictions
      1. x & y predictions
      1. z velocity predictions - pretty darn good, snr 2
    1. Movie of the day: http://m8ta.com/tim/clem032807_3dBMI.MPG
      1. cells for that day - 40 in all

{49}
hide / edit[1] / print
ref: notes-2005.06 tags: Crick claustrum cortex telecephalon date: 01-03-2012 15:20 gmt revision:1 [0] [head]

http://www.klab.caltech.edu/news/crick-koch-05.pdf

  • small, sheetlike region, not very think 5mm in humans.
  • between the extreme capsule and the external capsule. in the sheep
  • there are remarkably few microelectrode investigations of claustral receptive fields in the claustrum & almost none in awake animals.
  • the claustrum is interconnected with the extrastriate visual areas (17 & 18), sensory cortex, and prefrontal cortex.
  • claustrum is highly vasularized and protected from stroke via multiple arteries.
    • hence, few selective lesions of the claustrum and so we don't know what effects its absence manifests.

{212}
hide / edit[3] / print
ref: life-notes-2007 tags: electrode assay technology electrophysiology hack ad-hoc date: 01-03-2012 07:10 gmt revision:3 [2] [1] [0] [head]

properties of electrodes that are to penetrate the pia mater of a rhesus macaque:

  1. must easily go into a canned peach (in heavy or light sauce, it does not matter)
  2. does not go into pineapple cross-grain
  3. does go into the end-grain of pineapple
  4. penetrates the skin of a red grape (somewhat fresh) ~= pia
    1. The pia is a bit more tough than this, but is much less firm - if you are implanting electrodes that are any less than extremely sharp - e.g. etched - it will dimple the surface and not penetrate. Very sharp electrodes are key for getting through this tough membrane - which is even tougher in humans!
      • dimpling seems to silence cortical activity (observational evidence for this only)
      • however, once implanted lower-impedance electrodes work better. Low current microstimulation may be able to round the sharp tips of tungsten electrodes - we may want to test this.
    1. microdissection of the pia often damages the surface vasulature of the cortex, leading to localized infarctions, and hence should be avoided (unless you are really good)
    2. Bunching multiple elctrodes into one shaft - that is, making the shaft thicker and duller (albiet staggered) is not a good strategy for entering the brain (need to test the present monkeys).
  1. Cortical layer V (location of large pyramidal cells + betz cells in M1) in humans is 3-3.5mm below the surface, and ~1.6mm deep in rhesus. microwire/microwire arrays should have at least 2mm free wire length if intended for monkeys, and 4mm free wire if intended for humans.
    1. M1/S1 / central sulcus region is mostly inactive under isoflouro anesthesia, somewhat mangled/depressed with light ketamine, and silent with fentanyl. So, be careful with intraoperative recordings - the monkey/rat may be too deep, hence no cells to listen to!

{224}
hide / edit[1] / print
ref: notes-0 tags: k-means clustering neurophysiology sorting date: 01-03-2012 06:51 gmt revision:1 [0] [head]

k-means is easy!

% i want to do the k-means alg. 
v = [x y]; 
nc = 7;
dim = cols(v); 
n = rows(v); 
cent = rand(nc,dim); 
d = zeros(n, nc); 
for k = (1:500)
	for s = 1:nc
		d(:,s) = sqrt(sum((v - rvecrep(cent(s, :), n)).^2,2));
	end
	% select the smallest
	[nada, g] = min(d'); 
	g = g';
	for s = 1:nc
		if(numel(find(g==s)) > 0)
			cent(s, :) = mean(v(g==s, :));
		end
	end
end

real data from clementine:

{519}
hide / edit[33] / print
ref: notes-0 tags: NXT EMG design myopen date: 01-03-2012 02:49 gmt revision:33 [32] [31] [30] [29] [28] [27] [head]

devices:

devices that can be turned off & on to save power (e.g. actually disconnected from power through a P channel MOSFET. must be careful to tristate all outputs before disabling, otherwise we'll get current through the ESD protection diodes )

  1. ethernet
  2. usb reset
  3. usb host power
  4. RS 232
  5. LCD (or at least the 40ma, 6V LED -- the LCD can be disabled in software, and it only consumes 2-3 ma anyway.)
  6. core voltage boost 0.8v to 1.2V
  7. AFE

{246}
hide / edit[2] / print
ref: notes-0 tags: NRSA grants date: 01-03-2012 02:42 gmt revision:2 [1] [0] [head]

{719}
hide / edit[2] / print
ref: notes-0 tags: challenge grants NIH obama date: 12-28-2011 21:06 gmt revision:2 [1] [0] [head]

I was looking over the NIH's omnibus document (181 pages!) for the Challenge Grants due April 27, and happened upon a few interesting & relevant ones - and made some observations along the way.

  • The section on behavior modification is especially interesting -- the NIH wants to test techniques, biofeedback, treatments, cognitive therapy, behavioral therapy to, basically, improve the quality of life of the patients/citizens. Mainly this is targeted at illegal drugs. This is all very well so long as we are given a choice in the matter (it would seem so, of course -- drugs are a big problem in the US, and most of them are rightfully illegal). It is easy to change something designed to help into a tool that will help manipulate.
  • Example: 01-GM-101 Individual model of social behavior Development of a robust and well-characterized individual-based model of social behavior that includes the dynamics of social interactions that matches observed patterns of behavior. Contact: Dr. Irene Eckstrand
    • Sounds slightly big-brother like, no?
  • 01-OD(OBSSR)-101 Tools for studying cultural phenomena Development of new tools for: the measurement of culturally-shared mental phenomena (e.g. representations, scripts, prejudices); studying mechanisms by which these phenomena are transferred and adapted across individuals; and advancing research on the distribution and transmission of cultural phenomena within populations. (they list 5 scientists to contact).
    • Epidemiology meets sociology? The language they use suggests treating culture as a disease.
  • On the plus side, they also have sections for funding studies of informed consent, data access policies, responsible dissemination of research results, and the ethical considerations of all this (section 02-*)
  • A specific challenge topic states some of the guiding theory well: 04-DA-112 Enhancing the Impact of Behavioral Interventions using New and Innovative Technology. The ultimate goal of the NIH is to improve public health as measured in terms of biological well-being, which is multidimensional and strongly shaped by behavioral variables. Neuroscience on brain plasticity has demonstrated, unequivocally, that the brain changes as a result of behavior changes. Technological advances have made it possible to better measure the impact of behavioral interventions on specific biological targets and processes. [...] Dr. Lisa Onken
  • 06-OD-111 Mathematical and/or computational models of health-relevant behaviors. ...monitor social processes that occur over time. Dr. Lisa Onken. (eh, this document is not very well organized! why didn't they provide database access to it? They provide only 15 categories + two letter codes; I think that 'tagging' challenge tpoics with keywords would have been more effective, as the topics belong to overlapping fields. Of course, it is nice to see all of them; it forces you to get the big picture, something that would be missed with the focused results of a database search. )
  • 05-MD-101 Social Determinants of Health There is a growing research that reveals the important role of social determinants of health in addressing and understanding health disparities. Social determinants of health are the economic and social conditions under which people live which determine their health. We propose research that investigates interventions that address these social determinants (e.g. employment training, school readiness programs, food stamp programs, adequate and affordable housing programs). Contact Dr. Kyu Rhee
    • (next proposal): Approximately 70-80% of all current health care costs are connected with the treatment of chronic diseases.
  • 05-NS-102 Technologies to Enable Comparative Effectiveness Research in Clinical Neuroscience. Talks about looking for ways of decreasing the cost of randomized control trials.
  • 10-CA-101 Cyber-infrastructure for health: building technologies to support coordination and computational thinking The NSF as identified research based on 'cyberinfrastructure' as the single most important challenge confronting the nations science laboratories flash animation and article
  • 15-MH-110 Understanding the mechanism of action of deep brain stimulation. Conduct basic research on the mechanism of action of deep brain stimulation. Studies should be relevant to it's use in the treatment of mental disorders.
  • 06-CA-104 Quantum biology in cancer biology -- wow! I hadn't heard of the field of quantum biology.
  • 06-AG-101 Neuroscience blueprint: Development of non-invasive imaging approaches or technologies that directly assess neural activity (page 75) focus is on non-invasive methodologies, but it's possibly applicable specific challenge topic that I've seen so far.
  • 06-DA-102 Tool development for the Neurosciences (page 82) Tools that unambiguously identify, manipulate, and report from neurons in vivo and in vitro are needed to help us understand the interactions within neural circuits, to examine the functions of types of neurons that are derived from different brain regions, and to determine how selective and conditional silencing of activation of individual neurons or groups of similar neurons may alter functional outcomes, esp. behavior. (...) identification of real-time responses to drugs of abuse or therapeutic interventions ... understand endogenous neuroprotective mechanisms [and] neural dysfunction.
  • Neurolex -- mentioned. interesting.
  • 06-HD-101* Improved interfaces for prostheses to improve rehabilitation outcomes (page 91) Mechanical design and control algorithms for prosthetic limbs have seen remarkable advances recently. Still lacking, however, are robust interfaces for these limbs to both the brain and the skeleton. The foci of this challenge will be to improve functional rehabilitation outcomes by 1) developing or refining control interfaces that can utilize signals from [the] cerebral cortex to drive the latest generation of arm prostheses; 2] developing or refining methods for anchoring prosthetic arms directly to bone without risk of infection and 3) ... Contact: Dr. Michael Weinreich
  • 06-MH-102 Technologies to study neuronal signaling, plasticity, and neurodevelopment (page 96) molecular target.
  • 06-MH-103 New Technologies for neuroscience research (page 97) Develop technologies for neuroscience research that are software, hardware, or biology based. Dr. Huerta.
  • 06-NS-103 Breakthrough technologies for neuroscience (page 97) Advances in basic neuroscience are often catalyzed by the development of breakthrough technologies that allow interrogation of nervous system function (e.g. patch clamp recording from single cells, optical imaging, multi-channel recording arrays, fluorescent dyes to image cell types and intracellular processes etc) The challenge is to develop new technologies with the potential to enable basic neuroscientists to make quantum leaps in understanding nervous system development and function. Dr. Edmund Talley.
  • 06-NS-104 Developing and validating assistive neuro-technologies. mention neural control of prostheses.
  • 13-NS-101 Developing novel biomaterials to interfaces with neural activity (yes, the typo is from the original document; page 147). talk about neural-computer interfaces, repair of injured nerve or spinal cord, neurotransmission across a damage (another typo!) nerve or cord. Contact Dr. Joe Pancrazio.

{718}
hide / edit[5] / print
ref: notes-0 tags: thesis timetable contingency plan hahaha date: 12-06-2011 07:15 gmt revision:5 [4] [3] [2] [1] [0] [head]

Timetable / Plan:

  1. Get recording technology finished & assembled.
    1. Hardware
      1. Clean up prototype 2. Test in-chair with Clementine.
      2. Decide upon a good microelectrode-to-headstage connector with Gary.
      3. Fit headstage PCB into head-mounted chamber. Select battery and fit that too.
      4. Assemble one; contract Protronics to assemble 3 more.
      5. Contract Protronics to assemble 4 receiver boards.
    2. Software
      1. Headstage firmware basically complete; need to add in code for LFP measurement & transmission.
      2. Need some simple sort-client; use existing "Neurocaml" source as a basis. Alternately, use Rppl, inc's open-source "Trellis" electrophysiology suite.
      3. Integrate UDP reception into the BMI suite.
      4. Get an rugged all-in-one computer for display of BMI task - at tablet PC in a plexiglas box would be perfect.
    3. Due: June 30 2009
  2. Monkeys.
    1. Test in-cage recording with Clementine. He's a bit long in the tooth now, and does not have enough cells in M1/premotor cortices to do BMI control.
    2. Select two monkeys, train them on 2D target acquisition with a joystick using Joey's chair and setup. Make sure the monkeys can learn the 2D task in a reasonable amount of time; we don't want to waste time on dumb monkeys.
    3. Arrange for implantation surgeries this summer, depending on the availability of neurosurgeon.
    4. Work with Gary Lehew to assemble microelectrodes & head-mounted chamber.
    5. Get an ethernet drop in the vivarium for transmission of data.
    6. Due: August 30 2009
  3. Experiments
    1. Test & refine task 1 with both monkeys. Allow a maximum of 1 month to learn task 1. Neuron class (x/y/z) selected based on correlational structure (PCA of firing rate).
      1. Will have to get them to turn off Wifi (in same wireless band as the headstages) in the vivarium.
      2. Batteries will need to be replaced daily.
      3. Data will be inspected daily, to eliminate possible confounds / fix bugs / optimize the probability that the monkey learns.
      4. Expected data rate per headstage, given mean firing rate of 40Hz, full waveform storage, one LFP channel sampled at 1Khz = 3.5Gb / day. 1.5Tb drive, $120, will take 100 days to fill with data from 4 headstages.
      5. Very occasionally interleave 4-target test trials after the first week of learning, with both 'y' and 'z' neurons used to control the y-axis.
    2. Test & refine task 2 with both monkeys, in position control; here, record for a minimum of 1 month.
      1. Adjust cursor and target sizes to maintain task difficulty; measure asymptotic performance in bits/sec.
      2. Interleave randomly positioned target acquisition with stereotyped target sequences to measure neuronal tuning curves.
      3. Occasionally perturb cursor to see if there is an internal expectation of cursor motion.
    3. Switch task 2 to velocity control. Measure performance and learning effects of the switch. Train the monkey on this for at least 2 weeks, or until performance asymptotes.
    4. Shuffle the neuron class to make it non-topological, and re-train on position control in task 2 (this to test if topology matters). Train monkey for at least 3 weeks.
    5. Continue recording for as long as it seems worthwhile to do so.
    6. Due: February 1 2010
  4. Writing
    1. Write the DBS paper. This can be done in parallel with many other things, and should take about a month off and on.
    2. Keep good notes during experiments, write everything up within 1-2 months of finishing the proposed experiments.
    3. Write thesis.
    4. Due : June 2010

Contingency Plan:

  1. Recording technology does not work / cannot be made workable in a reasonable amount of time (Reasonable = 4 months.)
    1. Use Plexon, record for as long as possible (or permissible given our protocol - 4 hours) while monkey is in chair. If monkeys will not go into REM/SWS in a chair, as seems likely given what I've tried, scratch the sleep specific aim.
    2. Focus instead on making the simplified BMI work. Will have to assume that neuron identity does not change between sessions.
  2. Monkey surgery fails.
    1. Unlikely. If it does happen, we should just get another monkey. As Joey's travails in publishing his paper show, it is best to have two monkeys that learn and perform the same task.
    2. Even if the implants don't last as long as all the others, the core experiments can be completed within 2 months. Recording quality from even our worst monkey has lasted much longer than this.
  3. Monkey does not learn the BMI
    1. Focus on figuring out why the monkeys cannot learn it - start by re-implementing Dawn Taylor's kludgy autoadaptive algorithm, and go from there.
    2. Focus on sleep. Put a joystick into the cage, and train the monkey on relatively complex sequences of movement to see if there is replay.
    3. Use the experiment as a springboard to test more complicated decoding algorithms with the help of Zheng.
  4. There are no signs of replay.
    1. Try different mathematical methods of looking for replay.
    2. If still nothing, report that.

{723}
hide / edit[1] / print
ref: notes-0 tags: data effectiveness Norvig google statistics machine learning date: 12-06-2011 07:15 gmt revision:1 [0] [head]

The unreasonable effectiveness of data.

  • counterpoint to Eugene Wigner's "The Unreasonable effectiveness of mathematics in the natural sciences"
    • that is, math is not effective with people.
    • we should not look for elegant theories, rather embrace complexity and make use of extensive data. (google's mantra!!)
  • in 2006 google released a trillion-word corpus with all words up to 5 words long.
  • document translation and voice transcription are successful mostly because people need the services - there is demand.
    • Traditional natural language processing does not have such demand as of yet. Furthermore, it has required human-annotated data, which is expensive to produce.
  • simple models and a lot of data triumph more elaborate models based on less data.
    • for translation and any other application of ML to web data, n-gram models or linear classifiers work better than elaborate models that try to discover general rules.
  • much web data consists of individually rare but collectively frequent events.
  • because of a huge shared cognitive and cultural context, linguistic expression can be highly ambiguous and still often be understood correctly.
  • mention project halo - $10,000 per page of a chemistry textbook. (funded by DARPA)
  • ultimately suggest that there is so so much to explore now - just use unlabeled data with an unsupervised learning algorithm.

{91}
hide / edit[13] / print
ref: notes-0 tags: perl one-liner svn strip lines count resize date: 03-22-2011 16:37 gmt revision:13 [12] [11] [10] [9] [8] [7] [head]

to remove lines beginning with a question mark (e.g. from subversion)

svn status | perl -nle 'print if !/^?/' 

here's another example, for cleaning up the output of ldd:

ldd kicadocaml.opt | perl -nle '$_ =~ /^(.*?)=>/; print $1 ;' 

and one for counting the lines of non-blank source code:

cat *.ml | perl -e '$n = 0; while ($k = <STDIN>) {if($k =~ /\w+/){$n++;}} print $n . "\n";'

By that metric, kicadocaml (check it out!), which I wrote in the course of learning Ocaml, has about 7500 lines of code.

Here is one for resizing a number of .jpg files in a directory into a thumb/ subdirectory:

ls -lah | perl -nle 'if( $_ =~ /(\w+)\.jpg/){ `convert $1.jpg -resize 25% thumb/$1.jpg`;}'
or, even simpler:
ls *.JPG | perl -nle '`convert $_ -resize 25% thumb/$_`;'

Note that -e command line flag tells perl to evaluate the expression, -n causes the expression to be evaluated once per input line from standard input, and -l puts a line break after every print statement. reference

For replacing charaters in a file, do something like:

cat something |  perl -nle '$_ =~ s/,/\t/g; print $_'

{583}
hide / edit[3] / print
ref: notes-0 tags: usbmon decode chart linux debug date: 07-12-2010 03:29 gmt revision:3 [2] [1] [0] [head]

From this and the USB 2.0 spec, I made this quick (totally incomprehensible?) key for understanding the output of commands like

# mount -t debugfs none_debugs /sys/kernel/debug
# modprobe usbmon
# cat /sys/kernel/debug/usbmon/2u

To be used with the tables from the (free) USB 2.0 spec:

{820}
hide / edit[1] / print
ref: notes-0 tags: CSV blog article group dynamics steinberg date: 07-05-2010 15:30 gmt revision:1 [0] [head]

Another excellent post from Steinberg regarding treating people as predictable nonlinear fluids. "The system works far better when a column is introduced off-center in front of the door,as demonstrated Mr. Torrens. "It's counterintuitive, but the column sends shock waves through the crowds to break up the congestion patterns." (...) Most traffic jams are emergent phenomena that begin with mistakes from just one or two drivers. According to Horvitz's models, they can actually "un-jam" traffic by calling drivers at a particular location, and giving them very specific instructions: "Move to the left-most lane, and then speed-up to 65."

{805}
hide / edit[0] / print
ref: notes-0 tags: ice hydrophones glissando recording sound date: 01-19-2010 16:41 gmt revision:0 [head]

http://silentlistening.wordpress.com/2008/05/09/dispersion-of-sound-waves-in-ice-sheets/ -- amazing!

{798}
hide / edit[1] / print
ref: notes-0 tags: Gladwell talent narcissism management structure business date: 11-19-2009 06:02 gmt revision:1 [0] [head]

http://www.gladwell.com/pdf/talent.pdf -- From 2002. Old but excellent. Structure is required to achieve broad, slow to ROI projects. (It's almost common sense when expressed this way!)

{722}
hide / edit[0] / print
ref: notes-0 tags: programming excellence norvig 10 years date: 04-07-2009 20:26 gmt revision:0 [head]

Teach yourself programming in 10 years

  • points out that, in order to be excellent at any difficult skill/art, you must practice 10 years or 10,000 hours, and this practice must be focused and deliberate.
    • quote: "have shown it takes about ten years to develop expertise in any of a wide variety of areas, including chess playing, music composition, telegraph operation, painting, piano playing, swimming, tennis, and research in neuropsychology and topology"
    • possibly this is partially due to competition - most other people drop out after 10 years!
    • Or this is due to the fact that, for general purpose behaviors, we are really no better than the present gradient descent & reinforcement learning algorithms which require repeated presentation of patterns and behaviors. Where humans achieve sub-gradient/RL performance is where evolution has supplied us with hardware or 'prior assumptions' to bias for a correct solution / correct solution space. These prior assumptions are (part of) that which the make study brain interesting!
  • "Life is short, [the] craft long, opportunity fleeting, experiment treacherous, judgment difficult." -- Hippocrates.

{717}
hide / edit[2] / print
ref: notes-0 tags: EWH electrosurgery comments date: 03-26-2009 17:18 gmt revision:2 [1] [0] [head]

For the Instructions for use:

  • Section 1.0 -- "... instructions for use of the Electro Surgery ..."
    • Why do we need the decimal point? "Section 1"
  • Section 2.0 -- the figures are labeled 1.1, 1.2, 1.3. Should be 2.1, 2.2, 2.3? Good figures though.
    • Is there some way of cleaning up the figure labeling & numbering in section 5 (and indeed the assembly instructions). It's not bad, but...
  • Section 3.0 -- Maybe make "3.x.x" into bullet points. Numbers are a bit much.
  • Section 4.0 -- The 4.1 is extraneous...
  • Section 5.4 -- Why is the second paragraph text gray?
  • Section 5.5 -- "Wait two minutes for the power resistor to cool before repeating step 5.4". (Might as well tell them why they are waiting, gives them more reason to do so).
  • Section 5.7 -- Remind the user to wait some time for the power resistors to cool before trying different power settings. At lower powers, they will not have to wait too long; higher power will require longer wait time. In the future might want to put a thermsistor/resettable poly fuse or the like in there to thermally protect the device. Or one of the bimetal heat switches that they use in hair dryers; I'd imagine that they are cheap.
  • I'm not very familiar with ESU devices, but is there a possibility to see varying power levels within the 4-second evaluation period? Would this be important to note?

For the assembly instructions:

  • Section 2.0 -- You can probably get some images of the resistors off digikey :-)
    • Also, don't need to number "2.x" all of the components. One number in that table should be enough.
    • Separate column for device quantity would aid clarity.
  • Section 3.0 -- Are numbers needed for this short list?
  • Section 4.0 -- Ditto. Maybe bullets would be clearer. As for the grounded bench, perhaps should explain that static electricity can damage the diodes.
  • Section 5.0 --
    • Why make the user refer to the appendix for the resistor color codes? Just take a picture of the finished board, with all but the resistors masked out or lightened in photoshop, so the assembler can see what goes where. Or some other clear figure.
    • Tools and materials should not get its own column; put that in a row or bullet before the table. Maybe have a bullet point: "Components needed: R8, R7, R6..." This lets you make the pictures larger.
  • Section 5.2 -- Figure 3 - exactly! good figure.
    • Might as well put the diode numbers and values in the table. There is enough space below the first instruction bullet point.
  • Section 5.3 - 5.6 -- looks good.
  • Section 5.7 -- I would have to try this; it seems that most of the creases are intuitively obvious. Again, don't see the need for the gray text, though. The figures are good & illustrative.
  • Section 5.9 -- Would it be easier to apply the labels before folding, that way it is easy to apply even and firm pressure? I'm extrapolating here, don't know.
  • Appendix A -- You can hold LEDs or other components flush by bending the leads out after insertion. Re-melting & pushing the leads in sometimes results in bad solder joints. Otherwise good.

{594}
hide / edit[4] / print
ref: notes-0 tags: wireless nordic headstage bridge neurorecord pictures photo EMG myopen date: 03-12-2009 02:33 gmt revision:4 [3] [2] [1] [0] [head]

{674}
hide / edit[1] / print
ref: notes-0 tags: Barto Hierarchal Reinforcement Learning date: 02-17-2009 05:38 gmt revision:1 [0] [head]

Recent Advancements in Hierarchal Reinforcement Learning

  • RL with good function-approximation methods for evaluating the value function or policy function solve many problems yet...
  • RL is bedeviled by the curse of dimensionality: the number of parameters grows exponentially with the size of a compact encoding of state.
  • Recent research has tackled the problem by exploiting temporal abstraction - decisions are not required at each step, but rather invoke the activity of temporally extended sub-policies. This is somewhat similar to a macro or subroutine in programming.
  • This is fundamentally similar to adding detailed domain-specific knowledge to the controller / policy.
  • Ron Parr seems to have made significant advances in this field with 'hierarchies of abstract machines'.
    • I'm still looking for a cognitive (predictive) extension to these RL methods ... these all are about extension through programmer knowledge.
  • They also talk about concurrent RL, where agents can pursue multiple actions (or options) at the same time, and assess value of each upon completion.
  • Next are partially observable markov decision processes, where you have to estimate the present state (belief state), as well as a policy. It is known that and optimal solution to this task is intractable. They propose using Hierarchal suffix memory as a solution ; I can't really see what these are about.
    • It is also possible to attack the problem using hierarchal POMDPs, which break the task into higher and lower level 'tasks'. Little mention is given to the even harder problem of breaking sequences up into tasks.
  • Good review altogether, reasonable balance between depth and length.

{668}
hide / edit[7] / print
ref: notes-0 tags: triangulation kicadocaml date: 02-04-2009 21:40 gmt revision:7 [6] [5] [4] [3] [2] [1] [head]

PCB copper zones using triangle meshes

Abstract:

Many tasks in computer-assisted design involve the removal of polygons from other polygons. Particularly, this problem is found when filling a region of a printed circuit board (PCB) with a polygonal zone or 'pour' of copper. This zone is attached to a net, perhaps ground, and hence other tracks, vias, and segments of copper not on the same net but within its region must be avoided by a clearance distance. This clearance can be observed by subtraction of expanded polygons from the original zone's outline polygon, as is done in two open-source PCB design softwares, Kicad and gEDA. Here we present a fast and scalable algorithm that works with triangles instead of polygons. The algorithm is able to mesh, add edges, and remove conflicting triangles within a few seconds for problems involving 10,000 points.

Introduction:

I have contributed, infrequently, to the open-source electronic design automation (EDA) suite Kicad for the past year or so. November/December of 2007 I added duplicated hierarchal support to Kicad's schematic editor, eeschema, which allows, like many commercial packages, duplicate instances of sub-schematics. This feature is used when a segment of circuitry is duplicated multiple times in a design, perhaps when there are multiple identical channels, e.g. in an audio mixer.

However pcbnew (the layout editor in Kicad) is unaware of the duplication, hence for each sub-schematic the layout had to be duplicated. This involved a lot of work for the 8-channel microstimulator board that I was working on at the time, so I decided to implement a small application to help layout an array of duplicated circuitry. Ocaml was chosen to implement the software, as I wanted to learn the language. In the course of working on PCBs, learning Ocaml, and basically scratching a series of itches, the software, tentatively named "Kicadocaml", has become progressively more feature-rich, useful, and tested. It has ratsnest, DRC online and offline checking, push routing, schematic hierarchy comprehension (of course), connectivity testing, bill-of-materials generation, and a responsive OpenGL-based GUI.

In my last board, pcbnew failed to fill all the zones; I'm not sure why. I tried to fix the bug, but got lazy/overwhelmed after a while, and decided to just write a zone-filling algorithm from scratch myself (to scratch the itch, so to speak). Sure it's reinventing the wheel, but reinventing is fun. In the interest of documenting the algorithm a bit for posterity, the algorithm is described below.

Algorithm:

A list is made of all points and segments that may be involved in the zone-fill. This includes, of course, the edges of the zone, as well as the outline of any track/via/pad cutout within the zone (and not of the same net number), expanded to allow for zone clearance and zone-edge stroking. The list of points also must include any intersections between segments. For efficiency, the lists of points and segments are culled by checking each polygon to be subtracted to make sure that at least one of it's points is within the zone polygon; this is done via the standard inside/outside polygon test.

The list of points is then incrementally inserted into a linked triangle mesh via a very simple, very effective method of triangle splitting and edge-flipping. Linked triangle mesh means that each triangle stores a index (or pointer) to the triangle off each of its three edges. This is to facilitate the insertion of points: to find the triangle that a point is in, you walk over the linked mesh, crossing the edge between triangles that intersects a ray from the center of the present triangle to the target point. (Given the ordering of points within the list, this can be nearly a constant-time operation). See below.

  • Figure 1: Method of finding the triangle which contains a point. The highlighted triangle indicates the working triangle (in practice, this is an index to an array), and n is a point within that triangle (in my implementation, I chose to simply average the 3 corners of the triangle to get an interior point). p is the target point. In each iteration, each segment of the working triangle is checked to see if it intersects with the line np ; if it does, then the working triangle index is updated with the index of the triangle off the intersected edge. This continues until p is within the working triangle. The working triangle index is cached between calls of this iterative algorithm, as usually sequential calls involve points that are close.

Once a triangle is found, it is split into three triangles by the addition of the point. Then, each pair of triangles, one new and one old (bordering the triangle that was split) is checked to see if flipping the interior segment would increase the smallest angle. Remarkably, this reliably takes care of edge insertion - no specialized edge insertion routine was required (however, loops in the find triangle algorithm (figure 1) must be eliminated for a triangle to be found when a point is on an edge). I decided to simply maximize the minimum angle in each triangle, rather than observe the Delaunay criteria which doesn't matter for this application.

  • Figure 2: Point insertion method. After triangle ABC is split into ABP, BCP, and CAP, each pair (BFC & BCP ; CDA & CAP ; AEB & ABP) is check to see if flipping the internal segment would make the minimum internal angle between the two larger. For example, here the minimum internal angle of triangles BFP & FCP was found to be less than BFC & BCP. Indeed, all new triangles were 'flipped' in this example. Care must be taken to maintain the integrity of the linked mesh when inserting and flipping triangles - with extra caution to the fact that it is dual-linked (to and from a given triangle).

This algorithm only deals with finding containing triangles and inserting points; hence, it must be seeded with at least one triangle which will contain all others. I chose to use two triangles defined by a slightly-enlarged bounding box of all points to be inserted.

The algorithm does not insure that all polygon segments are in the list of edges of a mesh; hence, after all points are inserted, every edge is checked to make sure if it is in the mesh -- see figure 3.

  • Figure 3: Adding segment AB to the mesh. First, the segment is checked to see if it - or a sub-segment (via a parallel test), is already in the mesh. If not, a working triangle index is found that has endpoint B as a vertex. The angle between the associated edges and AB are measured; if the angle is greater, the triangle off the CCW edge becomes the working triangle (e.g. 1); if less, the triangle off the CW edge becomes the working triangle; if AB is between the two associated triangle edges, then the intersection point with the far edge is found (2). These calculations are simplified by the fact that all triangles are CCW. The intersection point is inserted into the mesh, and the segment is made shorter - the newly inserted point becomes end B of the segment, and the algorithm recurses. Note, as in 5, when inserting points the flipping rule still holds; as a result of this, all edges must be checked twice, the second time without flipping, to be certain that all edges are in the mesh. As with the triangle finding algorithm, segment checking/adding is relatively efficient with the linked-mesh data structure.

Once all points and all edges from the original list are in the mesh, then each triangle may be tested to see if it should be kept or removed. In kicadocaml this is done with DRC (design rule check) testing.

  • Figure 4: Final result, after conflicting triangles are removed. Original polygon edges are shown in light gray.

Afterword:

The algorithm runs well; it takes ~ 2 seconds to mesh, edge check, and filter 10,000 points on my Core2 2.4Ghz desktop computer. Though it was written in a higher-level language (about 600 lines of Ocaml), I do not think that it would be hard to port to C++ for inclusion in other PCB layout packages. Great effort was not necessarily put into the design of the algorithm, but rather the numerical stability of it's sub-components, such as the triangle inside-outside check (computed with the cross product), and the segment intersection test. For these, please see the source, or {661}.

{652}
hide / edit[0] / print
ref: notes-0 tags: policy gradient reinforcement learning aibo walk optimization date: 12-09-2008 17:46 gmt revision:0 [head]

Policy Gradient Reinforcement Learning for Fast Quadrupedal Locomotion

  • simple, easy to understand policy gradient method! many papers cite this on google scholar.
  • compare to {651}

{649}
hide / edit[2] / print
ref: notes-0 tags: ME270 project light power date: 12-08-2008 19:42 gmt revision:2 [1] [0] [head]

ME 270 Final Project - Optical Power Transfer

The purpose of this project was to develop a means for delivering optical power to the top of monkey unconstrained within his cage. This power will ultimately be used to recharge the batteries on a small neural telemetry device that we are developing. To deliver the power, we decided to use a moving-mirror DJ light controlled through a microcontroller in turn controlled via a video tracking computer. Hence, out report will be broken into three sections: the light, microcontroller, and video tracking.

Section 1 : Reverse-engineering the light, part selection

Rather than engineering our own articulated spotlight, we elected to buy a moving-mirror DJ light; creating our own light source would simply have taken too much time, and demanded optical experience that we lack. After a brief survey, we bought an Elekralite mm150 (moving mirror, 150W bulb) DJ light, one of the cheapest on the market ($650); despite this, it is very well constructed, as you will see below. The light was originally controlled through the stage-specific DMX bus, but the possibility of directly controlling the light through this was discarded after we learned that the resolution on each axis is only 8 bits (+- 127); given the large range of the pan mirror, this is insufficient for tracking. Hence we decided to reverse engineer the light to determine the best way to directly control the mirror and shutter.
  • Overview, with dichroic color filter wheel and globos removed. We ended up putting these back in, as without them the unit does not initialize properly.
  • Another view with the shell taken off. The white ballast on the bottom powers the 150W HMI metal-halide bulb, along with a stabilization capacitor (to the left of the ballast) and starter (below the capacitor). The starter produces 2kV to initially ionize the gas in the bulb; there is no third starter electrode as in mercury vapor bulbs, as this would be a point of stress in the high-pressure (90atm) fused quartz arc tube. The bulb is on whenever the unit is plugged in, and the light output is controlled via the shutter. The top large transformer (+20V, +12V) is used to drive the display/control unit (left center) and the 6 stepper motors in the lamp, which are:
    • mirror tilt
    • mirror pan
    • shutter
    • globo selection
    • globo rotate
    • colorwheel
    • Detail of the breakout board for the 6 stepper motors, with the colorwheel stepper above it. The stepper motors are two-phase, permanent-magnet rotor types; we're not sure of the steps/revolution yet, though they all seem different. The breakout board also has attachments for the hall-effect sensors to detect orientation of the globo and color wheels.
    • The dichroic mirror color wheel. Regular filters would undoubtedly melt here - a pencil put into the beam of the HMI lamp will light on fire!
    • The globo wheel. Each globo is mounted to a gear which engages a center gear on the same axis as this plate. This center gear is driven by the globo rotate stepper motor.
    • Dichroic IR filter. Note that since it is viewed at an angle, the reflective wavelength goes up, and so you can see a slight red tint in the reflections off this. Removed this, since silicon photovoltaic cells respond to near IR energy.
    • Stepper motor controller. The three chips at the bottom are NXP 87LPC768 OTP microcontroller. Each can control two stepper motors, and each has an internal program for self-calibration using either the hall-effect sensors or hard mechanical limits on motor range. Upper chip is for the mirror (U3). These chips are controlled via one high-speed serial bus from the upper control board (the one with the LED display). The six upper chips, with heat-sinks on them, contain dual H-bridges, probably similar to the Allegro A3955 PWM microstepping motor driver. Between them are two standard 74HC04 hex inverters to drive the opposite leg of the h-bridges (each 87LPC768 has four outputs, two per motor, whereas each motor requires four inputs, two per phase. In this way, you can switch the direction of current flow through each motor phase with a single +20v supply rail.)
    • The Elekralite mm150 without the two control boards, globo wheel, or filter wheel. You can see the lamp, focus adjustment screws and reflector. Below the lamp is a 24V radial fan.
    • The Elektralite powered on, with globo and filter wheel back in place. The lamp is very, very bright!
    • Close-up of filter and globo wheels. The shutter has been removed; it fits on the shaft just above the long hex spacer. Just above that is the mechanical hard stop for the shutter.
    • The pin on the main controller that is used to control the 6 stepper axes. We tried probing it for some time, but could not directly figure out the serial protocol without a good logic analyzer (which is at home), so decided to implement our own microstepping PWM controller, and drive the inverters / H-bridges driectly.
    • The shutter, after being used for a good bit. The UV and IR from the lamp (mostly the IR, I think - the shutter gets really hot!) bleaches the black anodization on this bit of aluminum. We've drilled a 1/4" hole in one side to try to get a more tightly-collated beam.
    • The PWM waveform at the motor for the two phases (the glare at the left is from the light, which was of course on!). The other leads in the motor are simply the inverse of these via the 74HC04. For vector control like this, a 50% on/50% off PWM effectively sets the phase current to zero (the motor has sufficient leakage inductance at the 16kHz PWM frequency to keep di/dt low over multiple PWM periods). Hence, to control the motors we need something like:
      phase1 = 0.5*sin(theta) + 0.5 ; phase2 = 0.5*cos(theta) + 0.5
      , where theta is changed based on the control algorithm, and phase is scaled and used to set the PWM counter compare register. See below.
    • Microstepping control scheme based on vector control of current in the two phases of these stepper motors. As before, current will be regulated via PWM @ 16kHz, as the Elektralite engineers do, as opposed to linear current control. To generate the appropriate 6 PWM signals (mirror pan, mirror tilt, and shutter), we used a MSP430 microcontroller with 3 16-bit counters and 5+ capture-compare registers.
    • We used a MSP430F5xxx development board from TI -- see the next section. The device features sufficient timers and PWM outputs to control the stepper motors in the Elekralite. We will control motion of each using a simple up-down toggling via the parallel port to increment/decrement the motor theta variable. The microcontroller will need a look-up table or algorithm for calculating the sines and cosines of rotor angles.
    • small solar cell from Spark Fun Electronics. When placed in the beam of the light, it is possible to generate 500ma short-circuit current and 5V open-circuit voltage, but not at the same time. In a solar cell composed of a series of junctions, such as this, the total current at full voltage is limited by the minimum current from each of the junctions (they are in series!). Therefore to get maximum current you need very uniform illumination, something that is normally not difficult with the sun, but which will be difficult in this application. To avoid this problem we will try to procure higher efficiency single-junction GaAs concentrator cells, which can be up to ~40% efficient (as compared to this one, which is ~15% efficient).

Section 2: Microcontroller & microstepping

As mentioned before, we chose MSP430F5438 100-pin 16 bit microcontroller because it offers sufficient timers and speed for our problem and because we were both familiar with the architecture. Four 16-bit timers are used to control microstepping mirror tilt and pan, since the stepper motors have two phases. The microcontroller only needs to provide digital signals; current is provided through H-bridge drivers in the control board of the mm-150 - the DIPs with heat sinks below.

Opposite sides of the H-bridge are driven via hex inverters; hence, we only have to supply two PWM signals per motor, one per phase. Setting the PWM duty cycle to 50% will set the motor phase current to zero; by vectoring the duty cycle proportional to the sine and cosine of theta, where theta is the orientation of the motor * number of poles of the stepper, you can control microstepping. That, of course, is simplified; in practice, there are many details to contend with, namely:

  • The MSP430 is a 16 bit integer processor; hence, fractional values must be represented as fixed-point numbers. We chose 11-bit fixed point to optimize resolution and prevent overflow.
  • There is no divide. Division can be accomblished via bit-shifts (which is equivalent to dividing by 2), and addition.
  • There is one 16*16 -> 32 bit multiplier used as a peripheral in the MSP430 architecture, but the standard C library does not access it properly for our fixed-point math.
  • We have to approximate sine and cosine using fixed-point math, since the standard C library Sin and cos each take more than 2500 cycles -- too long when the microcontroller is only running at 12Mhz, and we want to update 4 microstepping phases at ~ 40Khz.

We approximated sine and cosine, needed to vector the stepper motor phase currents, in fixed-point arithmetic first in C on linux - where the results could be plotted in matlab - before converting to MSP430 code. Since the trigonometric functions are repeating, we only need a polynomial approximation of sine from 0 to pi/2. The taylor series for sine is

 sin(x) = x - x^3/3! + x^5/5! - x^7/7! ...
; a quick check in matlab showed that the first three terms are enough to get an accurate approximation in the domain of interest. The MSP430 does not have division, however, so we approximated 1/3! = 1/6 as (1/8 + 1/32 + 1/128) and 1/5! = 1/120 as 1/128; division by powers of two is possible with right bit-shift operations. We chose base 11 (5 bits whole, 11 bits fractional) representation to avoid overflow: if 2^11 -> 1, we need to represent (pi/2)^5 -> 9.5 ; ceil(log_2(9.5)) = 4 (plus one bit for safety). The C program below shows this test.

#include <stdio.h>

char qsin(short i){
       //i goes from  0 pi/2 base 11 or...
       // 0 to 3217
       unsigned int cube, fifth, result;
       cube = (i*i) >> 11;
       cube = (cube*i) >> 11; //max = 7937
       fifth = (cube*i) >> 11;
       fifth = (fifth*i) >> 11; // max = 19585
       //our approximation to sine based on taylor series:
       //original: sin(x) = x - x^3/3! + x^5/5!
       //sin(x) = x - x^3*(1/8+1/32+1/128) + x^5*(1/128)
       result = (unsigned int)i -
               ((cube >> 3) + (cube >> 5) + (cube >> 7)) + (fifth >> 7);
       //result is base 11.  need it to be base 7.
       result = result >> 4;
       if(result > 127) result = 127;
       return (char)result;
}
//this is tricky, as it involves shifts, x-inversions, and y-inversions. 
//but it all makes sense if you plot out the respective functions. 
char isin(short i){
       // i is base 2^11
       //but we accept 0 to 2*pi or 12867
       if(i >= 0 && i < 3217) return qsin(i);
       else if(i >= 3217 && i < 6434) return qsin(6434 - i);
       else if(i >= 6434 && i < 9651) return -1*qsin(i - 6434);
       else if(i >= 9651 && i < 12867) return -1*qsin(12867 - i);
       else return 0;
}
char icos(short i){
       // i is base 2^11
       //but we accept 0 to 2*pi or 12867
       if(i >= 0 && i < 3217) return qsin(3217 - i);
       else if(i >= 3217 && i < 6434) return -1*qsin(i - 3217);
       else if(i >= 6434 && i < 9651) return -1*qsin(9651 - i);
       else if(i >= 9651 && i < 12867) return qsin(i - 9651);
       else return 0;
}

int main(void){
	short i; 
	for(i=0; i<12867; i++){
		printf("%d\t%f\t%d\t%d\n", i, ((float)i)/2048.0, (int)(isin(i)), (int)(icos(i))); 
	}
	return 0; 
}

We compiled and ran this program on the command line:

 gcc integer_trig.c 
 ./a.out > test.txt

Then we imported the data into matlab and plotted (Actual double floating-point sine and cosine are plotted on the same axis as thin black and magenta lines, respectively)

Later, we had to change the naive standard implementation of multiply to assembly to properly implement the fixed-point arithmetic - the MSP430's standard library did not implement the 16x16 multiply followed by shift correctly (it only keeps the bottom 16 bits). Note: this assembly function is for use with Code-Composer Studio, available from the Texas Instruments website. It seems that the IAR compiler uses different assembly syntax.

;*******************************************************************************
            .cdecls C,LIST,"msp430x54x.h"  ; Include device header file

;-------------------------------------------------------------------------------
            .text                           ; Progam Start
;-------------------------------------------------------------------------------
                       
          ;;.sect "mply_11"
          ;;.asmfunc "mply_11"
                        .global mply_11 ;; this MUST BE PRECEDED BY TABS !!!!!

mply_11: 
        PUSH	SR	; 
         DINT		; turn off interrupts here. 
         NOP			; required after DINT
         MOV.W	R12, &MPY ; load the first operand. 
         MOV.W	R13, &OP2 ; load the second operand & start multiplication. 
         MOV.W	&RESLO, R12 ; low to R12 (this is the return value)
         MOV.W	&RESHI, R13 ; high to R13
         RRA.W R12 ; 1
         RRA.W R12 ; 2
         RRA.W R12 ; 3
         RRA.W R12 ; 4 
         RRA.W R12 ; 5
         RRA.W R12 ; 6
         RRA.W R12 ; 7
         RRA.W R12 ; 8
         RRA.W R12 ; 9
         RRA.W R12 ; 10
         RRA.W R12 ; 11
         
         RLA.W R13 ; 1
         RLA.W R13 ; 2
         RLA.W R13 ; 3
         RLA.W R13 ; 4
         RLA.W R13 ; 5
         
        ;; r14 can be clobbered across a function call, according to the msp430 ABI
        MOV.W	#0x001f, R14
        AND.W	R14, R12 ; mask off all but the bottom 5 bits from RESLO
         ADD.W	R13, R12 ; add (logical OR) the results. R12 is the 11-bit fixed point result.
         POP.W 	SR	;
         RETA		; return from subroutine.

            .end

Note the MSP430 does not have an opcode for multiple arithmetic shifts, nor does it have code for logical shifts - hence the need for repeated shifts and bitmasks!

Section 3 - Video tracking and host computer control

With the microcontroller done, we then moved to controlling it via a video-tracking computer. At this point, we had created a simple program for testing out parallel port control of the light's three axes using the keyboard (tilt, pan, and shutter). This program was split into two files, a main, and a set of subroutines that could then be called and compiled into the full video tracking program. It uses libparapin to abstract interaction with the parallel port in userspace.

First, the main loop, which is very simple:

#include "parallelout.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

char g_main_loop ; 

int main(int argc, char *argv[])
{
	g_main_loop = 1; 
	char c;
	parallel_setup(); 
 
	while(1){
		c = fgetc(stdin);
		interpret_cmd(c); 
	}
}

Second, the parallel port controller. This uses a thread and circular queue to provide asynchronous, non-blocking control of the communications channel. Non-blocking is critical, as the program waits a small period between low-high transition of the interrupt pin (pin 4) for the MSP430 to read the status of the three lines.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <parapin.h>
#include <pthread.h>

#include "parallelout.h"

char g_q[1024]; //queue for the commands. 

int g_q_rptr; //where to read the next command from. 
int g_q_wptr; //where to put the next command

double g_velPan; 
double g_velTilt; 

void stepstep(void){
       int i = 0;
       for(i=0; i<20000; i++){
               set_pin(LP_PIN[4]);
               clear_pin(LP_PIN[4]);
	       set_pin(LP_PIN[5]);
               clear_pin(LP_PIN[5]);
	       set_pin(LP_PIN[5]);
               clear_pin(LP_PIN[5]);
       }
}

void velstep(int n){
	//printf("velstep %d\n", n); 
	clear_pin(LP_PIN[4]);
	if(n&0x1) set_pin(LP_PIN[2]) ; 
	else clear_pin(LP_PIN[2]); 
		
	if(n&0x2) set_pin(LP_PIN[3]) ; 
	else clear_pin(LP_PIN[3]); 
	set_pin(LP_PIN[4]); 
	//leave it up, so the msp430 knows it is a velocity command. 
}
void openShutter(){
	printf("opening shutter\n"); 
	clear_pin(LP_PIN[4]);
	set_pin(LP_PIN[2]); 
	set_pin(LP_PIN[3]); 
	set_pin(LP_PIN[4]); 
	clear_pin(LP_PIN[4]); //clear the trigger to indicate a shutter command. 
}
void closeShutter(){
	printf("closing shutter\n"); 
	clear_pin(LP_PIN[4]);
	clear_pin(LP_PIN[2]); 
	clear_pin(LP_PIN[3]); 
	set_pin(LP_PIN[4]); 
	clear_pin(LP_PIN[4]); //clear the trigger to indicate a shutter command. 
}
void smallShutter(){
	printf("small shutter\n"); 
	clear_pin(LP_PIN[4]);
	clear_pin(LP_PIN[2]); 
	set_pin(LP_PIN[3]); 
	set_pin(LP_PIN[4]); 
	clear_pin(LP_PIN[4]); //clear the trigger to indicate a shutter command. 
}
void stopMirror(){
	printf("stop mirror\n"); 
	clear_pin(LP_PIN[4]);
	set_pin(LP_PIN[2]); 
	clear_pin(LP_PIN[3]); 
	set_pin(LP_PIN[4]); 
	clear_pin(LP_PIN[4]); //clear the trigger to indicate a shutter command. 
}

void parallel_setup(){
	if (pin_init_user(LPT1) < 0)
		exit(0);

	pin_output_mode(LP_DATA_PINS | LP_SWITCHABLE_PINS);
	clear_pin(LP_PIN[2]);
	clear_pin(LP_PIN[3]); 
	clear_pin(LP_PIN[4]); 
	pthread_t thread1;
	//start the queue-servicing thread. 
	pthread_create ( &thread1, NULL, pq_thread, NULL ); 
}

void interpret_cmd(char cmd){
	//these codes don't make much sense unless you are 
	//controlling from a keyboard.
	switch(cmd){
		case 'w': velstep(0); g_velPan-=1.0; break; //pan to right (looking at but of light)
		case 'a': velstep(1); g_velTilt+=1.0; break; //tilt toward.
		case 's': velstep(2); g_velPan+=1.0; break; //pan to left
		case 'd': velstep(3); g_velTilt-=1.0; break; //tilt away
		case 'o': openShutter(); break; 
		case 'c': closeShutter(); break; 
		case 'x': smallShutter(); break;
		case ' ': stopMirror(); g_velPan=0; g_velTilt=0; break; 
	}
}

void usleep(int us){
	timespec ts; 
	ts.tv_sec = 0; 
	ts.tv_nsec = us * 1000; 
	nanosleep(&ts, NULL);
}

extern int g_main_loop ; 

void* pq_thread(void* a){
	while(g_main_loop){
		if(g_q_wptr > g_q_rptr){
			char cmd = g_q[g_q_rptr % sizeof(g_q)]; 
			g_q_rptr++; 
			interpret_cmd(cmd); 
		}
		usleep( 200 ); // run at max 500hz update.
		// the msp430 takes about 125us to service the parallel port irq.
	}
	return (void*)0;
}

void enqueue(char cmd){
	//this should be sufficiently atomic so there is no thread contention.
	g_q[g_q_wptr % sizeof(g_q)] = cmd; 
	g_q_wptr++; 
}

Then, we worked on the video tracking program. I will omit the some of the noncritical sections involving the firewire (ieee1394), Xv (video display) and X11 (window manager) calls, as the whole program is long, ~1000 lines. Below is 'main' -- see the comments for a detailed description.

int main(int arc, char *argv[]){
	int i; 
	double t1, t2, t3, t4; 
	t1 = t2 = t3 = t4 = 0.0; 
	signal(SIGINT, cleanup); //trap cntrl c
	signal(SIGPIPE, cleanup);
	//turn off output buffering for ttcp!
	//setvbuf(stdout,(char*)NULL,_IONBF,0);
	//init buffers for old tracking... 
	for(int i=0; i<4; i++){
                g_buffer[i] = (short*)malloc(640*480*sizeof(short)); 
        }
        g_averagefb = (int*)malloc(640*480*sizeof(int)); 
        g_velfb = (int*)malloc(640*480*sizeof(int));
        g_lastfb = (unsigned char*)malloc(640*480);	
        g_trackedfb = (unsigned char*)malloc(640*480);	
        for(i=0; i < 640*480; i++){
                g_averagefb[i] = 0; 
        }
	//Step -2: set up threads (the display runs on a seperate thread
	// to keep from blocking the iscochronous recieve channel
	// and hence causing the frame rate to drop. 
	pthread_mutex_init(&g_dispthread_mutex, NULL); 
	pthread_cond_init(&g_dispthread_cond, NULL); 
	//STEP -1: init the parallel port for control of mirror (this also starts that thread)
	parallel_setup(); 
	//Step 0: small shutter so we can track the light easily. 
	smallShutter(); 
	//Step 0.5: move the mirror to the close left (from but of light) for calibration
	//for reference (from the viewpoint of the cord end of the light): 
	// pan left : s
	// pan right: w
	// tilt toward: a
	// tilt away: s
	// small shutter: x
	// open shutter: o
	// closed shutter: c
	// stop mirrors : <space>
	for(i=0; i<10; i++){
		enqueue('s'); //to the left if you are looking at the but of the light.
		enqueue('a'); //the tilt axis has far fewer steps for full range than
		enqueue('s'); // the pan axis hence requires a much higher velocity - 
		enqueue('s'); // so enqueue more 's'. 
		enqueue('s'); 
		enqueue('s'); 
	}
	//Step 1: Open ohci and assign a handle to it.
	//==================================================================================================================
	init_cards();
        //Step 2: Get the camera nodes and describe them as we find them.
	//==================================================================================================================
	init_cams();
        //Step 3: Setup Capture
	//==================================================================================================================
	setup_cams();
	//Step 4: Start sending data
	//==================================================================================================================
	start_iso_transmission();
	//start the other thread. 
	pthread_t thread1;
	pthread_attr_t attr;
	pthread_attr_init(&attr);
	pthread_create( &thread1, &attr, display_thread, 0 ); 
	
	//Main event loop
	while(g_main_loop==true){
		for( i=0; i<numCameras; i++){
			if(dc1394_dma_single_capture(&camera[i]) != DC1394_SUCCESS){
				fprintf(stderr, "dma1394: Failed to capture from cameras\n");
				cleanup(0);
			}
		}
		t2=get_time();
		for( i=0; i<numCameras; i++){
			//display_frames_old(i);
			display_frames(i);
			/*if((g_frame%60) < 15){
				velstep(0); 
			}else if((g_frame%60) < 45){
				velstep(2); 
			}else {
				velstep(0); 
			}	*/			
			if(dc1394_dma_done_with_buffer(&camera[i]) != DC1394_SUCCESS){
				fprintf(stderr, "dma1394: Can't release dma bufer\n");
			}
		}
		
		if(g_frame % 60 == 0){
			printf("frame dt: %f (%f) track time %f (%f)\n", t2-t4, 1/(t2-t4), tracktime, 1/(tracktime)); 
		}
		//start with the state machine for the calibration -- 
		if(g_frame == CALIB_0){
			enqueue(' '); //stop it
			printf("!!assuming that the mirror reached it's limit!!\n");
			for( i=0; i<3; i++){
				//now that we have put the mirror into a corner, give it velocity
				// to move to the center of the FOV so that we may turn on 
				// feedback-based tracking. 
				enqueue('w'); //to the left if you are looking at the but of the light.
				enqueue('d'); 
				enqueue('w'); //again, pan motor has many more steps/range than tilt
				enqueue('w');
				enqueue('w');
				enqueue('w');
				enqueue('w');
				enqueue('w');
				enqueue('w');
			}
		}
		if(g_frame == CALIB_1){
			enqueue(' '); //stop it
			printf("!!assuming light is centered now!!\n");
		}
		if(g_frame == CALIB_2){
			enqueue('x');  
		}
		t4 = t2; 
		g_frame++; 
	}
	cleanup(0); 
	return 0;
}

Our tracking algorithm periodically opens and closes the shutter on the light. It is impossible to track a target based on brightness or even pattern detection, since the light is so bright it is impossible to image what it hits and what it does not with our cameras of limited dynamic range. (The human eye, of course, has far better dynamic range.) During the period when the light is off, we wait for the camera shutter speed to stabilize, then average the brightest spot over 10 consecutive frames to obtain a target position. Then, the shutter is opened, and visual feedback is used with a simple PD controller to guide the light to the target. When the device is deployed, we will make the update non-periodic and purely contingent on the detection of motion or of decreased solar cell output. See below for the thread that implements this logic, as well as blits the image onto the screen.

void* display_thread(void* ptr ){
	make_window(); 
	while(g_main_loop){
		if(pthread_cond_wait(&g_dispthread_cond, &g_dispthread_mutex) == 0){
			pthread_mutex_unlock(&g_dispthread_mutex); 
			double t1 = get_time(); 
			g_first_frame=false;
			//convert into the XV format (this seems very inefficient to me...)
			for(unsigned int i=0; i< g_framewidth*g_frameheight; i++){
				g_fb[i] = g_trackedfb[i]+ 0x8000;
			}
			double c_r, c_c; 
			new_track(0, &tcam[0], g_trackedfb, 
				g_framewidth, g_frameheight, CONTRAST_MIN, SEARCHR, 
				GAUSSDROPOFF, NUMBER_OF_MARKERS, &c_r, &c_c);
			xv_image=XvCreateImage(display, info[adaptor].base_id, 
				format_disp, (char*)g_fb, g_framewidth, g_frameheight*numCameras);
			XvPutImage(display, info[adaptor].base_id, window, gc, xv_image, 0, 
				0, g_framewidth, g_frameheight*numCameras, 0, 0,
				g_windowwidth, g_windowheight);
			free(xv_image); 
			
			//do some dumb control (finally!)
			// initially, guide the light to the center of the screen. 
			if(g_frame > CALIB_1 && g_frame <= CALIB_2){
				g_target_c = 320.0; 
				g_target_r = 240.0; 
				servo_mirror(c_c, c_r); //get it stuck on the center! 
			}
			int time = g_frame - CALIB_2; 
			// below is the *main loop* for cycling the shutter open/close
			if(g_frame > CALIB_2){
				if(time % 300 < 240){
					servo_mirror(c_c, c_r); 
				}
				if(time % 300 == 240){
					enqueue('c'); 
					enqueue(' '); 
				}
				if(time % 300  >= 260 && time % 300  < 280 ){
					g_target_c += c_c; 
					g_target_r += c_r; 
				}
				if(time % 300 == 280){
					enqueue('x'); 
					g_target_c /= 20.0; 
					g_target_r /= 20.0; 
				}
			}
			double t2 = get_time(); 
			tracktime = t2 - t1 ; 
		}
		//normalize_com(NUMBER_OF_MARKERS);
		XFlush(display);
		while(XPending(display)>0){
			XNextEvent(display,&xev);
			switch(xev.type){
				case ConfigureNotify:
					g_windowwidth=xev.xconfigure.width;
					g_windowheight=xev.xconfigure.height;
				break;
				case KeyPress:
					switch(XKeycodeToKeysym(display,xev.xkey.keycode,0)){
						case XK_q:
						case XK_Q:
							g_main_loop = false; 
							//cleanup(0);
						break;
						}
				break;
			}
		} //XPending
	}
	if ((void *)window != NULL){
		XUnmapWindow(display,window);
	}
	fprintf(stderr,"dma1394: Unmapped Window.\n");
	if (display != NULL){
		XFlush(display);
	}
	return (void*) 0;
}

The PD controller uses very pessimistic values for the coefficients, as we discovered that the timing resolution on out older linux computer is low - about 5ms. This means that if too many velocity step commands are sent to the parallel port thread at one time, it will get backlogged, which will induce a phase-shift between control and actuation of velocity. Hence, the light must move rather slowly, on the order of one velocity step on each axis per frame. Again, below.

void servo_mirror(double c_c, double c_r ){
	double dc = c_c - g_target_c; //for now assume that we want to stabilize in
	double dr = c_r - g_target_r; // the center.
	double vgain = 8.0 ; 
	double pgain = 1.0/80.0; 
	int lim = 1; 
	double c = dc + g_velPan*vgain ; 
	int ccmd = 0; 
	int rcmd = 0; 
	if(c > 0){
		for(int i=0; i<c*pgain && i < lim; i++){
			enqueue('w');
			ccmd --; 
		}
	}
	if(c < 0){
		for(int i=0; i<c*-1.0*pgain && i < lim; i++){
			enqueue('s');
			ccmd ++; 
		}
	}
		
	vgain *= 1.5; //tilt mirror moves quicker!
	double r = dr + g_velTilt*vgain;
	if(r>0){
		for(int i=0; i<r*pgain && i < lim; i++){
			enqueue('d');
			rcmd--; 
		}
	}
	if(r<0){
		for(int i=0; i<r*-1.0*pgain && i < lim; i++){
			enqueue('a');
			rcmd++; 
		}
	}
	//this for debugging loop stability problems in matlab. 
	//printf("%f %f %d %f %f %d\n", dc, g_velPan*vgain, ccmd, dr, g_velTilt*vgain, rcmd); 
	//if(dr + g_velTilt*vgain > 0) enqueue('d'); OLD
	//if(dr + g_velTilt*vgain < 0) enqueue('a'); 
}

Our video tracking algorithm first uses a tree-like algorithm to quickly and robustly search for the brightest region in the scene; we presume, somewhat simplistically, that this will be the target. When the device is put into use with an actual monkey cage, we'll surround the camera with high-intensity infrared LEDs to effectively illuminate a retroreflector placed on the monkey's head. Below is the code which performs this computation.

//make a blur matrix
//void blur(frame_info* frame, unsigned char * fb, int framewidth, int downsamp, int downsamp_w, int downsamp_h){
void blur(int camno, track_cam* tcam, unsigned char* fb, int framewidth, int downsamp_r, int downsamp_c, int downsamp_w, int downsamp_h){
	//initialize contrasts
	for(int m=0; m<downsamp_r * downsamp_c; m++){
		tcam[camno].frame.sum[m]=0;
		tcam[camno].frame.contr_min[m]=255;
		tcam[camno].frame.contr_max[m]=0;
	}
	for(int k=0; k<downsamp_r; k++){	
		for(int row=k*downsamp_h; row<k*downsamp_h+downsamp_h; row++){
			for(int j=0; j<downsamp_c; j++){
				for(int col=j*downsamp_w; col<j*downsamp_w+downsamp_w; col++){
					tcam[camno].frame.sum[j+(k*downsamp_c)]+=int(fb[row*framewidth+col]);
					if(int(fb[row*framewidth+col])>tcam[camno].frame.contr_max[j+(k*downsamp_c)]){
						tcam[camno].frame.contr_max[j+(k*downsamp_c)]=int(fb[row*framewidth+col]); //introducing a contrast check.  
					}
					if(int(fb[row*framewidth+col])<tcam[camno].frame.contr_min[j+(k*downsamp_c)]){
						tcam[camno].frame.contr_min[j+(k*downsamp_c)]=int(fb[row*framewidth+col]); //introducing a contrast check
					}
				}
			}
		}
	}
}

//blob_search function
//search through the sum matrix and find the brightest sums
//void blob_search(frame_info* frame, marker* marker, int num_markers, int contrast_min){
void blob_search(int camno, track_cam* tcam, int num_markers, int contrast_min, int downsamp_r, int downsamp_c){
	//frame->num_blobs=0; //innocent until proven guilty
	for(int i=0; i<num_markers; i++){
		int blob_val=0;
		for(int m=0; m<downsamp_r*downsamp_c; m++){
			if(tcam[camno].frame.sum[m]>blob_val && tcam[camno].frame.contr_max[m]-tcam[camno].frame.contr_min[m]>contrast_min){ //has to have a big contrast to be a blob (CONTRAST is user defined macro)
				blob_val=tcam[camno].frame.sum[m]; //the new max'
				tcam[camno].marker[i].downsamp_loc=m; //the sum integer (0-255)
				//frame->num_blobs++;
			}
		}
		tcam[camno].frame.sum[tcam[camno].marker[i].downsamp_loc]=0; //kill the one we just found so we can find the next biggest one.
	}
}

//brightest_pix_search function
//search through the blobs for the brightest pixel
//void brightest_pix_search(unsigned char * fb, frame_info* frame, marker* marker, int num_markers, int framewidth, int downsamp, int downsamp_w, int downsamp_h){
void brightest_pix_search(unsigned char * fb, int camno, track_cam* tcam, int num_markers, int framewidth, int downsamp_r, int downsamp_c, int downsamp_w, int downsamp_h){
	//br_pix_info[0] is the row
	//br_pix_info[1] is the col
	//br_pix_info[2] is the value
	for(int i=0; i<num_markers; i++){
		tcam[camno].marker[i].br_pix_val=0; //always has to start low
		for(int row=int(floor(tcam[camno].marker[i].downsamp_loc/downsamp_c))*downsamp_h; row<int(floor(tcam[camno].marker[i].downsamp_loc/downsamp_c))*downsamp_h+downsamp_h; row++){
			for(int col=tcam[camno].marker[i].downsamp_loc%downsamp_c*downsamp_w; col<tcam[camno].marker[i].downsamp_loc%downsamp_c*downsamp_w+downsamp_w; col++){
				if(int(fb[row*framewidth+col])>tcam[camno].marker[i].br_pix_val){ //if it is greater than the brightest pixel then store its info
					tcam[camno].marker[i].br_pix_row=row; //save the row
					tcam[camno].marker[i].br_pix_col=col; //save the column
					tcam[camno].marker[i].br_pix_val=int(fb[row*framewidth+col]); //save the value
				}
			}
		}
	}
}

The blocking (or blobbing) and search algorithm yields the estimated location of the brightest pixel in the image. This is passed to a specialized array-growth region growing algorithm which dynamically expands a region around the suggested brightest pixel to include all pixels that are within a threshold of brightness to the brightest. The region growing algorithm then computes the center of mass from the list of pixel coordinates, which are then passed to the PD and target location routines.

void region_grow(unsigned char * src, unsigned short* dest, 
		int w, int h, int b_r, int b_c, double* c_r, double* c_c){
	//need to do an expansion from the brightest point. 
	//this is sorta a random-access op - which is bad. 
	unsigned short fill = 0xff00; 
	int n = 0; 
	short r, c; 
	int  i, p; 
	unsigned char thresh = 20 ; 
	unsigned char brightest = src[w*b_r + b_c]; 
	g_rows[n] = b_r; 
	g_cols[n] = b_c; 
	n++; 
	int sta = 0; 
	int end = 0; 
	int lim = sizeof(g_rows)/sizeof(int); 
	while(n < lim && n > sta){
		//loop through all the new points, adding to the set as we go. 
		end = n; 
		for(i=sta; i < end; i++){
			r = g_rows[i]; 
			c =  g_cols[i]; 
			r++; //down
			if(r >= 0 && r < h && c >= 0 && c < w && n < lim){
				p = r*w +c; 
				if(brightest - src[p] < thresh){
					src[p] = 0; 
					dest[p] = fill; 
					g_rows[n] = r; 
					g_cols[n] = c; 
					n++; 
				}
			}
			r -= 2; //up.
			if(r >= 0 && r < h && c >= 0 && c < w && n < lim){
				p = r*w +c; 
				if(brightest - src[p] < thresh){
					src[p] = 0; 
					dest[p] = fill; 
					g_rows[n] = r; 
					g_cols[n] = c; 
					n++; 
				}
			}
			r++; //center
			c++; //to the right. 
			if(r >= 0 && r < h && c >= 0 && c < w && n < lim){
				p = r*w +c; 
				if(brightest - src[p] < thresh){
					src[p] = 0; 
					dest[p] = fill; 
					g_rows[n] = r; 
					g_cols[n] = c; 
					n++; 
				}
			}
			c-=2; //to the left. 
			if(r >= 0 && r < h && c >= 0 && c < w && n < lim){
				p = r*w +c; 
				if(brightest - src[p] < thresh){
					src[p] = 0; 
					dest[p] = fill; 
					g_rows[n] = r; 
					g_cols[n] = c; 
					n++; 
				}
			}
		}//end loop over past points. 
		sta = end; 
	}
	//calculate the center of mass. 
	double cm_r = 0; 
	double cm_c = 0; 
	for(i=0; i<n; i++){
		cm_r += g_rows[i]; 
		cm_c += g_cols[i]; 
	}
	cm_r /= n; 
	cm_c /= n; 
	*c_r = cm_r; 
	*c_c = cm_c; 
	//printf("point: %f %f %d \n",  cm_r, cm_c, g_frame++); 
	int cm_r_i, cm_c_i; 
	cm_r_i = (int)cm_r; 
	cm_c_i = (int)cm_c; 
	if(cm_c_i >= 0 && cm_c_i < w && cm_r_i >= 0 && cm_r_i < h)
		dest[cm_r_i*w + cm_c_i] = 0xffff; 
}

And that is, roughly, the entirety of the video tracking program! (Most of the rest of the code deals with the firewire bus and other less interesting details.) We conclude with a picture of the whole setup in the office.

{648}
hide / edit[0] / print
ref: notes-0 tags: ME270 light video tracking date: 12-04-2008 00:07 gmt revision:0 [head]

Section 3 - Video tracking and host computer control

With the microcontroller done, we then moved to controlling it via a video-tracking computer. At this point, we had created a simple program for testing out parallel port control of the light's three axes using the keyboard (tilt, pan, and shutter). This program was split into two files, a main, and a set of subroutines that could then be called and compiled into the full video tracking program. It uses libparapin to abstract interaction with the parallel port in userspace.

First, the main loop, which is very simple:

#include "parallelout.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

char g_main_loop ; 

int main(int argc, char *argv[])
{
	g_main_loop = 1; 
	char c;
	parallel_setup(); 
 
	while(1){
		c = fgetc(stdin);
		interpret_cmd(c); 
	}
}

Second, the parallel port controller. This uses a thread and circular queue to provide asynchronous, non-blocking control of the communications channel. Non-blocking is critical, as the program waits a small period between low-high transition of the interrupt pin (pin 4) for the MSP430 to read the status of the three lines.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <parapin.h>
#include <pthread.h>

#include "parallelout.h"

char g_q[1024]; //queue for the commands. 

int g_q_rptr; //where to read the next command from. 
int g_q_wptr; //where to put the next command

double g_velPan; 
double g_velTilt; 

void stepstep(void){
       int i = 0;
       for(i=0; i<20000; i++){
               set_pin(LP_PIN[4]);
               clear_pin(LP_PIN[4]);
	       set_pin(LP_PIN[5]);
               clear_pin(LP_PIN[5]);
	       set_pin(LP_PIN[5]);
               clear_pin(LP_PIN[5]);
       }
}

void velstep(int n){
	//printf("velstep %d\n", n); 
	clear_pin(LP_PIN[4]);
	if(n&0x1) set_pin(LP_PIN[2]) ; 
	else clear_pin(LP_PIN[2]); 
		
	if(n&0x2) set_pin(LP_PIN[3]) ; 
	else clear_pin(LP_PIN[3]); 
	set_pin(LP_PIN[4]); 
	//leave it up, so the msp430 knows it is a velocity command. 
}
void openShutter(){
	printf("opening shutter\n"); 
	clear_pin(LP_PIN[4]);
	set_pin(LP_PIN[2]); 
	set_pin(LP_PIN[3]); 
	set_pin(LP_PIN[4]); 
	clear_pin(LP_PIN[4]); //clear the trigger to indicate a shutter command. 
}
void closeShutter(){
	printf("closing shutter\n"); 
	clear_pin(LP_PIN[4]);
	clear_pin(LP_PIN[2]); 
	clear_pin(LP_PIN[3]); 
	set_pin(LP_PIN[4]); 
	clear_pin(LP_PIN[4]); //clear the trigger to indicate a shutter command. 
}
void smallShutter(){
	printf("small shutter\n"); 
	clear_pin(LP_PIN[4]);
	clear_pin(LP_PIN[2]); 
	set_pin(LP_PIN[3]); 
	set_pin(LP_PIN[4]); 
	clear_pin(LP_PIN[4]); //clear the trigger to indicate a shutter command. 
}
void stopMirror(){
	printf("stop mirror\n"); 
	clear_pin(LP_PIN[4]);
	set_pin(LP_PIN[2]); 
	clear_pin(LP_PIN[3]); 
	set_pin(LP_PIN[4]); 
	clear_pin(LP_PIN[4]); //clear the trigger to indicate a shutter command. 
}

void parallel_setup(){
	if (pin_init_user(LPT1) < 0)
		exit(0);

	pin_output_mode(LP_DATA_PINS | LP_SWITCHABLE_PINS);
	clear_pin(LP_PIN[2]);
	clear_pin(LP_PIN[3]); 
	clear_pin(LP_PIN[4]); 
	pthread_t thread1;
	//start the queue-servicing thread. 
	pthread_create ( &thread1, NULL, pq_thread, NULL ); 
}

void interpret_cmd(char cmd){
	//these codes don't make much sense unless you are 
	//controlling from a keyboard.
	switch(cmd){
		case 'w': velstep(0); g_velPan-=1.0; break; //pan to right (looking at but of light)
		case 'a': velstep(1); g_velTilt+=1.0; break; //tilt toward.
		case 's': velstep(2); g_velPan+=1.0; break; //pan to left
		case 'd': velstep(3); g_velTilt-=1.0; break; //tilt away
		case 'o': openShutter(); break; 
		case 'c': closeShutter(); break; 
		case 'x': smallShutter(); break;
		case ' ': stopMirror(); g_velPan=0; g_velTilt=0; break; 
	}
}

void usleep(int us){
	timespec ts; 
	ts.tv_sec = 0; 
	ts.tv_nsec = us * 1000; 
	nanosleep(&ts, NULL);
}

extern int g_main_loop ; 

void* pq_thread(void* a){
	while(g_main_loop){
		if(g_q_wptr > g_q_rptr){
			char cmd = g_q[g_q_rptr % sizeof(g_q)]; 
			g_q_rptr++; 
			interpret_cmd(cmd); 
		}
		usleep( 200 ); // run at max 500hz update.
		// the msp430 takes about 125us to service the parallel port irq.
	}
	return (void*)0;
}

void enqueue(char cmd){
	//this should be sufficiently atomic so there is no thread contention.
	g_q[g_q_wptr % sizeof(g_q)] = cmd; 
	g_q_wptr++; 
}

Then, we worked on the video tracking program. I will omit the some of the noncritical sections involving the firewire (ieee1394), Xv (video display) and X11 (window manager) calls, as the whole program is long, ~1000 lines. Below is 'main' -- see the comments for a detailed description.

int main(int arc, char *argv[]){
	int i; 
	double t1, t2, t3, t4; 
	t1 = t2 = t3 = t4 = 0.0; 
	signal(SIGINT, cleanup); //trap cntrl c
	signal(SIGPIPE, cleanup);
	//turn off output buffering for ttcp!
	//setvbuf(stdout,(char*)NULL,_IONBF,0);
	//init buffers for old tracking... 
	for(int i=0; i<4; i++){
                g_buffer[i] = (short*)malloc(640*480*sizeof(short)); 
        }
        g_averagefb = (int*)malloc(640*480*sizeof(int)); 
        g_velfb = (int*)malloc(640*480*sizeof(int));
        g_lastfb = (unsigned char*)malloc(640*480);	
        g_trackedfb = (unsigned char*)malloc(640*480);	
        for(i=0; i < 640*480; i++){
                g_averagefb[i] = 0; 
        }
	//Step -2: set up threads (the display runs on a seperate thread
	// to keep from blocking the iscochronous recieve channel
	// and hence causing the frame rate to drop. 
	pthread_mutex_init(&g_dispthread_mutex, NULL); 
	pthread_cond_init(&g_dispthread_cond, NULL); 
	//STEP -1: init the parallel port for control of mirror (this also starts that thread)
	parallel_setup(); 
	//Step 0: small shutter so we can track the light easily. 
	smallShutter(); 
	//Step 0.5: move the mirror to the close left (from but of light) for calibration
	//for reference (from the viewpoint of the cord end of the light): 
	// pan left : s
	// pan right: w
	// tilt toward: a
	// tilt away: s
	// small shutter: x
	// open shutter: o
	// closed shutter: c
	// stop mirrors : <space>
	for(i=0; i<10; i++){
		enqueue('s'); //to the left if you are looking at the but of the light.
		enqueue('a'); //the tilt axis has far fewer steps for full range than
		enqueue('s'); // the pan axis hence requires a much higher velocity - 
		enqueue('s'); // so enqueue more 's'. 
		enqueue('s'); 
		enqueue('s'); 
	}
	//Step 1: Open ohci and assign a handle to it.
	//==================================================================================================================
	init_cards();
        //Step 2: Get the camera nodes and describe them as we find them.
	//==================================================================================================================
	init_cams();
        //Step 3: Setup Capture
	//==================================================================================================================
	setup_cams();
	//Step 4: Start sending data
	//==================================================================================================================
	start_iso_transmission();
	//start the other thread. 
	pthread_t thread1;
	pthread_attr_t attr;
	pthread_attr_init(&attr);
	pthread_create( &thread1, &attr, display_thread, 0 ); 
	
	//Main event loop
	while(g_main_loop==true){
		for( i=0; i<numCameras; i++){
			if(dc1394_dma_single_capture(&camera[i]) != DC1394_SUCCESS){
				fprintf(stderr, "dma1394: Failed to capture from cameras\n");
				cleanup(0);
			}
		}
		t2=get_time();
		for( i=0; i<numCameras; i++){
			//display_frames_old(i);
			display_frames(i);
			/*if((g_frame%60) < 15){
				velstep(0); 
			}else if((g_frame%60) < 45){
				velstep(2); 
			}else {
				velstep(0); 
			}	*/			
			if(dc1394_dma_done_with_buffer(&camera[i]) != DC1394_SUCCESS){
				fprintf(stderr, "dma1394: Can't release dma bufer\n");
			}
		}
		
		if(g_frame % 60 == 0){
			printf("frame dt: %f (%f) track time %f (%f)\n", t2-t4, 1/(t2-t4), tracktime, 1/(tracktime)); 
		}
		//start with the state machine for the calibration -- 
		if(g_frame == CALIB_0){
			enqueue(' '); //stop it
			printf("!!assuming that the mirror reached it's limit!!\n");
			for( i=0; i<3; i++){
				//now that we have put the mirror into a corner, give it velocity
				// to move to the center of the FOV so that we may turn on 
				// feedback-based tracking. 
				enqueue('w'); //to the left if you are looking at the but of the light.
				enqueue('d'); 
				enqueue('w'); //again, pan motor has many more steps/range than tilt
				enqueue('w');
				enqueue('w');
				enqueue('w');
				enqueue('w');
				enqueue('w');
				enqueue('w');
			}
		}
		if(g_frame == CALIB_1){
			enqueue(' '); //stop it
			printf("!!assuming light is centered now!!\n");
		}
		if(g_frame == CALIB_2){
			enqueue('x');  
		}
		t4 = t2; 
		g_frame++; 
	}
	cleanup(0); 
	return 0;
}

Our tracking algorithm periodically opens and closes the shutter on the light. It is impossible to track a target based on brightness or even pattern detection, since the light is so bright it is impossible to image what it hits and what it does not with our cameras of limited dynamic range. (The human eye, of course, has far better dynamic range.) During the period when the light is off, we wait for the camera shutter speed to stabilize, then average the brightest spot over 10 consecutive frames to obtain a target position. Then, the shutter is opened, and visual feedback is used with a simple PD controller to guide the light to the target. When the device is deployed, we will make the update non-periodic and purely contingent on the detection of motion or of decreased solar cell output. See below for the thread that implements this logic, as well as blits the image onto the screen.

void* display_thread(void* ptr ){
	make_window(); 
	while(g_main_loop){
		if(pthread_cond_wait(&g_dispthread_cond, &g_dispthread_mutex) == 0){
			pthread_mutex_unlock(&g_dispthread_mutex); 
			double t1 = get_time(); 
			g_first_frame=false;
			//convert into the XV format (this seems very inefficient to me...)
			for(unsigned int i=0; i< g_framewidth*g_frameheight; i++){
				g_fb[i] = g_trackedfb[i]+ 0x8000;
			}
			double c_r, c_c; 
			new_track(0, &tcam[0], g_trackedfb, 
				g_framewidth, g_frameheight, CONTRAST_MIN, SEARCHR, 
				GAUSSDROPOFF, NUMBER_OF_MARKERS, &c_r, &c_c);
			xv_image=XvCreateImage(display, info[adaptor].base_id, 
				format_disp, (char*)g_fb, g_framewidth, g_frameheight*numCameras);
			XvPutImage(display, info[adaptor].base_id, window, gc, xv_image, 0, 
				0, g_framewidth, g_frameheight*numCameras, 0, 0,
				g_windowwidth, g_windowheight);
			free(xv_image); 
			
			//do some dumb control (finally!)
			// initially, guide the light to the center of the screen. 
			if(g_frame > CALIB_1 && g_frame <= CALIB_2){
				g_target_c = 320.0; 
				g_target_r = 240.0; 
				servo_mirror(c_c, c_r); //get it stuck on the center! 
			}
			int time = g_frame - CALIB_2; 
			// below is the *main loop* for cycling the shutter open/close
			if(g_frame > CALIB_2){
				if(time % 300 < 240){
					servo_mirror(c_c, c_r); 
				}
				if(time % 300 == 240){
					enqueue('c'); 
					enqueue(' '); 
				}
				if(time % 300  >= 260 && time % 300  < 280 ){
					g_target_c += c_c; 
					g_target_r += c_r; 
				}
				if(time % 300 == 280){
					enqueue('x'); 
					g_target_c /= 20.0; 
					g_target_r /= 20.0; 
				}
			}
			double t2 = get_time(); 
			tracktime = t2 - t1 ; 
		}
		//normalize_com(NUMBER_OF_MARKERS);
		XFlush(display);
		while(XPending(display)>0){
			XNextEvent(display,&xev);
			switch(xev.type){
				case ConfigureNotify:
					g_windowwidth=xev.xconfigure.width;
					g_windowheight=xev.xconfigure.height;
				break;
				case KeyPress:
					switch(XKeycodeToKeysym(display,xev.xkey.keycode,0)){
						case XK_q:
						case XK_Q:
							g_main_loop = false; 
							//cleanup(0);
						break;
						}
				break;
			}
		} //XPending
	}
	if ((void *)window != NULL){
		XUnmapWindow(display,window);
	}
	fprintf(stderr,"dma1394: Unmapped Window.\n");
	if (display != NULL){
		XFlush(display);
	}
	return (void*) 0;
}

The PD controller uses very pessimistic values for the coefficients, as we discovered that the timing resolution on out older linux computer is low - about 5ms. This means that if too many velocity step commands are sent to the parallel port thread at one time, it will get backlogged, which will induce a phase-shift between control and actuation of velocity. Hence, the light must move rather slowly, on the order of one velocity step on each axis per frame. Again, below.

void servo_mirror(double c_c, double c_r ){
	double dc = c_c - g_target_c; //for now assume that we want to stabilize in
	double dr = c_r - g_target_r; // the center.
	double vgain = 8.0 ; 
	double pgain = 1.0/80.0; 
	int lim = 1; 
	double c = dc + g_velPan*vgain ; 
	int ccmd = 0; 
	int rcmd = 0; 
	if(c > 0){
		for(int i=0; i<c*pgain && i < lim; i++){
			enqueue('w');
			ccmd --; 
		}
	}
	if(c < 0){
		for(int i=0; i<c*-1.0*pgain && i < lim; i++){
			enqueue('s');
			ccmd ++; 
		}
	}
		
	vgain *= 1.5; //tilt mirror moves quicker!
	double r = dr + g_velTilt*vgain;
	if(r>0){
		for(int i=0; i<r*pgain && i < lim; i++){
			enqueue('d');
			rcmd--; 
		}
	}
	if(r<0){
		for(int i=0; i<r*-1.0*pgain && i < lim; i++){
			enqueue('a');
			rcmd++; 
		}
	}
	//this for debugging loop stability problems in matlab. 
	//printf("%f %f %d %f %f %d\n", dc, g_velPan*vgain, ccmd, dr, g_velTilt*vgain, rcmd); 
	//if(dr + g_velTilt*vgain > 0) enqueue('d'); OLD
	//if(dr + g_velTilt*vgain < 0) enqueue('a'); 
}

Our video tracking algorithm first uses a tree-like algorithm to quickly and robustly search for the brightest region in the scene; we presume, somewhat simplistically, that this will be the target. When the device is put into use with an actual monkey cage, we'll surround the camera with high-intensity infrared LEDs to effectively illuminate a retroreflector placed on the monkey's head. Below is the code which performs this computation.

//make a blur matrix
//void blur(frame_info* frame, unsigned char * fb, int framewidth, int downsamp, int downsamp_w, int downsamp_h){
void blur(int camno, track_cam* tcam, unsigned char* fb, int framewidth, int downsamp_r, int downsamp_c, int downsamp_w, int downsamp_h){
	//initialize contrasts
	for(int m=0; m<downsamp_r * downsamp_c; m++){
		tcam[camno].frame.sum[m]=0;
		tcam[camno].frame.contr_min[m]=255;
		tcam[camno].frame.contr_max[m]=0;
	}
	for(int k=0; k<downsamp_r; k++){	
		for(int row=k*downsamp_h; row<k*downsamp_h+downsamp_h; row++){
			for(int j=0; j<downsamp_c; j++){
				for(int col=j*downsamp_w; col<j*downsamp_w+downsamp_w; col++){
					tcam[camno].frame.sum[j+(k*downsamp_c)]+=int(fb[row*framewidth+col]);
					if(int(fb[row*framewidth+col])>tcam[camno].frame.contr_max[j+(k*downsamp_c)]){
						tcam[camno].frame.contr_max[j+(k*downsamp_c)]=int(fb[row*framewidth+col]); //introducing a contrast check.  
					}
					if(int(fb[row*framewidth+col])<tcam[camno].frame.contr_min[j+(k*downsamp_c)]){
						tcam[camno].frame.contr_min[j+(k*downsamp_c)]=int(fb[row*framewidth+col]); //introducing a contrast check
					}
				}
			}
		}
	}
}

//blob_search function
//search through the sum matrix and find the brightest sums
//void blob_search(frame_info* frame, marker* marker, int num_markers, int contrast_min){
void blob_search(int camno, track_cam* tcam, int num_markers, int contrast_min, int downsamp_r, int downsamp_c){
	//frame->num_blobs=0; //innocent until proven guilty
	for(int i=0; i<num_markers; i++){
		int blob_val=0;
		for(int m=0; m<downsamp_r*downsamp_c; m++){
			if(tcam[camno].frame.sum[m]>blob_val && tcam[camno].frame.contr_max[m]-tcam[camno].frame.contr_min[m]>contrast_min){ //has to have a big contrast to be a blob (CONTRAST is user defined macro)
				blob_val=tcam[camno].frame.sum[m]; //the new max'
				tcam[camno].marker[i].downsamp_loc=m; //the sum integer (0-255)
				//frame->num_blobs++;
			}
		}
		tcam[camno].frame.sum[tcam[camno].marker[i].downsamp_loc]=0; //kill the one we just found so we can find the next biggest one.
	}
}

//brightest_pix_search function
//search through the blobs for the brightest pixel
//void brightest_pix_search(unsigned char * fb, frame_info* frame, marker* marker, int num_markers, int framewidth, int downsamp, int downsamp_w, int downsamp_h){
void brightest_pix_search(unsigned char * fb, int camno, track_cam* tcam, int num_markers, int framewidth, int downsamp_r, int downsamp_c, int downsamp_w, int downsamp_h){
	//br_pix_info[0] is the row
	//br_pix_info[1] is the col
	//br_pix_info[2] is the value
	for(int i=0; i<num_markers; i++){
		tcam[camno].marker[i].br_pix_val=0; //always has to start low
		for(int row=int(floor(tcam[camno].marker[i].downsamp_loc/downsamp_c))*downsamp_h; row<int(floor(tcam[camno].marker[i].downsamp_loc/downsamp_c))*downsamp_h+downsamp_h; row++){
			for(int col=tcam[camno].marker[i].downsamp_loc%downsamp_c*downsamp_w; col<tcam[camno].marker[i].downsamp_loc%downsamp_c*downsamp_w+downsamp_w; col++){
				if(int(fb[row*framewidth+col])>tcam[camno].marker[i].br_pix_val){ //if it is greater than the brightest pixel then store its info
					tcam[camno].marker[i].br_pix_row=row; //save the row
					tcam[camno].marker[i].br_pix_col=col; //save the column
					tcam[camno].marker[i].br_pix_val=int(fb[row*framewidth+col]); //save the value
				}
			}
		}
	}
}

The blocking (or blobbing) and search algorithm yields the estimated location of the brightest pixel in the image. This is passed to a specialized array-growth region growing algorithm which dynamically expands a region around the suggested brightest pixel to include all pixels that are within a threshold of brightness to the brightest. The region growing algorithm then computes the center of mass from the list of pixel coordinates, which are then passed to the PD and target location routines.

void region_grow(unsigned char * src, unsigned short* dest, 
		int w, int h, int b_r, int b_c, double* c_r, double* c_c){
	//need to do an expansion from the brightest point. 
	//this is sorta a random-access op - which is bad. 
	unsigned short fill = 0xff00; 
	int n = 0; 
	short r, c; 
	int  i, p; 
	unsigned char thresh = 20 ; 
	unsigned char brightest = src[w*b_r + b_c]; 
	g_rows[n] = b_r; 
	g_cols[n] = b_c; 
	n++; 
	int sta = 0; 
	int end = 0; 
	int lim = sizeof(g_rows)/sizeof(int); 
	while(n < lim && n > sta){
		//loop through all the new points, adding to the set as we go. 
		end = n; 
		for(i=sta; i < end; i++){
			r = g_rows[i]; 
			c =  g_cols[i]; 
			r++; //down
			if(r >= 0 && r < h && c >= 0 && c < w && n < lim){
				p = r*w +c; 
				if(brightest - src[p] < thresh){
					src[p] = 0; 
					dest[p] = fill; 
					g_rows[n] = r; 
					g_cols[n] = c; 
					n++; 
				}
			}
			r -= 2; //up.
			if(r >= 0 && r < h && c >= 0 && c < w && n < lim){
				p = r*w +c; 
				if(brightest - src[p] < thresh){
					src[p] = 0; 
					dest[p] = fill; 
					g_rows[n] = r; 
					g_cols[n] = c; 
					n++; 
				}
			}
			r++; //center
			c++; //to the right. 
			if(r >= 0 && r < h && c >= 0 && c < w && n < lim){
				p = r*w +c; 
				if(brightest - src[p] < thresh){
					src[p] = 0; 
					dest[p] = fill; 
					g_rows[n] = r; 
					g_cols[n] = c; 
					n++; 
				}
			}
			c-=2; //to the left. 
			if(r >= 0 && r < h && c >= 0 && c < w && n < lim){
				p = r*w +c; 
				if(brightest - src[p] < thresh){
					src[p] = 0; 
					dest[p] = fill; 
					g_rows[n] = r; 
					g_cols[n] = c; 
					n++; 
				}
			}
		}//end loop over past points. 
		sta = end; 
	}
	//calculate the center of mass. 
	double cm_r = 0; 
	double cm_c = 0; 
	for(i=0; i<n; i++){
		cm_r += g_rows[i]; 
		cm_c += g_cols[i]; 
	}
	cm_r /= n; 
	cm_c /= n; 
	*c_r = cm_r; 
	*c_c = cm_c; 
	//printf("point: %f %f %d \n",  cm_r, cm_c, g_frame++); 
	int cm_r_i, cm_c_i; 
	cm_r_i = (int)cm_r; 
	cm_c_i = (int)cm_c; 
	if(cm_c_i >= 0 && cm_c_i < w && cm_r_i >= 0 && cm_r_i < h)
		dest[cm_r_i*w + cm_c_i] = 0xffff; 
}

And that is, roughly, the entirety of the video tracking program! (Most of the rest of the code deals with the firewire bus and other less interesting details.) We conclude with a picture of the whole setup in the office.

{624}
hide / edit[5] / print
ref: notes-0 tags: elektralite mm150 optical power light ME270 project date: 12-03-2008 20:39 gmt revision:5 [4] [3] [2] [1] [0] [head]

Section 1 : Reverse-engineering the light, part selection

Rather than engineering our own articulated spotlight, we elected to buy a moving-mirror DJ light; creating our own light source would simply have taken too much time, and demanded optical experience that we lack. After a brief survey, we bought an Elekralite mm150 (moving mirror, 150W bulb) DJ light, one of the cheapest on the market ($650); despite this, it is very well constructed, as you will see below. The light was originally controlled through the stage-specific DMX bus, but the possibility of directly controlling the light through this was discarded after we learned that the resolution on each axis is only 8 bits (+- 127); given the large range of the pan mirror, this is insufficient for tracking. Hence we decided to reverse engineer the light to determine the best way to directly control the mirror and shutter.
  • Overview, with dichroic color filter wheel and globos removed. We ended up putting these back in, as without them the unit does not initialize properly.
  • Another view with the shell taken off. The white ballast on the bottom powers the 150W HMI metal-halide bulb, along with a stabilization capacitor (to the left of the ballast) and starter (below the capacitor). The starter produces 2kV to initially ionize the gas in the bulb; there is no third starter electrode as in mercury vapor bulbs, as this would be a point of stress in the high-pressure (90atm) fused quartz arc tube. The bulb is on whenever the unit is plugged in, and the light output is controlled via the shutter. The top large transformer (+20V, +12V) is used to drive the display/control unit (left center) and the 6 stepper motors in the lamp, which are:
    • mirror tilt
    • mirror pan
    • shutter
    • globo selection
    • globo rotate
    • colorwheel
    • Detail of the breakout board for the 6 stepper motors, with the colorwheel stepper above it. The stepper motors are two-phase, permanent-magnet rotor types; we're not sure of the steps/revolution yet, though they all seem different. The breakout board also has attachments for the hall-effect sensors to detect orientation of the globo and color wheels.
    • The dichroic mirror color wheel. Regular filters would undoubtedly melt here - a pencil put into the beam of the HMI lamp will light on fire!
    • The globo wheel. Each globo is mounted to a gear which engages a center gear on the same axis as this plate. This center gear is driven by the globo rotate stepper motor.
    • Dichroic IR filter. Note that since it is viewed at an angle, the reflective wavelength goes up, and so you can see a slight red tint in the reflections off this. Removed this, since silicon photovoltaic cells respond to near IR energy.
    • Stepper motor controller. The three chips at the bottom are NXP 87LPC768 OTP microcontroller. Each can control two stepper motors, and each has an internal program for self-calibration using either the hall-effect sensors or hard mechanical limits on motor range. Upper chip is for the mirror (U3). These chips are controlled via one high-speed serial bus from the upper control board (the one with the LED display). The six upper chips, with heat-sinks on them, contain dual H-bridges, probably similar to the Allegro A3955 PWM microstepping motor driver. Between them are two standard 74HC04 hex inverters to drive the opposite leg of the h-bridges (each 87LPC768 has four outputs, two per motor, whereas each motor requires four inputs, two per phase. In this way, you can switch the direction of current flow through each motor phase with a single +20v supply rail.)
    • The Elekralite mm150 without the two control boards, globo wheel, or filter wheel. You can see the lamp, focus adjustment screws and reflector. Below the lamp is a 24V radial fan.
    • The Elektralite powered on, with globo and filter wheel back in place. The lamp is very, very bright!
    • Close-up of filter and globo wheels. The shutter has been removed; it fits on the shaft just above the long hex spacer. Just above that is the mechanical hard stop for the shutter.
    • The pin on the main controller that is used to control the 6 stepper axes. We tried probing it for some time, but could not directly figure out the serial protocol without a good logic analyzer (which is at home), so decided to implement our own microstepping PWM controller, and drive the inverters / H-bridges driectly.
    • The shutter, after being used for a good bit. The UV and IR from the lamp (mostly the IR, I think - the shutter gets really hot!) bleaches the black anodization on this bit of aluminum. We've drilled a 1/4" hole in one side to try to get a more tightly-collated beam.
    • The PWM waveform at the motor for the two phases (the glare at the left is from the light, which was of course on!). The other leads in the motor are simply the inverse of these via the 74HC04. For vector control like this, a 50% on/50% off PWM effectively sets the phase current to zero (the motor has sufficient leakage inductance at the 16kHz PWM frequency to keep di/dt low over multiple PWM periods). Hence, to control the motors we need something like:
      phase1 = 0.5*sin(theta) + 0.5 ; phase2 = 0.5*cos(theta) + 0.5
      , where theta is changed based on the control algorithm, and phase is scaled and used to set the PWM counter compare register. See below.
    • Microstepping control scheme based on vector control of current in the two phases of these stepper motors. As before, current will be regulated via PWM @ 16kHz, as the Elektralite engineers do, as opposed to linear current control. To generate the appropriate 6 PWM signals (mirror pan, mirror tilt, and shutter), we used a MSP430 microcontroller with 3 16-bit counters and 5+ capture-compare registers.
    • We used a MSP430F5xxx development board from TI -- see the next section. The device features sufficient timers and PWM outputs to control the stepper motors in the Elekralite. We will control motion of each using a simple up-down toggling via the parallel port to increment/decrement the motor theta variable. The microcontroller will need a look-up table or algorithm for calculating the sines and cosines of rotor angles.
    • small solar cell from Spark Fun Electronics. When placed in the beam of the light, it is possible to generate 500ma short-circuit current and 5V open-circuit voltage, but not at the same time. In a solar cell composed of a series of junctions, such as this, the total current at full voltage is limited by the minimum current from each of the junctions (they are in series!). Therefore to get maximum current you need very uniform illumination, something that is normally not difficult with the sun, but which will be difficult in this application. To avoid this problem we will try to procure higher efficiency single-junction GaAs concentrator cells, which can be up to ~40% efficient (as compared to this one, which is ~15% efficient).

{643}
hide / edit[1] / print
ref: notes-0 tags: artificial cerebellum robot date: 11-06-2008 17:16 gmt revision:1 [0] [head]

Artificial Cerebellum for robot control:

{640}
hide / edit[5] / print
ref: notes-0 tags: robots pick place date: 11-06-2008 16:32 gmt revision:5 [4] [3] [2] [1] [0] [head]

Misc. interesting pick & place robotics projects on the web:

{637}
hide / edit[0] / print
ref: notes-0 tags: wireless spectrum FCC regulation nytimes date: 10-13-2008 22:52 gmt revision:0 [head]

My comments on this blog post, preseved here for posterity:

I agree with William’s first point, spectrum is ‘owned’ by everybody; the government’s only purpose is to regulate it so that it remains an effective communication medium. Like the bandwidth that it uses, the communication system is optimally owned by users, hence it is a bad idea to auction off segments of spectrum for exclusive use by corporations.

Examine at what happened to the 2.4 GHz band, an area where water absorption is high and most households have a 1kw noise generator (microwave oven): EVERYONE USES IT because it is FREE and OPEN, no licenses required. Just look at all the innovation created for this band: 802.11, bluetooth, ZigBee, cordless phones, wireless remotes, and others. If 802.11 was in the 700-1GHz band someone or a company could easily make long-distance wireless repeaters & mesh-network nodes, sell them to consumers, and everyone could SIP for FREE without paying Verizon / ATT etc. This could set it up as a pyramid scheme, where to get on the network you simply have to buy a mesh node repeater, and with it became part of the ‘corporation’ which provided your wireless services. A certain part of the purcase & access price would, of course, need to go to pay for backbone connections, service, matenance and extending connection to remote areas, but this too can be solved and managed efficiently with something like 1 phone = 1 share.

With coprotations, you either have redundancy (two networks w/ twice as many cell towers) or a monopoly; neither are economically efficient. A re-allocation of prime wireless spectrum back to the correct owners - the citizens - would spur American Innovation greatly and simultaneously cut communication costs. The technology is changing, and the policy should too!

Anyway, i’m sick of paying $0.10 for 100 bytes of data (txt messages) when audio data costs ~1/500th that.

{590}
hide / edit[1] / print
ref: notes-0 tags: ocaml run external command stdin date: 09-10-2008 19:32 gmt revision:1 [0] [head]

It is not obvious how to run an external command in ocaml & get it's output from stdin. Here is my hack, which simply polls the output of the program until there is nothing left to read. Not very highly tested, but I wanted to share, as I don't think there is an example of the same on pleac

let run_command cmd = 
	let inch = Unix.open_process_in cmd in
	let infd = Unix.descr_of_in_channel inch in
	let buf = String.create 20000 in
	let il = ref 1 in
	let offset = ref 0 in
	while !il > 0 do (
		let inlen = Unix.read infd buf !offset (20000- !offset) in
		il := inlen ; 
		offset := !offset + inlen;
	) done; 
	ignore(Unix.close_process_in inch);  
	if !offset = 0 then "" else String.sub buf 0 !offset
	;;

Note: Fixed a nasty string-termination/memory-reuse bug Sept 10 2008

{599}
hide / edit[1] / print
ref: notes-0 tags: sony robots date: 09-09-2008 18:36 gmt revision:1 [0] [head]

Sony Robots:

  • youtube video - the robots are amazingly articulated (including the hips/ankles) , and the sequence of movements is quite long!
  • Sony QRIO (Quest for cRIOsity) entertainment robot.
    • QRIO video
    • One of the first robots that is able to run (both feet off the ground at one time).
    • Stereo Vision
    • Adaptive balance to protect the all-important head
    • Sophisticated AI : Interestingly, when they’re doing demonstrations, they have found that the AI in QRIO is so strong that if you haven’t been friendly with it before hand, for examples, by not kicking back a football it kicks to you, it will refuse to do what you ask it in the demonstration. Effectively it is expressing its annoyance. source
    • Not for commercial sale: too expensive to manufacture - approximately $50k. Only about 100 in existence. Seems to be somewhat of a 'halo technology'.
      • Startes circa 2002, discontinued January 26 2006.
  • Sony AIBO (Artificial Intelligence RObot)
    • able to learn from the environment.
    • Sounds created by Nobukazu Takemura; has a MIDI processor on-board.
    • built-in wireless LAN.
    • total 20 DOF
    • single VGA resolution camera for vision
    • ~ $2k price, 130k sold so far.
    • Sony released a development kit at the behest of the community; AIBO is useful as it is a good platform for AI & robotics research.
  • Industrial robots:
    • SCARA robot (4 axis?):

{593}
hide / edit[5] / print
ref: notes-0 tags: robots Tokyo Institute of Technology date: 09-04-2008 17:30 gmt revision:5 [4] [3] [2] [1] [0] [head]

Robots & others designed & made at the Tokyo Institute of Technology (from the Hirose / Fukushima Robotics lab)

  • snake robots
  • gripper
      • with human-crushing, kid-grabbing power. frightening!
  • walking robots
      • -- 1994. can climb a 70 degree slope!
    • --window washing robot.
    • -- skating robot: walk ; skate. movie -- wow!
  • wheeled robots
  • other
    • -- prismatic, variable-speed eccentric linear drive. sorta like harmonic drive for linear motion? link

{592}
hide / edit[5] / print
ref: notes-0 tags: CMU robotics date: 09-02-2008 16:50 gmt revision:5 [4] [3] [2] [1] [0] [head]

Robotics Research at Carnegie Mellon University (CMU):

The list is not complete!

{588}
hide / edit[2] / print
ref: notes-0 tags: linear discriminant analysis LDA EMG date: 07-30-2008 20:56 gmt revision:2 [1] [0] [head]

images/588_1.pdf -- Good lecture on LDA. Below, simple LDA implementation in matlab based on the same:

% data matrix in this case is 36 x 16, 
% with 4 examples of each of 9 classes along the rows, 
% and the axes of the measurement (here the AR coef) 
% along the columns. 
Sw = zeros(16, 16); % within-class scatter covariance matrix. 
means = zeros(9,16); 
for k = 0:8
	m = data(1+k*4:4+k*4, :); % change for different counts / class
	Sw = Sw + cov( m ); % sum the 
	means(k+1, :) = mean( m ); %means of the individual classes
end
% compute the class-independent transform, 
% e.g. one transform applied to all points
% to project them into one plane. 
Sw = Sw ./ 9; % 9 classes
criterion = inv(Sw) * cov(means); 
[eigvec2, eigval2] = eig(criterion);

See {587} for results on EMG data.

{438}
hide / edit[7] / print
ref: notes-0 tags: filter DSP finite precision 16bit blackfin matlab date: 07-22-2008 03:25 gmt revision:7 [6] [5] [4] [3] [2] [1] [head]

I needed to evaluate different fixed-point filters & implement them in a way which would more-or-less easily transfer to hand-coded blackfin assembly. Hence, I wrote a small program in C to test two likely alternatives: a 5th order elliptic filter, with 82db stopband rejection, or a 4th order elliptic, with 72 db stopband rejection. see {421} also, and this useful reference. (also at {584})

UPDATE: this filter is not stable/ suitable for the 1.15 signed fraction format of the blackfin processor. As in the reference, you must use a non-canonic form which puts the numerator before the denominator. I had a great deal of difficulty trying to determine why the output of the Direct Form II filter was giving crap results with poles/zeros designed for lowpass operation. The reason appears to be that the Direct FormII filter requires dynamic range > +-1 for the w's (first feedback section). The numerator / b coefficients for these highpass filters is usually [1 -2 1] - a highpass - which returns 0 when passed saturated data. See the signal flowchart below.

The program for implementing these filters as cascaded biquad/ triquads follows. The method of generating the filter coefficients is in the comments. Note that the filter coefficients for the triquad exceed and absolute magnitude of 2, hence the triquad implementation has a fixed-point format of s.2.13 (one bit sign, 2 bits whole part, 13 bits fractional part). The biquad has s.1.14 format - one bit for the whole part. Also note that I incorporated a scale factor of x2 into the first stage, and x4 into the second stage, as the output of the ADC is only 12 bits and we can afford to expand it to the full range.

The filter responses, as designed (in floating point). 5th order is on the left, 4th on the right.

The filter output to white noise, in the time domain. 5th order has, in this impementation, a 'softer shoulder', which i do not think is appropriate for this application.

The same output in fourier space, confirming the softer shoulder effect. this was actually kinda unespected .. I thought an extra pole/zero would help! I guess the triquad & lower res coefficient quantization is less efficient.. ?

#include <stdio.h>
// gcc -Wall filter_test.c -o filter_test

//need to test fixed-point filtering in C (where it is easy)
//before converting to hand-coded assembly. 
short w1_1[2]= {0,0};
short w1_2[3]= {0,0,0};
short w2_1[2]= {0, 0}; 
short w2_2[2]= {0, 0}; 
/*
filter 1: 5th order. biquad then a triquad.
[B1, A1] = ellip(5,0.2,84, 6/31.25); %84db = 14 bits. 
rb = roots(B1); 
ra = roots(A1); 
pa1 = poly(ra(1:2)); 
pa2 = poly(ra(3:5)); 
pb1 = poly(rb(1:2)); 
pb2 = poly(rb(3:5)); 
b1_1 = round(pb1*sqrt(B1(1))*2^15)
a1_1 = round(pa1* 2^14)* -1
b1_2 = round(pb2*sqrt(B1(1))*2^15)
a1_2 = round(pa2*2^13)*-1 % triquad.
*/
//biquad1: 
short b1_1[3] = {1199, 87, 1199}; 
short a1_1[2] = {24544 -14085};
//triquad1: 
short b1_2[4] = {1199, 2313, 2313, 1199};
short a1_2[3] = {18090, -14160, 3893};

/*filter 2: can be implemented by 2 biquads. 
[B3, A3] = ellip(4,0.5,72, 6/31.25);
rb = roots(B3); 
ra = roots(A3); 
pa1 = poly(ra(1:2)); 
pa2 = poly(ra(3:4)); 
pb1 = poly(rb(1:2)); 
pb2 = poly(rb(3:4)); 
b2_1 = round(pb1*sqrt(B3(1))*2^15)
a2_1 = round(pa1* 2^14)* -1
b2_2 = round(pb2*sqrt(B3(1))*2^16) %total gain = 8. 
a2_2 = round(pa2*2^14)*-1
*/
//biquad2: 
short b2_1[3] = {2082, 914, 2082};
short a2_1[2] = {24338, -13537}; 
//biquad2 (2): 
short b2_2[3] = {4163, 6639, 4163};
short a2_2[2] = {24260, -9677}; 

int madd_sat(int acc, short a, short b){
	//emulate the blackfin
	//signed-integer mode of operating. page 567  in the programming reference.
	int c; 
	long long l, lo, hi;
	lo = (long long)(-2147483647); 
	hi = (long long)(2147483647); 
	c = (int)a * (int)b; 
	l = (long long)acc + (long long)c; 
	if(l < lo)
		l = lo; 
	if(l > hi)
		l = hi; 
	acc = (int)l; 
	return acc; 
}
//need to deal with samples one at a time, as they come in, from different channels
//need to quantize the coeficients
//need to utilize a biquad topology / filter structure.  
//   (this is simple - just segregate the poles. order 5 filter req. biquad & triquad. 
short filter_biquad(short in, short* a1, short* b1, short* w1){
	int acc; 
	short out, w; 
		
	//in varies from 0 to 0x0fff - ADC is straight binary. (0 to 4095). unsigned.
	acc = madd_sat(0, in, 16384); 
	acc = madd_sat(acc, w1[0], a1[0]); 
	acc = madd_sat(acc, w1[1], a1[1]);
	w = (short)(acc >> 14); //hopefully this does sign-extended shift. 
	acc = madd_sat(0, w, b1[0]); 
	acc = madd_sat(acc, w1[0], b1[1]); 
	acc = madd_sat(acc, w1[1], b1[0]); //symmetry.  
	out = (short)(acc >> 14); 
	w1[1] = w1[0]; 
	w1[0] = w; 
	return out; 
}
short filter_triquad(short in, short* a2, short* b2, short* w2){
	int acc; 
	short out, w; 
	//this one is a bit different, as the coefficients are > 2 in the denom. 
	// hence have to normalize by a different fraction. 
	//multiply the numerator by 4 for a net gain of 8.
	
	acc = madd_sat(0   , in, 8192); 
	acc = madd_sat(acc, w2[0], a2[0]); 
	acc = madd_sat(acc, w2[1], a2[1]); 
	acc = madd_sat(acc, w2[2], a2[2]); 
	w = acc >> 13; 
	acc = madd_sat(0   , w, b2[0]); 
	acc = madd_sat(acc, w2[0], b2[1]); 
	acc = madd_sat(acc, w2[1], b2[1]); 
	acc = madd_sat(acc, w2[2], b2[0]); //symmetry.
	out = (short)(acc >> 13); 
	w2[2] = w2[1]; 
	w2[1] = w2[0]; 
	w2[0] = w; 
	return out; 
}

int main( int argv, char* argc[]){
	//read the samples from stdin.
	int in, out; 
	while(scanf("%d", &in)){
		//compare 5th and 4th order filters directly. 
		in -= 2048; 
		out = filter_biquad(in, a1_1, b1_1, w1_1); 
		out = filter_triquad(out, a1_2, b1_2, w1_2); 
		printf("%d	", out); 
		out = filter_biquad(in, a2_1, b2_1, w2_1); 
		out = filter_biquad(out, a2_2, b2_2, w2_2); 
		printf("%d
", out); 
	}
	return 0; 
}
// gcc -Wall filter_test.c -o filter_test
//  cat filter_test_in.dat | ./filter_test > filter_test_out.dat

Below, some matlab code to test the filtering.

% make some noisy data. 

x = randn(2000, 1);
x = x .* 1000; 
x = x + 2048; 
i = find(x >= 4096)
x(i) = 4095; 
i = find(x < 0);
x(i) = 0; 
x = round(x); 
fid = fopen('filter_test_in.dat', 'w'); 
for k = 1:length(x)
	fprintf(fid, '%d
', x(k)); 
end
fprintf(fid, 'quit'); 
fclose(fid); 

Here is a blackfin assembly implementation of the filter, Note the filter weights (i0) and delays (i1, i2) need to be on two different cache/sram banks, or the processor will stall. Also note that , as per the second diagram above, the delays for biquad 1 output are synonymous to the delays for biquad 2 input, hence they are only represented once in memory.

	/*
	directform 1 biquad now, form II saturates 1.15 format.
	operate on the two samples in parallel (both in 1 32bit reg). 
	r0	x(n)				-- the input from the serial bus. 
	r1 	x(n-1) (yn-1)	-- ping-pong the delayed registers. 
	r2	x(n-2) (yn-2)	-- do this so save read cycles. 
	r3	y(n-1) (xn-1)
	r4	y(n-2) (xn-2)
	r5	b0 b1 			-- (low  high)
	r6	a0 a1
	
	i0 reads the coeficients into the registers; 
		it loops every 32 bytes (16 coef, 4 biquads)
	i1 reads the delays. 
		it loops every 640 bytes = 10 delays * 4 bytes/delay * 16 stereo channels.
		only increments. 
	i2 writes the delays, loops every 640 bytes. 
		also only increments. 
		if i1 and i2 are dereferenced in the same cycle, the processor will stall -- 
		each of the 1k SRAM memory banks has only one port. 
	
	format of delays in memory: 
	[x1(n-1) , 
	 x1(n-2) ,  
	 x2(n-1) aka y1(n-1) , 
	 x2(n-2) aka y1(n-2) , 
	 x3(n-1) aka y2(n-1) , 
	 x3(n-2) aka y2(n-2) , 
	 x4(n-1) aka y3(n-1) , 
	 x4(n-2) aka y3(n-2) , 
	 y4(n-1) , 
	 y4(n-2) ] 
	 --that's 10 delays, 4 bytes each. 
	*/
	
	r5 = [i0++] || r1 = [i1++]; 
	a0 = r0.l * r5.l , a1 = r0.h * r5.l || r6 = [i0++] ||  [i2++] = r0; 
	a0 += r1.l * r5.h, a1 += r1.h * r5.h || r2 = [i1++] ; 
	a0 += r2.l * r5.l, a1 += r2.h * r5.l || r3 = [i1++] ; 
	a0 += r3.l * r6.l, a1 += r3.h * r6.l || r4 = [i1++] ;
	r0.l = (a0 += r4.l * r6.h), r0.h = (a1 += r4.h * r6.h) (s2rnd) || [i2++] = r1;
	
	r5 = [i0++] || [i2++] = r0; 
	a0 = r0.l * r5.l, a1 += r0.h * r5.l || r6 = [i0++] || [i2++] = r3; 
	a0 += r3.l * r5.h, a1 += r3.h * r5.h || r1 = [i1++]; 
	a0 += r4.l * r5.l, a1 += r4.h * r5.l || r2 = [i1++]; 
	a0 += r1.l * r6.l, a1 += r1.h * r6.l; 
	r0.l = (a0 += r2.l * r6.h), r0.h = (a1 += r2.h * r6.h) (s2rnd); 
	
	r5 = [i0++] || [i2++] = r0; 
	a0 = r0.l * r5.l, a1 = r0.h * r5.l || r6 = [i0++] || [i2++] = r1; 
	a0 += r1.l * r5.h, a1 += r1.h * r5.h || r3 = [i1++]; 
	a0 += r2.l * r5.l, a1 += r2.h * r5.l || r4 = [i1++]; 
	a0 += r3.l * r6.l, a1 += r3.h * r6.l; 
	r0.l = (a0 += r4.l * r6.h), r0.h = (a1 += r4.h * r6.h) (s2rnd); 
	
	r5 = [i0++] || [i2++] = r0; 
	a0 = r0.l * r5.l, a1 += r0.h * r5.l || r6 = [i0++] || [i2++] = r3; 
	a0 += r3.l * r5.h, a1 += r3.h * r5.h || r1 = [i1++]; 
	a0 += r4.l * r5.l, a1 += r4.h * r5.l || r2 = [i1++]; 
	a0 += r1.l * r6.l, a1 += r1.h * r6.l; 
	r0.l = (a0 += r2.l * r6.h), r0.h = (a1 += r2.h * r6.h) (s2rnd); 
	
	[i2++] = r0; //save the delays. 
	[i2++] = r1; //normally this would be pipelined.

{584}
hide / edit[4] / print
ref: notes-0 tags: IIR blackfin filter paper Drutarovsky date: 07-19-2008 17:20 gmt revision:4 [3] [2] [1] [0] [head]

images/584_1.pdf -- this is a highly useful paper, but is no longer available on the author's website. For the good of all, i post it here. These may also have utility:

  • EE-197 -- Multicycle instructions and Latencies for the Blackfin BF531/2/3 processors. (10 stage pipeline, I think this should also applicable to the BF534/6/7 processors)
    • Seems like they have the pipeline well forwarded/interlocked for most of the DSP-type operations that you might want to perform (this is not so surprising).
    • However, you should be careful with 8-word aligning 64 bit instructions to prevent instruction fetch stalls, and spreading simultaneous data reads among different sub-blocks of the data L1/SRAM.
      • Data sub-blocks are 4096 bytes long (0x1000).
  • EE-171 -- Multicycle instructions and latencies for the Blackfin BF535 (8 stage pipeline)

{582}
hide / edit[0] / print
ref: notes-0 tags: bjork music life date: 07-12-2008 15:46 gmt revision:0 [head]

Bjork has a special place in my heart - and not only because of stuff like this: http://www.youtube.com/watch?v=jX9y6AA5oOo ;) When I was in college - not so far back as Post, but before Selmasongs - we used to play a lot of pool. Not so much that we didn't get any work done, but enough that we started getting good. Near the end of that year we filmed a bunch of games & made a music video set to Underworld's remix of "Human Behavior". I don't know what happened to the actual end product, but I do clearly recall my mom complaining about the repetitive beats while I was cutting the shots so the ball collisions would align with snare/bass hits. Sometime later that year I was blown away by the real deal, the "All is full of love" music video, projected on the side of the art museum at ~ 2am when the mind is labile... Bjork & her music pervaded that period for me. I've found that music can 'tag' periods of life for me, such that when I remember the music first then the events. This winter it was Interpol, last fall was Metric, spring 2007 was Arca (you *have* to hear them!). When me and my brother went to Portugal for a few weeks we found two Pixies mix tapes in the tiny car that my friend generously let us use. Hence, Frank Black soaked our ears while the incredible Portuguese sun soaked our skin.

{581}
hide / edit[1] / print
ref: notes-0 tags: android google date: 07-09-2008 03:33 gmt revision:1 [0] [head]

brilliant!! source: android winners

{579}
hide / edit[3] / print
ref: notes-0 tags: software debian xpaint maxima math mathematica date: 07-02-2008 14:37 gmt revision:3 [2] [1] [0] [head]

oldies but goodies:

  • Maxima a computer algebra system, almost like a free version of Mathematica!
    • be sure to install maxima-emacs to get LaTeX prettyprinting.
  • [xpaint] Has a cool spring-mass-friction system where the length of the spring (the distance between cursor and paint brush) controls the width of the paint brush. see below!

Both are in Debian of course :)

{502}
hide / edit[7] / print
ref: notes-0 tags: nordic nrf24L01 state diagram flowchart SPI blackfin date: 06-25-2008 02:44 gmt revision:7 [6] [5] [4] [3] [2] [1] [head]

Outline:

The goal is to use a nRF24L01 to make an asymmetrical, bidirectional link. The outgoing bandwidth should be maximized, ~1.5mbps, and the incoming bandwidth can be much smaller, ~17kbps, though on both channels we want guaranteed latency, < 4ms for the outgoing data, and < 10ms for the incoming data. Furthermore, the processor that is being used to run this, a blackfin BF532, does not seem to play well when both SPI DMA is enabled and most CPU time is being spent in SPORT ISR reading samples & processing them. Fortunately, the SPI port and SPORT can be run synchronously (provided the SPI port is clocked fast enough), allowing the processor to run one 'thread' e.g. no interrupts. It seem that with high-priority interrupts, the DMA engine is not able to service the SPI perfectly, and without DMA, data comes out of the SPI in drips and drabs, and cannot keep the radio's fifo full. Hence, must program a synchronous radio controller, where states are stored in variables and not in the program counter (PC register, saved upon interrupt, etc).

As in other postings on the nRF24L01, the plan is to keep the transmit fifo full for most of the 4ms allowed by the free-running pll, then transition back into either standby-I mode, or send a status packet. The status packet is always acknowledged by the primary receiver with a command packet, and this allows both synchronization and incoming bandwidth. Therefore, there are 4 classes of transfers:

  1. just a status packet. After uploading, wait for TX_DS IRQ, transition to RX mode, wait for RX_DR irq, clear ce, read in the packet, and set back to TX mode.
  2. one data packet + status packet. There are timeouts on both the transmission of data packets and status packets; in this case, both have been exceeded. Here TX data state is entered, the packet is uploaded, CE is asserted, send the status packet, wait for IRQ from both packets. This requires a transition from tx data CE high state to tx status CSN low state.
  3. many data packets and one status packet. This is the same as above, only the data transmission was triggered by a full threshold in the outgoing packet queue (in processor ram). In this case, two packets are uploaded to the radio before waiting for a TX_DS IRQ, and, at the end of the process, we have to wait for two TX_DS IRQs after uploading the data packet.
  4. many data packets. This is straightforward - upload 2 packets, wait for 1 TX_DS IRQ, {upload another, wait for IRQ}(until packets are gone), wait for final IRQ, set CE low.

screenshot of the derived code working (yea, my USB logic analyzer only runs on windows..yeck):

old versions:

{577}
hide / edit[0] / print
ref: notes-0 tags: grain protein growing framing feed oats alfalfa barley corn wheat date: 06-18-2008 15:14 gmt revision:0 [head]

I found this on my computer tucked away into a dusty corner. Such fascinating information should not be left hidden -

{511}
hide / edit[2] / print
ref: notes-0 tags: linux rsync date: 06-17-2008 17:36 gmt revision:2 [1] [0] [head]

simple backups to an external usb disk:

rsync --verbose --progress --stats --recursive --times --perms --links --del --ignore-errors /home/tlh24/ /media/usb0/

note:

  • the --del flag tells rsync to delete files in the target prior to writing them, not to delete the source files.
  • --times tells rsync to preserve file modification times.
  • for the --ignore-errors, see: http://lists.samba.org/archive/rsync/2004-June/009891.html - I was getting an IO error when trying to copy ~/.dbus etc.
  • otherwise, it's just rsync <options> <source> <dest> or so.

{227}
hide / edit[5] / print
ref: notes-0 tags: expectation maximization EM clustering autosorting date: 06-16-2008 19:40 gmt revision:5 [4] [3] [2] [1] [0] [head]

so, I coded up the EM algorithm - it was not hard, though i did have to put the likelihood calculation in C++ because i couldn't figure out how to vectorize it properly. It fits the clusters pretty well, but it does not tell you how many clusters there are!

clustering with 5 underlying gaussians:

plot of the log-likelihood of fitted gaussian mixtures vs. number of gaussians:

the code is in subversion, of course.

James has code for gibbs-sampling to the correct number of components! Here is an example of the output - it quickly removes the unnecessary gaussian components:

images/227_4.pdf -- original CEM (classification expectation maximization) paper, 1992, by Celeux and Govaert. Note that CEM with no variance estimation and gaussian clusters is the same as k-means, see {224}. See also http://klustakwik.sourceforge.net/

{568}
hide / edit[3] / print
ref: notes-0 tags: perl slurp a2a date: 04-07-2008 04:52 gmt revision:3 [2] [1] [0] [head]

My friend wanted to grab a whole bunch of data from a historical database site, http://www.a2a.org.uk/ . He was paying a person to manually copy all the records into excel (for a rather low fee, too, $150), and the guy was having a problem entering the rupee amounts, since it seems that in this historical data, currency is denominated my Rs xx-yy-z, where xx is rupees, yy are 1/16 rupee, and z is 1/64 of a rupee (cool base 2 system for currency, no?).

Neverminding the currency detail, I told him that I could easily write a script to screen-scrape this data and export it to a CSV file. For reference, here it is:

#!/usr/bin/perl

$narg = $#ARGV + 1; 
if( $narg ne 1 ){
	print "please specify the file to read"; 
}else{
	$source = $ARGV[0]; 
	local( $/, *FH ) ;
	open(FH, $source); 
	$/ = "FILE"; 
	@j = <FH>; #slurp entire file, split on 'FILE'
	close FH; 
	#print "num\tcase\tplaintiff\tdefendant\tior\tdatestart\tdateend\tclaim\tr1\tr2\tr3\tcountry1\tcountry2\n"; 
	foreach $l (@j){
		# try to match the line..
		# match must be robust, as some of the records are incomplete. 
		my $case = ""; 
		my $plaintiff = ""; 
		my $defendant = ""; 
		my $num = ""; 
		my $ior = ""; 
		my $datestart = ""; 
		my $dateend = ""; 
		my $claim = ""; 
		my $r1 = "0"; 
		my $r2 = "0"; 
		my $r3 = "0"; 
		my $cont1 = ""; 
		my $cont2 = ""; 
		$l =~ s/[\n\t]/ /g; # remove newlines &tabs.
		if($l =~ /Case\s([\d\/]+)([^<]+)/){
			$num = $1; 
			$case = $2; 
			$case =~ s/^: //; #remove leading colon space.
			if($case =~ /\(([^\)]+)\)[^\(]+\(([^\)]+)\)/ ){
				$cont1 = $1; 
				$cont2 = $2; 
			}
			#remove the countries (in parenthesis)
			$case =~ s/\([\w ]+\)//g;
			if($case =~ /(.+(?= v )) v (.+)/){
				$plaintiff = $1; 
				$defendant = $2; 
			}
			if($case =~ /(.+(?= v\. )) v\. (.+)/){
				$plaintiff = $1; 
				$defendant = $2; 
			}
		}
		if($l =~ /IOR([^<]+)/){
			$ior = $1; 
		}
		if($l =~ /date: <\/b>([^-]+)-([^<]+)<\/font>/){
			$datestart = $1; 
			$dateend = $2; 
		}elsif($l =~ /date: <\/b>([^<]+)<\/font>/){
			$datestart = $1; 
		}
		if($l =~ /Claim<\/span>([^<]+)/ ){
			$claim = $1;
			$claim =~ s/(\d),(\d)/$1$2/g; #remove commas from numbers.
			if($claim =~ /Rs\.* (\d+)[-\.](\d+)[-\.](\d+)/i){
				$r1 = $1; 
				$r2 = $2; 
				$r3 = $3; 
			}elsif($claim =~ /Rs\.* (\d+)[-\.](\d+)/i){
				$r1 = $1; 
				$r2 = $2; 
			}elsif($claim =~ /Rs\.* (\d+)/i){
				$r1 = $1; 
			}
		}
		if($num ne ""){
			print "$num\t$case\t$plaintiff\t$defendant\t$ior\t$datestart\t$dateend\t$claim\t$r1\t$r2\t$r3\t$cont1\t$cont2\n"; 
		}
	}
}

run it with > , e.g.

./a2a_extract.pl document.html > out1.csv
where document.html is saved from the web browser.

{375}
hide / edit[4] / print
ref: engineering notes-0 tags: BGA PCB design blueCore bluetooth laser drilling CSR via clearance date: 03-19-2008 22:35 gmt revision:4 [3] [2] [1] [0] [head]

This is from the CSR reference design for the BlueCore5 chip.

They also note that you have to pay attention to the aspect ratio of the vias - with laser drilling, this means that they needed a 63um prepreg between layers 1 and 2 (ground), with start copper thickness of 18um.

PTH = plated-through-hole. (refers to a type of via)

For 0.8mm BGA, you can loosen the design rules to the following: "

Minimum track width0.125mm(*) local, 0.15mm global0.005"
Minimum clearance0.125mm(*)0.005"
Minimum thru-hole0.15mm hole, 0.4mm landing under BGA0.006" on 0.016"
0.25mm hole, 0.6mm landing global0.01" on 0.024"
Solder Mask opening0.075mm radius opening around pads0.003"
(*) note: For a 0.8mm BGA with 0.4mm diameter pads, this could technically be 0.133mm, but I prefer to round to 1/8mm or just about 0.005"

{551}
hide / edit[2] / print
ref: notes-0 tags: DNA transfection yasuda experiment8 date: 03-17-2008 20:11 gmt revision:2 [1] [0] [head]

"

dishdnanameconc ug/ululug
1HM8-46His-mGFP-stop-C1-20.140.70.1
2HM8-46His-mGFP-stop-C1-20.143.60.5
5HM8-46His-mGFP-stop-C1-20.140.70.1
"HM8-47His-mCherry-stop-C10.120.830.1
6HM8-46His-mGFP-stop-C1-20.143.60.5
"HM8-47His-mCherry-stop-C10.120.830.1
7HM8-46His-mGFP-stop-C1-20.140.70.1
"HM8-47His-mCherry-stop-C10.124.20.5
8HM8-46His-mGFP-stop-C1-20.143.60.5
"HM8-47His-mCherry-stop-C10.124.20.5

{552}
hide / edit[0] / print
ref: notes-0 tags: CO2 global warming carbon dioxide indonesia brazil date: 03-14-2008 21:34 gmt revision:0 [head]

From the New Yorker, Feb 25:

  • "Just two countries - Indonesia and Brazil - account for ten percent of the greenhouse gasses released into the atmosphere. "
  • "During the next twenty-four hours the effect of losing forests in Brazil and Indonesia will be the same as if eight million people boarded airplanes at Heathrow airport and flew en mass to New York. "

{550}
hide / edit[3] / print
ref: notes-0 tags: cairo ocaml cvs date: 03-11-2008 02:36 gmt revision:3 [2] [1] [0] [head]

cairo-ocaml is broken in Debian (lenny) in that it is incompatible with liblabl-gtk2 in the repository; to compile ocaml programs (e.g. Geoproof) that depend on it, you need to :

  1. sudo apt-get install liblablgtk2-ocaml-dev
  2. get http://cairographics.org/snapshots/cairo-1.5.12.tar.gz, unpack, configure, make, make install.
  3. get the cvs version of cairo-ocaml (which apparently has not been touched in a few years..)
    1. cvs -d :pserver:anoncvs@cvs.cairographics.org:/cvs/cairo co cairo-ocaml (cvs syntax is confusing. I'm glad we have svn now)
    2. aclocal -I support
    3. autoconf
    4. ./configure (ignore complaints about LIBSVG_CAIRO)
    5. make
  4. oh, and make note of this (essential if you are using ocamlopt, the native compiler)

{545}
hide / edit[2] / print
ref: notes-0 tags: telecommunications FCC wireless regulation government date: 02-26-2008 04:18 gmt revision:2 [1] [0] [head]

http://news.zdnet.com/2010-1035_22-6231729.html

  • quote: Further loosening of the regulatory grip would stimulate investment and innovation in high-tech market segments, providing a long-term, sustainable boost for the American economy.
  • exactly! 2.4 Ghz, the 'junk' band, is TOO CROWDED. more open spectrum => more products and services => greater tax revenue (which would be >> revenue gained from stupid, greedy FCC auctions).
    • This revenue is passed onto the consumers. Think about it .. companies pay $20B for wireless, which they must pass on to the consumers, say 100M => an implicit $200 governmental 'tax' on something that should be free and clear. The government should just tax corporations & consumers directly, and not force companies to shoulder huge debts and risks. These debts put a very high bar for entering the competitive field .. which limits competition & technological advance.
  • however ... The author does not want to impose net neutrality. WHAT???? That means that corporations can effectively regulate information consumption. We are not just consumers, Mr. Randolph May.
    • eh.. I guess they already do this, e.g. Fox News. All the more reason to change the system.
    • Provided there is some choice in the marketplace, consumers will be able to reject any offensive limitation imposed by one 'provider', so perhaps it will work.

{544}
hide / edit[2] / print
ref: notes-0 tags: energy carbon CO2 hot water heater. date: 02-25-2008 23:36 gmt revision:2 [1] [0] [head]

How much carbon dioxide (CO2) is released to heat the water for a 5-minute shower?

  1. assumptions
    1. water enters your house at 45F, and you heat it to 100F.
    2. the energy efficiency of your hot water heater is 87%, and we ignore the cost of static thermal losses.
    3. you live in the southeast like me, which is predominantly powered by coal-fired plants. These plants release about 0.8kg/kwh of CO2 ref
    4. transmission of energy from the power plant to your home is 90% efficient
    5. you have a shower head that flows at a rate of 2.2 gallons/minute
  2. result: 2.2gpm -> 138.6 ml/sec -> * 31C temp rise -> 4.2kw -> 0.31kg CO2.
    1. that's about equivalent of driving 4 miles in a 30mpg car. (gasoline CO2 release = 2.4kg/gallon)

  • Interesting analysis. I'm surprised how much CO2 is used by those 5-minutes of delicious, delicious hot shower! --joeyo

{538}
hide / edit[0] / print
ref: notes-0 tags: two-photon laser imaging fluorescence lifetime imaging FRET GFP RFP date: 01-21-2008 17:23 gmt revision:0 [head]

images/538_1.pdf

{537}
hide / edit[1] / print
ref: notes-0 tags: kicad C++ design hierarchy date: 01-18-2008 22:06 gmt revision:1 [0] [head]

{530}
hide / edit[4] / print
ref: notes-0 tags: neuroscience ion channels information coding John Harris date: 01-07-2008 16:46 gmt revision:4 [3] [2] [1] [0] [head]

  • crazy idea: that neurons have a number of ion channel lines which can be selectively activated. That is, information is transmitted by longitudial transmission channels which are selectively activated based on the message that is transmitted
  • has any evidence for such a fine structure been found?? I think not, due to binding studies, but who knows..
  • dude uses historical references (Neumann) to back up his ideas. I find these sorts of justifications interesting, but not logically substantiative. Do not talk about the opinions of old philosophers (exclusively, at least), talk about their data.
  • interesting story about holography & the holograph of Dennis Gabor.
    • he does make interesting analogies to neuroscience & the importance of preserving spatial phase.
  • fourier images -- neato.
conclusion: interesting, but a bit cooky.

{531}
hide / edit[0] / print
ref: notes-0 tags: patent maintenance fee date: 01-06-2008 17:23 gmt revision:0 [head]

http://www.uspto.gov/go/pac/doc/general/

  • A maintenance fee is due 3 1/2, 7 1/2 and 11 1/2 years after the original grant for all patents issuing from the applications filed on and after December 12, 1980

{388}
hide / edit[6] / print
ref: notes-0 tags: PCB footprints date: 12-23-2007 20:00 gmt revision:6 [5] [4] [3] [2] [1] [0] [head]

--

  • SOT-23-6 from Zetex.
  • SOT-23 from NXP.
  • SMT notes -- details food SMT PCB design, on page 7 lists recommended land patterns.
  • SC70-6
    • there is a bit of disagreement on the pad pitch with TI's docs:

{526}
hide / edit[0] / print
ref: notes-0 tags: flock OSS opensource Mozilla LGPL money corporations browser comment embedded mobile opera date: 12-20-2007 16:23 gmt revision:0 [head]

I'm posting my comments about http://flock.com/ here just in case they are removed from the actual site


This is all very interesting. I just downloaded it, and flock seems to work well. I'm probably not going to use it unless there is some demonstrable technical superiority (e.g. leaks less memory than firefox), as the social sites just distract me from getting work done.

Anyway, I have a question: how are you going to make money? How are you paying the developers? If you are not and it is all OSS, where is the source? It seems like the VC's are just throwing money away for the (hypothetical) good of the social-network crowd. Or, rather, you are indirectly funding the popularity of sites that flock makes it easy to get at. Are these sites (e.g. facebook) paying you? Wait -- flock allows you to look at content and not the ads. They are not paying you.

Perhaps you are moving along the lines of Opera, and intending to get people addicted to flock to a degree that they demand it on their mobile devices. Mobile devices are closed (for now .. check google), hence you can make money licensing software to phone manufacturers. I imagine that you'll have to rewrite the Mozilla core to do this (unless phones become significantly more powerful - not likely, they are battery devices. ) Mozilla is (L)GPL - you'll have to release the source. To the best of my knowledge, with non-physical goods money can only be made from gradients in knowledge (pun.. intended), therefore you will have to keep the source closed. If this is the case, you'll be able to make money (on this, i don't know what else you have planned) for a while, and when you can no longer, I hope you open the source like netscape.

Technically, though, excellent job! your website is also very pretty!

{525}
hide / edit[1] / print
ref: notes-0 tags: skate sideskate freeline date: 12-19-2007 04:50 gmt revision:1 [0] [head]

Tim's list of skate-like devices, sorted by flatland speed, descending order:

  1. rollerblades / in-line skates. clap skates and xcountry training skates are up here too.
  2. skateboard -- skateboarders in central park can do the whole loop (~7 miles?) in about ~20 minutes = 21mph average. You can get some very fast wheels, bearings, and boards.
  3. streetboards / snakeboards -- great acceleration. Unlike sideskates, freelines, and Xliders, you do not have to reserve / use muscle capacity to keep from doing a split; all can be put into whipping the board up to speed.
  4. Onshoreboards -- Don't have one, but looks like a randal in back there. These things are kinda heavy - 13bs for the largest - but should be pumpable to high speed? Compared to the flowlabs, all axles (when going straight) are perpendicular to the direction of motion, so there should be little more than the rolling resistance of the 8 wheels. Note dual skate wheels on the back - I presume this was to cut costs, as good inline skate wheels are much cheaper than good skateboard wheels.
  5. sideskates -- these generally have higher top-end speed compared to freelines, but worse acceleration. rolling resistance is comparable to a skateboard; they have large patchs of urethane in contact with the ground, with no rotational shear from a axle at angle to road.
  6. freeline -- these are far more stable at speed than sideskates. However, contact patch with ground undergoes rotational shear, which in addition to the softer urethane and higher loading, makes for more friction than sideskates.
  7. Hammerhead -- faster than below because it has one standard skate truck. Have not tested it.
  8. Flowlab -- the wheels are not co-axial, so there will always be more rolling resistance than a skateboard. Urethane and bearing quality is low on these boards (e.g. 608zz electric motor bearings), simply because they need so many of both and must cut costs to compete with skateboards!
  9. The Wave -- seriously, slow. downhill speed is ok, no speed wobbles - but no powerslides either.
  10. Xliders -- The videos make it look rather slow. But, it also looks very choreographic / dance-like.
  11. Tierney Rides -- hard to pump, but not impossible. Dumb because it is easy to tilt the deck a bit to much, hit the edge, and slide out (the coefficient of friction of hard maple << urethane wheel). Tried to learn it for a while, but the over tilt / deck slide bruised my ankles too many times. This makes it bad for both downhill and flatland. On the plus side, these are very well made boards - buy one & put some randals on it :)

{498}
hide / edit[4] / print
ref: notes-0 tags: Lego NXT ARM Atmel date: 12-12-2007 20:04 gmt revision:4 [3] [2] [1] [0] [head]

so, what's inside a Lego NXT brick? note: this has all been rendered irrelevant -- Lego has published the hardware schematics for the NXT brick & associated sensors. go lego!

  • Top:
    • 1 Atmel AT91SAM7S256 ARM CPU.
      • This chip can be clocked at 55mhz, but i don't know what the Lego group clocked it at.
      • 64kb SRAM, 256kb flash.
      • 1.8V vdd core, 50ma max out of Vdd core, 10ma max out of flash.
      • supports both ARM 32-bit instruction set as well as 16-bit thumb instructions.
    • 1 Atmel ATMEGA48
    • CSR bluecore-4 bluetooth module, with parallel flash (looks like reference design) on a vertical pcb branded by Lego
    • linear voltage regulator (i assume, SOT-223 package)
    • ST485C RS-485/RS-422 transceiver
  • Bottom:
    • ST 74HC14D schmitt-trigger
    • switching regulator
    • resettable fuse
    • diode protection on all the I2C ports
    • something that seems to be a ST microelectronics 14-MSOP ??
    • linear voltage regulator (again SOT-223 package)
    • small speaker driver (tone generator?) 8-SOIC package, text too small to read.

{377}
hide / edit[26] / print
ref: engineering notes-0 tags: bluetooth CSR NXP headset radio telemetry 802.11 zigbee low-power date: 12-12-2007 06:10 gmt revision:26 [25] [24] [23] [22] [21] [20] [head]

the contenders:

  • NXP BGB210S, a 4th generation chip from Philip's spin-off NXP.
    • 3 x 5 x 1 mm (!!).
    • supports Bluetooth 2.0 + EDR.
      • the higher data rate is really targeted at decreasing the TX active time.
    • power consumption: 12ma @ 1.8v supply = 21.5mW
    • CMOS w/ near-zero intermediate frequency radio.
  • BGW211 802.11 system-on-a-chip, from NXP
    • 400mw Tx power, 300mw Rx - both too much, me thinks.
  • BCM4326
    • similar power figures (295mw rx, 425mw tx)
    • ultra-small 0.25mm WLCSP (!!)
    • one chip solution for 802.11b/g ; BCM4328 supports 802.11a, too.
  • Wi2wi w2cbw003 - 230ma tx, 210ma rx 802.11 module. too much.
  • G2 Microsystems , developers of 802.11B (11mbps) system-on-a-chip for RFID.
    • insanely low power dissipation! years on AA batteries! (based on 40s interval between data transmissions. 1.3mJ per transmission - an order of 500 lower than existing solutions. much lower static dissipation, too.
    • includes 32 bit RISC processor with 80kb ram, 320 kb flash/rom.
    • works with existing infrastructure, e.g. cisco.
    • article on the chip / product, may 2006.
    • http://www.gainspan.com/ -- competitors. they do not appear to have a product yet.
  • Freescale LP1070FC 802.11a/b/g, requires external PA, LNA, switch. no data on the power consumption... actually, the datasheet appears to be rather incomplete!
  • CSR UniFi-1 radio is far better, but I can't seem to find documentation for that, specifically the power dissipation.
    • well, let's see - 20 hours talk time with a 1500mAH battery = 75ma. not bad, i guess; TX power can be decreased for the short range we need.
  • BlueCore5 ; product brief, which includes more power info.
    • rather recently developed; is the silicon debugged? The datasheet is preliminary information.
    • 10 x 10mm, 0.8mm pitch 105 balls or 8x8 TFBGA.
    • 1.5V core, 1.8V-3.6V io, USB
    • bluetooth v2.0/2.1.
    • 64mips DSP on-chip.
      • 0.3 mA/MIPS at 1.5V. compare to Texas instruments TMS320VC5507 = 0.45ma/Mhz @ 1.2V core ~= 54Mw at 100mips; Kalimba ~= 30mw @64mips.
      • this is 2mips/channel. enough? damn, gotta keep the power low!
      • the Bluecore3 datasheet has more information on the DSP power consumption.
    • 16 Mbit flash, too!
    • BlueCore4 seems to be much better documented, but it does not include the DSP, which saves a lot on parts count.. as well as power.
  • Bluecore4
    • 8x8mm 96-bga,
    • with 6mbit flash!
    • bluetooth 2.0 / EDR.
    • current consumption of about 26ma @ 1.8V supply when in SCO HV3
  • Boroadcom BCM4326
    • single chip 802.11b/g solution, integrated Arm7 CPU
    • again, 300mW (not mA! smaller!) Rx, 400 mW Tx. That's still a lot of power.
  • Broadcom BCM2047
    • again, seems that these have yet to come out; details are scarce.
    • The belkin bluetooth 2.0 adapter that I bought at compusa uses a BCM2045.
  • CC2400, non-bluetooth - simpler!
  • Zarlink - ultra low power, 433Mhz ISM band biomedical tranciever.
    • about 7x7mm.
    • 3v supply, 2.7 should work, 5ma = 13.5mw (yesss!)
    • 800kbps raw data rate, max.
    • 2.45Ghz wakeup reciever (??)
    • seems to be designed for pacemakers & neurostimulators.
    • need to contact zarlink for the full data sheet.
  • RFM TR1100 - what the wolf lab uses for telemetry. OOK or ASK.
    • 1Mbps max.
    • only 1 channel, so far as i can tell...
    • 8ma @ 2.7V = 21.6mw.
    • integrated SAW filters = narrow bandwidth.
    • 10 x 6 mm size, minimal external components, though it does seem to require extra resistors.
    • really interesting method of obtaining RX input amplification stability - a SAW delay line, where the amplifiers are pulsed on at different times to permit the passage of RF energy. quote: "rf stability is obtained by distributing RF gain over time", as opposed to the superheterodyne solution of distributing gain over frequencies. If there were 100db of gain in 1 frequency, the amplifier is very likely to oscillate.
  • RFM TRC101
  • RFM TR3100 576 kbps ASK, -85dbm 10e-3 error rate.
    • 10ma TX / 7ma RX
    • 11x9,65mm SM-20L package
    • kinda has a lot of external components.
    • 434 mhz operation.
  • ADF7025 Analog 431-464, 862-870, 902-928 ISM band FSK transceiver.
    • 20ma TX (28ma at +10dbm) , 20ma RX from 2.3 to 3.6V supply.
    • direct conversion: zero IF.
    • SPI interface (plus a bunch of other signals).
    • 384kbps max data rate.
    • 7mm x 7mm 48 lead CSP
  • CC1101 (chipcon was acquired by TI)
    • 500kbps FSK, GFSK, MSK, OOK, ASK transmit/receive. 500kbps is only available in MSK, minimum-shift keying mode.
      • -84dbm receiver sensitivity @ 500kbps.
    • same bands as above + a bit more margin.
    • suitable for frequency hopping systems.
    • QLP 4mm x 4mm package
    • 16ma TX (32.3 at +10dbm), 16ma RX
    • 1.8 - 3.6V operation.
  • Freescale MC13192, Zigbee compliant transciever, 2.405 - 2.480 Mhz, 5mhz channels, 2Mchip/sec over the air data rate, 200kbps practical rate.
    • 30ma TX @ 0dbm, 37ma RX.
    • 5mm x 5mm package
    • full Zigbee PHY support.
    • similar device from ember - 35ma TX / 35ma RX, 2.1-3.5V, 7x7mm, includes microprocessor.
    • MC13201 - also targeted at 802.15.4 compliance.
      • good to 250kbps, 5.0 mhz channels, DSSS, 2.0 - 3.4V,
      • requires external transmit/receive switch
      • 30ma TX / 37ma RX
      • 5 x 5mm package
  • TI / Chipcon CC2430 - 27ma TX / 27ma RX, with microcontroller, 7x7mm package, quick power-up.
  • Cypress wireless USB
    • 2.4ghz, 1mbps, DSSS encoding (like zigbee) -- DSSS reduces the data rate, of course; the data rate over the air is always 1mbps.
      • the favored rate is 8x DSSS, where each symbol encodes one byte (8 bits) but requires 32 or 64 chips for transmission (resulting in a net rate of 250kbsp or 125 kbps, like zigbee. )
    • 21ma normal operating current @-5dbm, 1.8V to 3.6V
    • 6mm x 6mm 40-lead package
    • document above is a generally good overview of the complexities of this type of design.
  • SC1211
    • 110kbps, UHF transceiver (~863 - 960mhz). very low power consumption in RX: 3ma / TX: 25ma @ +10dbm out
    • out November 2007.
    • competitor to below -- much lower RX power (and lower rate).
    • includes 64byte fifo, data whitening, etc.
  • advance info from Maxim
    • very low power TX: 4ma @ -10dbm, RX: 150ua Hey.. that's lower power than most PLL, VCO, & PA put together!
    • OOK, ~116kbps.
  • Nordic nRF24L01 - THE BEST (so far!)
    • datasheet.
    • 12ma TX/RX, 2.1 3.6V
    • 2mbps over-the-air rate, GFSK, 10m range (better with a bigger antenna)
    • 4x4mm 20 pin package.
    • 125 selectable channels.
    • allows clock sharing with a microprocessor, e.g. the blackfin, provided it exceeds the 60ppm specification.
    • 22ua power consumption in standby-1 mode (transition from this state to RX/TX in 130us), 320ua power consumption in standby-2 mode (ready to transition to TX)
      • it is important to never keep the nRF24L01 in TX mode for more than 4ms at a time (!)
    • i think the designer's confidence showes through the specification sheet: they are proud of the chip & it's specifications, which is a very good thing. it means they put some pride and passion into it.
    • development board - need to buy! They also [distribute the IC http://www.sparkfun.com/commerce/product_info.php?products_id=690], yay!

{522}
hide / edit[5] / print
ref: notes-0 tags: FCC part15 regulations radio date: 12-11-2007 01:23 gmt revision:5 [4] [3] [2] [1] [0] [head]

from http://www.fcc.gov/oet/info/rules/part15/part15-9-20-07.pdf :

  • Also available through the e-CFR (electronic code of federal regulations) site.
    • Telecommunications is title 47, radio devices are part 15. Industrial, medical, and scientific equipment is part 18.
  • TBSI 31 ch headstage is under the 300uv @ 3m for unintentional transmitters above 960Mhz, in compliance with Section 15.109 a and b.
  • 2.4ghz ISM band: relevant regulations are part 15, section 15.247 specifies max 1W output power & restricts the channel structure FHSS and DSSS systems within these bands.
  • Wideband systems: Section 15.250
    • -63dbm EIRP 1610 - 1990 mhz. EIRP measured with a 1mhz bandwidth.
    • minimum 50MHz bandwidth. (can meet this!!)
    • to get a certification, you have to file the testing documentation with the FCC (not sure what else you need to do..) "alternative measurement procedures may be considered by the commission"
    • emissions below 960mhz must be compliant with section 15.209
  • ultra-wideband systems: Section 15.501
    • UWB = bandwidth > 500mhz, or bandwidth > 0.2 center frequency.
    • -53.3dbm EIRP in the 1610-1990 - The regulators allow an extra 10db (factor of 3) if your bandwidth is at least ~ 350Mhz, as compared to the wideband specification.
    • -41.3dbm EIRP 3.1ghz - 10.6ghz. This is where it's at! (a factor of 4 larger..)

{521}
hide / edit[8] / print
ref: notes-0 tags: UWB ultrawideband radio bandwidth date: 12-10-2007 23:11 gmt revision:8 [7] [6] [5] [4] [3] [2] [head]

from: http://bwrc.eecs.berkeley.edu/Presentations/Retreats/Summer_Retreat_2004/WednesdayPM/Retreat_Jun04_talk-ianv0.ppt

Above, FCC limitations on UWB transmitted power levels in communication devices. Currently, only the US allows operation of UWB transceivers.

links:

{506}
hide / edit[3] / print
ref: notes-0 tags: gcc inline assembler blackfin date: 11-22-2007 19:13 gmt revision:3 [2] [1] [0] [head]

So, you want to write inline assembly for the blackfin processor, perhaps to speed things up in a (very) time-constrained environment? Check this first:

  • calling ASM from C on a Blackfin
  • Inline assembly with gcc (general)
  • gcc manual entry for constraints (general)
  • The general format is, as per the refs, asm("some assembly":"output constraints"(c out args):"input constraints"(c in args):"clobbered regs");
  • 'volatile' just means that the compiler should not move the instruction around and/or delete it. This may actually be good for checking - if you tell gcc that it may not delete an instruction, but gcc doesn't know where to put it, it will complain -- and not compile.
  • If you are using C / C++ preprocessor macros in the inline assembly, you must first compile the C code down to assembly (using -S flag), then run gcc with the flag -x assembler-with-cpp As the C preprocessor macros are necessarily in headers, just include them on the command line (e.g. in the makefile) with the -include flag.

Nobody seems to have a complete modifier list for the blackfin, which is needed to actually write something that won't be optimized out :) here is my list --

  • d -- use a data register, e.g r0 - r7. don't use 'r' for this ala x86 !
  • a -- use one of the addressing registers.
  • = -- register is written (output only)
  • + -- register is both read and written (output only)

examples:

  • asm volatile("%0 = w[p5];":"=d"(flags));
    • flags should be in a data register, it is written output.
  • asm volatile("bitclr(%0, RS_WAITIRQ_BIT)":"+d"(state));
    • state must be in a data register and it is both read and written (which is true - a bit is modified, and the input state matters). Must be an output register, not an input -- you cannot use the '+' constraint with inputs.

Constraints for particular machines - does not include blackfin.

  • however, it should be in the gcc tree -- and, well, the source is online...
  • here are the comments from /gcc/config/bfin/bfin.md :
; register operands
;     d  (r0..r7)
;     a  (p0..p5,fp,sp)
;     e  (a0, a1)
;     b  (i0..i3)
;     f  (m0..m3)
;     B
;     c (i0..i3,m0..m3) CIRCREGS
;     C (CC)            CCREGS

{500}
hide / edit[4] / print
ref: notes-0 tags: global warming bayes politics plik-l biofuel oil economics date: 11-21-2007 22:20 gmt revision:4 [3] [2] [1] [0] [head]

This was written for the plik-l mailing list, Nov 16 2007


I actually had a bit of an argument yesterday with my dentist, no less, about global warming:
  • Dentist: Hello, how are you today?
  • Tim: Ok.
  • D: Are you still in school?
  • T: <defers complicated explanation for the simplified>
  • D: Oh, so do you believe in global warming?
  • T: <cites scientific study, like http://www.ipcc.ch/ipccreports/assessments-reports.htm>
  • D: Well, i don't believe in it but even if it is happening, nobody is going to stop burning gas.
  • T: Yea, but if gas and electricity were more expensive, then people would make better economic decisions, smaller cars etc.
  • D: That would just prolong the supply. Oil is a great source of energy, and we are not going to stop using it until it become economically infeasible to do it. So, why worry? Oil will be depleted and the C02 will be stuck in the atmosphere, if not by us then by some other country that needs cheap energy to grow its economy, eventually. Economics.
  • T: You seem to be hinting of China, I guess. But, if our leaders decided to let the price of oil float to where it should be, and did not fight wars over it, then there would be greater economic impetus & possibly government funding to develop alternatives to oil. This would give us some energy-independence.
  • D: We are not in iraq for the oil. That's enough now, open up!
  • T: Wait wait! But don't you know what global warming will do to the envirnoment? More storms, droughts, floods, famines, etc - all very expensive, terrible.
  • D: I do not think there is sufficient organization in the world to impose the true costs of burning oil - e.g. the cost, accumulated over the future, of present greedy practices - upon present consumers.
  • T: True, i suppose if we integrated up, the cost would be almost boundless. Hence we should stop burning oil right now!
  • D: A responsibility to the future is not in the nature of man. They eventually die, and are selfish, greedy, and lack foresight during their lives. Besides, abstaining from oil imposes a severe economic disadvantage.
  • T: But what about their - your! children? and the climate then?
  • D: They are going to be rich dentists. See, I'm charging you $50 for 15 minutes of work. It's only going to get better.
  • T: Not if the economy collapses. It seems we have based it on unsustainable growth, fueled by unreasonably cheap energy. This could happen in your lifetime, or mine - and your kids. Present luxury and high wages are based on the efficiency / cheapness of transportation of goods into the US, and the developed world's exploitation of the developing world.
  • D: No. It is based on the labor/economic efficiency of manufacturing and agriculture. Anyway, take Europe for example - the price of oil there is high, and their economy is humming along.
  • T: Yet efficient manufacturing and agriculture is somewhat dependent on cheap transportation. As for Europe, that's because they tax oil to pay for public development, among other things. And Europeans consume half the oil of their American counterparts.
  • D: A gas tax that large would never happen here. People would go nuts, such a law would never pass!
  • T: True. The political system is irrational and irresponsible, but I can't think of an alternative structure. Humans were not designed for this, such responsibility!
  • D: If you keep talking I'm going to have to charge more.
  • T: <opens mouth>

Mostly I'd have to agree with the dentist - the oil is going to be burned eventually, because it is just such a cheap source of energy. We are going to have to deal with the consequences. However, for coal - of which we have a far greater supply, and is considerably more dangerous / expensive to obtain - there is good reason to search for alternatives, and putting a tax on oil/natural gas now fund development of alternatives is probably very future-responsible, and will shift the energy climate so we relinquish coal (and maybe some oil) earlier, resulting in less CO2 in the atmosphere.

There are infinitely many things more worthy/long-range responsible than the war, but our leaders have not touched on that. Correct me if I'm wrong, but there is little evidence that they even measured the worth of all alternatives, and decided rationally, based on integrating (over time and path probability) best-of-present knowledge of benefits and consequences. Or maybe they decided rationally, but with the worth of alternatives measured *personally*. It is this that truly angers me.

Bayes for president 2008!

Comments:

{394}
hide / edit[4] / print
ref: notes-0 tags: blackfin LED kernel module linux BF537 STAMP tftp BF537 bridge date: 11-13-2007 17:59 gmt revision:4 [3] [2] [1] [0] [head]

so, you want to control the LEDs on a BF537-STAMP board? You'll need a linux box with a serial port, then will need to do a few things:

  1. get the blackfin build tools:
    1. download the RPM file from blackfin.uclinux.org and use alien (if you are on debian, like me) to install it.
    2. installation instructions
  2. get uClinux distribution and compile it. http://blackfin.uclinux.org/gf/project/uclinux-dist/frs/
    1. unpack it to a local directory
    2. 'make menuconfig'
    3. select your vendor & device
    4. make sure runtime module loading is enabled.
    5. 'make' (it takes much less time than the full linux kernel)
    6. this will result in a linux.bin image, which uBoot can use.
  3. you need to set up a tftp server for uboot, see http://linuxgazette.net/125/pramode.html
  4. attach the blackfin stamp to the serial port on your computer. configure kermit with:
    set line /dev/ttyS1
    set speed 57600
    set carrier-watch off
    set prefixing all
    set parity none
    set stop-bits 1
    set modem none
    set file type bin
    set file name lit
    set flow-control none
    set prompt "Linux Kermit> " 
    (this is assuming that your serial port is /dev/ttyS1)
  5. power on the stamp, at the uBoot prompt press space.
  6. issue the following commands:
    set serverip 192.168.1.149
    set ipaddr 192.168.1.200
    tftpboot 0x1000000  linux
    bootelf 0x1000000 
    to get the device to boot your new uClinux image from SDRAM. your IP addresses will vary.
    1. note: you can boot any ELF image at this point; for example, the 'blink' example in the blackfin tool trunk SVN, 'make' produces a ELF file, which can be loaded into SDRAM via tftp and executed. I'm not sure what part of L1 uboot uses for its instruction, but conceivably you could load into L1 / data ram and execute from there. see also {403} you would do something like:
set serverip 192.168.1.149
set ipaddr 192.168.1.200
tftpboot 0x1000000  blink
bootelf 0x1000000 
  1. at the uCLinux prompt : ifconfig eth0 192.168.1.200
  2. write a simple kernel module, for example:
    #include <linux/module.h>
    //#include <linux/config.h>
    #include <linux/init.h>
    #include <linux/fs.h>
    
    #include <asm/uaccess.h>
    #include <asm/blackfin.h>
    #include <asm/io.h>
    #include <asm/irq.h>
    #include <asm/dma.h>
    #include <asm/cacheflush.h>
    
    MODULE_LICENSE("GPL");
    
    int major;
    char *name = "led";
    int count = 0;
    
    ssize_t led_write(struct file* filp, const char *buf, size_t size, loff_t *offp)
    {
    	printk("LED write called "); 
    	if (size < 2) return -EMSGSIZE;
    	if (!buf) return -EFAULT;
    	printk("led_write called with: %s ", buf); 
    	if(buf[0] == '0') {bfin_write_PORTFIO_CLEAR(1<< 6); }
    	else{ bfin_write_PORTFIO_SET(1<<6); }
    	return size;
    }
    int led_open(struct inode *inode, struct file *file){
    	printk("led opened"); 
    	return 0; 
    }
    int led_release(struct inode *inode, struct file *file){
    	printk("led released"); 
    	return 0; 
    }
    struct file_operations fops = {
    	 .owner = THIS_MODULE,
    	.read = NULL,
    	.write = led_write,
    	.open = led_open,
    	.release = led_release
    	};
    int __init init_module(void)
    {
    	// Set PF2 as output -- clear the FER bit.
    	bfin_write_PORTF_FER(bfin_read_PORTF_FER() & (~(1 << 6))); 
    	bfin_write_PORTFIO_SET(1<< 6);
    	bfin_write_PORTFIO_DIR(bfin_read_PORTFIO_DIR() | (1<<6)); 
    	major = register_chrdev(0, name, &fops);//hope it succeeds!
    	printk("registered, major = %d ", major); 
    	printk("portF = %d", bfin_read_PORTFIO()); 
    	printk("portF_FER = %d", bfin_read_PORTF_FER()); 
    	printk("portF_DIR = %d", bfin_read_PORTFIO_DIR()); 
    	return 0;
    }
    
    void __exit cleanup_module(void)
    {
    	unregister_chrdev(major, name);
    	printk("led: cleanup "); 
    }
  3. write a makefile for this module, for example:
    obj-m:=led.o
    default:
            make -C /uClinux-dist/linux-2.6.x/ M=`pwd`
    
  4. setup apache on your computer, e.g. 'apt-get install apache2'
  5. 'ln -s' your build directory to /var/www/, so that you can wget the resulting kernel module
  6. rm led.ko
    wget http://192.168.1.149/blackfin/led.ko (for example)
    insmod led.ko
    rm /dev/led
    mknod /dev/led c 253 0
    chmod 0644 /dev/led
    echo 1 >> /dev/led 

{448}
hide / edit[1] / print
ref: notes-0 tags: iceweasel firefox acroread uninstall debian linux mozplugger date: 11-10-2007 04:39 gmt revision:1 [0] [head]

Adobe acrobat reader 7.0 leaks a prodigious amount of memory on my linux system (Debian Etch, stable). However, some pdfs will only open in acroread, so i want to keep the application around for occasional use. Because of the memory leaks, it is not good to have it loaded by default by iceweasel / firefox (evince or xpdf is better). To do this:

  1. quit your browser (not sure if this is necessary, but perhaps it is a good idea).
  2. open /etc/mozpluggerrc and comment out (#) all the sections that reference acroread. There are 3 macro lines, as well as one line in in the pdf / x-pdf content handling list.
  3. goto ~/.mozilla and remove pluginreg.dat ; do the same for ~/.mozilla/firefox
  4. go to /usr/lib/iceweasel/plugins and move / remove / rename nppdf.so (if it is there) (this is what tripped me up for a while - i had to look at the automatically-generated pluginreg.dat to figure out that acroread was being loaded without mozplugger via this plugin).

that's it! :)

{487}
hide / edit[4] / print
ref: notes-0 tags: Nordic RD nrf24l01 problem transceiver date: 11-02-2007 18:00 gmt revision:4 [3] [2] [1] [0] [head]

here is the final, concluding, email i sent to nordic semiconductor concerning my 'troubles' with their chip. I post it here in hopes that it may help somebody else out there via the magic of the internet. See {485} for the development of the mode-switch solution (2) and {484} for the dropped packet investigation.


Hi xxx,

Ok, i figured out both of my problems:

  1. The missing RX_DR IRQ was because I was clearing the RX fifo upon reading outone packet. Because a packet was being received while the SPI was reading it out (the PTX is continually transmitting), this caused the radio to drop the packet before it was completely received. Dumb! dumb!
  2. Concerning my old problem of lost packets during mode switches, I needed to do a number of things to get it to work:
    1. Add inline resistors to keep spi noise out of the radio
    2. Increase the SPI clock on both PTX and PRX, to avoid not being able to read out the packet after one IRQ and before another was received (as you suggested below).
    3. Added a 62us (of course, longer delays also work) delay between transitioning from RX mode to TX mode. During this time I do not assert CE. A delay in for the opposite transition is not needed. Not exactly sure why this is needed, but it works!
    4. On the PRX, when i send the 'acknowlegement' packet, it is necessary to only pulse CE after uploading the packet. Holding CE high until TX_DS IRQ is asserted somehow messes things up. I guess this is described on the state diagram on your spec sheet - it is best to go back into standby-I mode not standby-II, as there is no transition to RX mode from standby-II.

As a result, I'm getting 99.99 % reliability on bidirectional bandwidth of 1.39mbps PTX->PRX and 18.3kbps PRX->PTX. So, I'm a happy person :) :) Hence, I don't have to try another radio solution.

Just wanted to pass the information along in case it would help your other customers.

cheers, Tim Hanson

{485}
hide / edit[14] / print
ref: notes-0 tags: Nordic RF problem fifo transceiver date: 11-02-2007 17:59 gmt revision:14 [13] [12] [11] [10] [9] [8] [head]

Problem: switching modes on the nordic radios. see also {486}

  1. Standard scheme:
    1. headstage sends 16 data packets as per {484} by keeping the fifo continuously full, then send a status packet (as indicated by the first two bytes), then transitions to RX mode and waits for a reply.
    2. bridge listens & reads in each packet, again as {484}; when it notices that a status packet has been received, it immediately transitions to TX mode and sends out a packet. After waiting for the TX data sent IRQ, it then transitions back into RX mode.
      1. note: at present transitioning between modes flushes both RX and TX fifos.
    3. result: bridge gets 52% of all status packets sent by the headstage ;
    4. result: headstage, in return, receives replies to 47% of its status packets (that means the bridge transmission efficiency is 90.6%. This does not depend on the headstage matching the 2-byte code.
  2. If the headstage only sends one data packet prior the status packet, transmission reliability is not affected
  3. If the headstage sends no data packets hence only the status packet prior to waiting for a reply, the bridge hears exacly half of the status packets, while the headstage seems to hear every one of the bridge's replies.
    1. adding a small delay after setting TX mode marginally affects the reception ratios 51.2% headstage status packets are seen by the bridge, and ~ 90% of the bridge's replies are seen by the headstage.
  4. ok! new development: if a 62us (exactly) delay is inserted between reading out the status-ack packet on the headstage & transitioning to TX mode (e.g. BEFORE transitioning to TX mode), almost all the status packets are received (99.6%). however, if the delay is inserted AFTER transitioning to TX mode, half (exactly) of the status packets are lost. In both cases, the software on the bridge is the same. ''The delay should be essential, as it takes a bit longer for the bridge to switch back to RX mode after transmitting the packet than the headstage from RX to TX. Both transitions are synchronized by TX_DS IRQ on the bridge and RX_DR IRQ on the headstage.
    1. if, upon switching modes, we don't flush both fifos, reliability is decreased (with the 62us delay before switching modes) to 92% status packets received, 83% overall replies sseen on headstage.
    2. the same delay between RX and TX mode is not the same on the bridge -- adding it before decreases performance, adding it after transitioning & before DMA improves performance, provided the TX fifo is flushed upon transition. 100us too much.

solution

-
  1. put a 62us (minimum) delay between reading in the status ACK packet on the headstage & transitioning to TX mode, to allow the bridge to be in RX mode before we send anything. Presently, i deassert CE during the delay.
  2. only pulse CE on the bridge when sending the packet, don't hold it high until the TX_DS IRQ is asserted. This leaves it in Standby-I mode, not standby-II.
  3. flush the appropriate TX or RX fifo whenever transitioning between modes (e.g. flush the TX fifo after going to TX mode). Not sure why - perhaps it is needed when starting or recovering from lost packets - but it works! Fifos are flushed after writing the configuration register.

present performance:

  txed packets = 118513 
  rxed packets = 118218 
 (note: computer has seen 118512 packets )
 (and 118414 status packets, ratio: 0.999165 )
 (note: 'stage ratio 0.997511 )
(this includes code validation)

now, if i boost the SPI clock on the bridge up to 5 mhz (headstage clock still running at 8.25mhz) to eliminate race-case (?) & add in 16 data packets before the status packets, perfection:

 txed packets = 44151 
 rxed packets = 44151 
 (note: computer has seen 750583 packets )
 (and 44152 status packets, ratio: 1.000023 )
 (note: 'stage ratio 1.000000 )
after adding separate counters for TXed status and TXed data packets:
  txed packets = 808640 
  rxed packets = 50538 
  txed status packets = 50540 
 (note: computer has seen 808639 packets, ratio : 0.999999 )
 (and 50540 status packets, ratio: 1.000000 )
 (note: 'stage ratio 0.999960 )
yay!! almost no dropped packets!!

This equates to :

  • a net incoming (to headstage) bandwidth of 32 * 8 / 3.48ms = 73.5 kbps. This seems like more than plenty - how much do we have to say to the bugger? 1/4 this bandwidth is probably sufficient = 18.375 kbps, or one 32 byte packet every ~ 11.2ms.
  • a net outgoing (from headstage) bandwidth of 32*16*8 bits / 3.48ms = 1.17 mbps
    • this can be tuned further by making the status packet transmission less frequent than once every 16 data packets.
    • 16 packets, with 3 byte address & 2 byte CRC, takes 2.72ms to transmit (CE enable to CE disable); hence, we should be able to transmit 23 packets within the 4ms time that the PLL is synched. ah, but 16 is such a nice number... and it is better not to get too close to device limits.
    • The maximum, excluding PLL resynchs, 1.6mbps (takes 160us to transmit a packet with 2 byte CRC, 5 byte address, and 32 data bytes).
    • The maximum, including pll resynchs every 4ms or less, is about 1.5mbps;
  • With status packet every 4th 16-packet block, we got an observed rate of 1.39mbps (empirical, based on computer's clock, including header, 5431.5 packets/sec) and an incoming bandwidth of about 18.3kbps (as above). This is enough to support 170 spikes/sec (28 sample waveform + header) on each of 32 channels!! :)
  • This is summarized in {487}

{486}
hide / edit[3] / print
ref: notes-0 tags: Nordic problem fifo transceiver email date: 11-02-2007 17:58 gmt revision:3 [2] [1] [0] [head]

here is an email I wrote to nordic semiconductor technical support concerning switching reception/transmission modes. see also {487} & {485}


Hello,

I've been having problems with switching modes on the nRF24L01. I want to implement a asymmetric bidirectional link, where there is a periodic (every ~36ms) time when the primary transmitter sends a status packet, then listens for a 32-byte command packet from the primary receiver. The command packet is for conveying configuration information, etc. I am driving both radios with blackfin DSPs using the built-in SPI port @ 4mhz, and am very careful with the CSN signal. The shock-burst feature is not enabled.

Unidirectional transfer works great - I get nearly 0% dropped packets when the primary transmitter & receiver never change modes, up to a rate of about 1.5mbps. Of course, I am careful not to let the radio stay in TX mode for more than 4 ms - every 3ms i give it a 'break' by de-asserting CE.

But bidirectional does not work reliably. Here is my procedure, on the primary transmitter side, for sending a status packet then changing from TX to RX & back to TX, with the initial condition that CE is asserted:

  1. wait until the TX fifo is empty by polling the FIFO_STATUS register through spi
  2. clear TX_DS interrupt in status register
  3. send packet with code 0xa0
  4. wait for TX_DS interrupt on IRQ
  5. deassert CE
  6. flush the RX fifo code 0xe2 (not sure if this is needed, but somehow, it improves reliability).
  7. write the config register with the following bits set: MASK_TX_DS | MASK_MAX_RT | EN_CRC | CRC0 | PWR_UP | PRIM_RX
  8. clear interrupts by writing 0x70 to register 0x07
  9. assert CE
  10. wait for RX_DR iterrupt on IRQ (e.g. wait for a packet from the primary receiver - the reciever has to both read in the status packet and send out command packet through SPI, hence must wait for 544us )
  11. clear interrupts again
  12. read in packet w / 0x61 command
  13. deassert CE
  14. write the config register with the following bits set: MASK_TX_DS | MASK_MAX_RT | EN_CRC | CRC0 | PWR_UP
  15. clear interrupts by writing 0x70 to register 0x07
  16. assert CE

The process on the primary receiver is basically the same, but inverted. Upon receiving a packet of the correct type, it switches to transmit mode, sends off a packet, waits for the TX_DS interrupt, and switches back to RX mode.

Like I said, when the transmitter and receiver never switch modes, the packets always get through without any corruption. When they switch roles for one packet, only ~ 78% get through, making the status packet -> command packet reply about 62% reliable. This is when the radio is only sending status packets - hence mostly it is in what the datasheet calls 'standby-II mode'. When the radio is also transmitting data packets, the status packet -> command packet relay is about 79% reliable, suggesting that the first packet after a switch from RX to TX mode is somehow being lost. Indeed, when I look at the IRQ signals on an oscilloscope, it is apparent that a certain percentage of the time the TX_DS interrupt is not followed by a RX_DR interrupt.

so - what am I doing wrong??!! I'm desperate to make this work, and have tried almost every permutation!

thanks, Tim Hanson

{484}
hide / edit[16] / print
ref: notes-0 tags: nordic RF problem fifo date: 11-01-2007 18:03 gmt revision:16 [15] [14] [13] [12] [11] [10] [head]

experimential results with the Nordic nRF24l01 (recall, as per {477}, that all SPI signals have an in-line 100 ohm resistor on both the headstage and bridge)

  1. If the bridge is a transmitter & the headstage is a receiver, we let the DMA finish before asserting CE, we continuously pool the SPI bus on the headstage, and read the packet entirely in, then almost all packets get through (by my rough oscilloscope measuring). This requires 420us per packet, 290 to actually transmit the packet and 130 for SPI maneuvers.
    1. If this direction is reversed (normal: headstage is the transmitter & bridge is the receiver), the packet reliability is increased. The headstage takes 350us to transmit one packet -- 60us for SPI transation ( can run at a higher speed, as it the bus traces on that board are smaller). However, the reliability of the link in both regimes > 95%.
  2. If the fifo is filled (3 packets) on the headstage side, then CE is pulsed, only the first and third packet get through, with 320 us between each packet. again, SPI bus is polled on the bridge (receiver) side. Reception of the first packet is reliable, reception of the third is not so much. Clearing the RX fifo increases reliability of receiving the third packet.
    1. This is not affected by disabling 2-byte CRC.
    2. This is not affected by doing non-dma SPI transfers.
    3. If i press my finger on the crystal oscillator next to the nRF24l01 (presumably thereby affecting tuning, sometimes only the second packet is received , but still never all 3.
  3. Now, if we offer the same regime & listen for the IRQ pin to go low, then clear the status, the bridge receives all 3 packets, but not always - it only gets every other group of 3 packets.
    1. This is not affected by disabling CRC, nor does it seem to be affected by channel selection.
    2. This is dependent on clearing the RX fifo after reception -- of course, clearing the RX fifo while a packet is in the air will cause that packet to be rejected
  4. If the fifo is not filled (2 packets) on the headstage (= transmitter), then CE is pulsed, the first packet gets through, and the second one does, too (sometimes)
    1. This is not affected by disabling CRC nor by changing the radio channel.
  5. If the fifo is not filled (2 packets) on the bridge (= transmitter), then CE is pulsed, only the first packet gets through
  6. if we reverse the order - have the bridge send 3 packets over SPI then assert CE, and set the headstage to listen & immediately clear the IRQ on interception, the first packet is most always received, the third packet is usually received, but the second packet is never received.
    1. if we do the same as above, and read the entire packet over SPI & use polling to see when another packet is received, then once again both the first and second packets are received properly. The polling implies that noise from the SPI bus is not corrupting packet reception.
  7. Again, if we do pipelined transmission from headstage to bridge by keeping the fifo consistently full, then every other packet is dropped -- see {477}
I wish i had pictures for this.. wish i had a webcam!

finally, it is solved!

how:
  1. don't clear the IRQ status multiple times
  2. don't poll the bus to see if there is a packet - wait for the IRQ pin, then read the packet in.
  3. don't clear the TX fifo or RX fifo, except in time of error or when starting up.
  4. keepin the fifo one-full works with a headstage (= transmitter) SPI clock of 8.25mhz. at this rate, can upload 2 packets before 1 is transmitted.

{477}
hide / edit[5] / print
ref: notes-0 tags: nordic fifo problem radio tranciever date: 11-01-2007 05:50 gmt revision:5 [4] [3] [2] [1] [0] [head]

I've been having problems transmitting packets in a pipelined fashion using the nordic nRF24L01 tranciever IC. Namely, I cannot send multiple packets at once by keeping the on-chip 3-packet fifo full (note packets are 32 bytes data, max; with header/CRC, they are close to 40 bytes). If this fifo is full, the radio should remain in transmit mode - see {470}, and also {484}

Above, what happens when I let the fifo go dry / empty, and force the PLL to resync for each transmitted packet, as per the following sequence:

  1. write a packet via SPI
  2. assert CE
  3. wait for the TX data sent IRQ to be asserted (0). This requires pll resync (130 us) and packet transmission (160us @ 2mbps)
  4. clear IRQ via SPI
  5. deassert CE
  6. if packet # < 16, go back to step 1.
The bottom trace is the receiver's IRQ line, which is 0 when data is received. I send them in groups of 16 so as to be as idential as possible to below, where it is necessary to get the radio out of TX mode to re-synch the pll. (however, it is possible to send indefinitely in this way..) On the receiver side, packets are either read in using DMA, or the RX fifo is cleared using the associated SPI command - either one works fine.

Note just about all packets are received properly and that the RX irq closely follows the TX irq.

Above, what happens when i try to pipeline transmission, e.g.

  1. upload a packet via SPI
  2. assert CE, force PLL to re-sync
  3. upload another packet
  4. wait for the data sent IRQ from the preceding packet & clear IRQ using SPI
  5. if packet number < 16, go back to step 3
  6. otherwise, wait for the final packet IRQ & clear using SPI
  7. de-assert CE
  8. wait 1ms or so.
The sequence should force the radio to stay in transmit mode for 16 sequential packets, and indeed the transmitter's IRQ line reflects this. However, only half of the (seemingly) transmitted packets are received, as indicated by the receiver's IRQ line, the bottom trace. What? I've been careful not to exceed the 4ms pll resync timeout. Also, the order of received packets sometimes changes - usually it gets the first packet in a group, but sometimes it does not (left segment of bottom trace).

One initial theory was that noise on the SPI bus was corrupting the packets. However:

  • If it was noise on the transmitter's bus, then every packet would be corrupted, as there is transmitter SPI activity (e.g. packet upload) during radio transmission of all but the last packet in a group.
  • If it was noise on the receiver, then continually polling the 'status' (0x07) and 'fifostatus' (0x17) registers would cause more packets to be dropped. However, i can poll using SPI with the transmission scheme in the first figure (wait for packet to be on the air before sending another), and will not get any more dropped packets than usual.
  • I tried adding 100 ohm resistors to all SPI signals on both the transmitter and receiver, but this did not affect the problem.
This is somewhat of a show-stopper for me...
  • If it takes 330us (130us pll sync, 160 to transnmit, 40us for SPI delays) to send 32 bytes, then the aggregate rate is only 775kbps, or 38% utilization of the 2mpbs radio, equivalent to a max 108 wf/sec/32 channels.
  • If i can use the fifos and pipeline the transmission, can get > 1.08 mbps, or 54% utilization, or 150wf/sec/32channels.
The latter is much more acceptable, as neurons can have firing rates > 100hz but not usually > 150hz.

{464}
hide / edit[2] / print
ref: notes-0 tags: Blackfin perl loopcounters registers ABI application-binary interface gcc assembly date: 10-19-2007 17:24 gmt revision:2 [1] [0] [head]

The problem: I have an interrupt status routine (ISR) which can interrupt the main, radio-servicing routine at any time. To keep the ISR from corrupting the register values of the main routine while it works, these registers must be pushed, and later popped, to the stack. Now, doing this takes time, so I'd prefer to pop / push as few registers as possible. Namely, I don't want to push/pop the hardware loop registers - LC0 (loop counter 0), LB0 (loop bottom 0, where the hardware loop starts) & LT0 (loop top 0, where the hardware loop ends).

Gcc seems to only touch bank 1, never bank 0, so I don't have to save the 3 regs above. However, to make sure, I've written a perl file to examine the assembled code:

my $file = "decompile.asm"; 
open(FH, $file); 
@j = <FH>; 
my $i=0; 
my @badregs = ("LC0", "LB0", "LT0"); 
foreach $reg (@badregs){
	foreach $k (@j){
		if($k =~ /$reg/){
			$i++;
			print "touch register $reg : $k";
		}
	}
}
#tell make if we found problems or not.
if($i>0){
	exit 1;
}else{
	exit 0;
}

'make' looks at the return value perl outputs, as instructed via the makefile (relevant portion below):

headstage.ldr:headstage.dxe
	rm -f *.ldr
	$(LDR) -T BF532 -c headstage.ldr $<
	bfin-elf-objdump -d headstage.dxe > decompile.asm
	perl register_check.pl

if it finds assembly which accesses the 'bad' registers, make fails.

{468}
hide / edit[6] / print
ref: notes-0 tags: perl SVN version insert date: 10-19-2007 16:20 gmt revision:6 [5] [4] [3] [2] [1] [0] [head]

On the 'headstage' I'm developing, there is a feild in the status packet for version number, so i wanted to automatically include the SVN version into this field by updating the source code. Rather than fiddling around with the SVN settings, I used perl (as always).

# script to insert the SVN version.. 
$verstr = `svn info`; 
if($verstr =~ /Revision: (\d+)/ ){
	$version = $1; 
	# print "svn version: $version \n"; 
	open(FH, "main.c"); 
	open(FHnew, ">main.c.new"); #open in write-over mode.
	@j = <FH>; 
	foreach $line (@j){
		$line =~ s/(SVN_VERSION\{\*\/)([^\/]*)(\/\*\})/$1$version$3/; 
		print FHnew $line; 
	}
	close FH; 
	close FHnew;
	`mv main.c.new main.c`;
}
lovely regex, no? it replaces:
 	stat->version = /*SVN_VERSION{*//*}*/; 
with
 	stat->version = /*SVN_VERSION{*/59/*}*/; 
(for example) in the file main.c (obviously)
Mr tlh24,

I suggest the following:

Add the string "$Rev$" to your main.c

$ svn ps svn:keywords "Rev" main.c
$ svn ci -m "adding Rev keyword" main.c

Now, eg:

stat->verstr = "$Rev$";
becomes
stat->verstr = "$Rev: 59$";

cheers, /joeyo


Mr. joeyo:

ahhh, that's sweet! problem is: i need it formatted as an integer. stat->version is type 'unsigned int'. any ideas?

{363}
hide / edit[8] / print
ref: notes-0 tags: perl wget hardmath date: 10-16-2007 17:43 gmt revision:8 [7] [6] [5] [4] [3] [2] [head]

so, I made a script for Jesse K to download multiple files from hardm.ath.cx. eventually I'll have to improve this - automake directories, etc. whatever, it works!

#!/usr/bin/perl
$narg = $#ARGV + 1; 
if( $narg ne 1 ){
	print "please specify the URL on the command line \n"; 
}else{
	$source = $ARGV[0]; 
	$command = "curl " . $source; 
	print $command . "\n"; 
	$page = `$command`; 
	print $page; 
	while( $page =~ /<a href=([^>]+)>/gs ){
		print "found link: " . $1 . "\n"; 
		$link = $1; 
		if( $link =~ /.mp3/ ){
			$command = "wget " . $source . $link; 
			print $command . "\n"; 
			`$command`; 
		}
	}
}

(as for all the different versions of this file, I used the entry to test & fix embedding \n and \t in the document & escaping them whem passing to mysql. current strategy is to convert the chars to HTML encodings - e.g. \ -> \ )

{466}
hide / edit[4] / print
ref: notes-0 tags: Duke Licensing patents university royalty royalties intellectualproperty date: 10-12-2007 17:41 gmt revision:4 [3] [2] [1] [0] [head]

What I have learned about licensing & Duke (or really, licensing at universities in general), in no particular order:

  • Licensing fees split up: 50% to the inventors, 10% to the lab, 10% to the department, 30% to the dean
    • The 50% inventors' fees are split up based on what is determined fair by the inventors themselves, or if that fails, by the Office of Licensing & Ventures (OLV) itself. If there are several patents in a licensing, then it is split between patents based on relevance / contribution, then between each of the inventors. Royalties are split in the same way.
    • The OLV & patent's budget is indirectly paid through these licensing fees.
  • Universities are granted ownership of any intellectual property developed by graduate students & other employees under federal funding through the 1980/1984 Bayh-Dole Act. Universities assume ownership of IP developed through privately funded work, though there is no one law for this.
    • Graduate students are considered employees under the law, hence IP retained, even if no formal contract was signed.
  • Even if an independent inventor (e.g. me) files a invention disclosure form to Duke in good faith, and upon investigation the OLV agrees that the claim of independence is supported, this does not prevent future litigation.
    • If the fields of invention and research overlap, as is probably true for me, then OLV & Duke are likely to protest (money is at stake, after all).
  • Patents require a servicing fee every 3-5 years - have to learn more about this!
  • Almost certainly want a patent on a device. without it, it is very easy to steal :/
    • Can patent software 'ideas' or 'methods' that have utility, but not the actual software. The text of the software is copyrighted, like a book.
  • If a patent has people on it who were not involved in the invention, the patent can be legally contested and voided. Conversely, if the patent does not have all the inventors on it, then it can also be contested by an outside party, and voided.
  • Duke will pay the legal fees for patents & writing up a licensing contract
    • Duke will also pay the fees to patent in other countries (where the patenting fees are much higher), depending on market.
      • The European Union has no centralized patent office - patents must be filed in each country and translated to & from the official language. The legal and translation fees & time spent on this can be very high, so usually companies only file in a few largest markets, if at all.
    • Concerning the named inventors on a patent, above, Duke determines who is involved usually by asking the PI, without delving into the internal politics of a lab. This may or may not be an issue.
  • Typical licensing fees $25k - $1M, depending on what is being patented.
  • Duke can revoke the licensing agreement if the company is not using it / making progress within a period specified by the licensing contract, e.g. 6 - 9 months.
  • Duke typically licenses multiple patents at a time to startups; startups typically need more than one patent.
  • Duke typically pursues non-exclusive licenses on biological models (e.g. Gouping Feng's OCD mouse), and exclusive licenses on devices (like this, i suppose)
    • In some fields, device licensing is exclusive to a field - e.g. one company licenses for Parkinson's application, another for Alzheimer's, etc.
  • Once a patent is licensed to a company, it typically becomes gradually 'diluted' as the company & employees invests more in the idea/technology. If the initial royalty level was 5%, and the company makes significant changes & improvements, then the company will re-negotiate the royalty percentage.
    • Oftent the licensing agreement specifies the maximum amount of dilution / the minimum royalty level, as ultimately the university was involved in the first step to commercialization, without which anything else could have happened.
  • Similarly, if the company licensing University IP needs to give a certain royalty percentage to another patent holder & cannot remain solvent without decreasing University share, then the company and University will negotiate a lower royalty rate.

conclusions:

  • Everything is fluid & up for negotiation, depending on the desires and situations of each of the parties.
    • Typically, the university and inventor are on the same side, but that is not true for me.
  • Need a lawyer to navigate the maze!

{465}
hide / edit[1] / print
ref: notes-0 tags: CRC32 ethernet blackfin date: 10-10-2007 03:57 gmt revision:1 [0] [head]

good explanation of 32-bit CRC (from the blackfin BF537 hardware ref):

{444}
hide / edit[5] / print
ref: notes-0 tags: nordic pinout nRF24L01 spark fun electronics date: 10-09-2007 19:59 gmt revision:5 [4] [3] [2] [1] [0] [head]

nordic semi links:

here is the connection list for the nRF24L01 module made by sparkfunelectronics
  1. VCC
  2. CE
  3. CSN
  4. SCK
  5. MOSI
  6. MISO
  7. IRQ
  8. GND
(1 is by the voltage regulator, obviously.) reversed:
  1. GND
  2. IRQ
  3. MISO
  4. MOSI
  5. SCK
  6. CSN
  7. CE
  8. VCC

{457}
hide / edit[1] / print
ref: notes-0 tags: NewYorker healthcare Clinton date: 10-08-2007 02:34 gmt revision:1 [0] [head]

be forewarned : this is poorly organized!

From the New Yorker, October 1 2007:

"We've been here before, but this time the stars are really coming into alignment. Our health-care system has continued to deteriorate. We spend twice as much as the French and the Germans and two and a half times as much as the Brits, yet we dies sooner and our babies die in greater numbers. Thirty-eight million americans were uninsured in 200; now it's 47M. Employer-bnased health insurance is increasingly expensive, stingy, and iffy. Companies, especially manufacturing companies, are beginning to realize that being deputized to pay the health-care costs of their employees and retirees puts them at a competitive disadvantage in the global economy. "

Therefore, then there will be two segments of the population supportive of centralized / federalized health care: the workers (myself one, i have to pay for health insurance myself; its (BCBSNC) costs ~$160/month and I can't be certian of it's quality or coverage just yet), and the employers. The employers have seen an increase of 63% for single coverage and 58% for family coverage since 2001.[1] Who else is there? oh, yea, the healthcare industry ( $224 billion in biotech 2000, $184B spent on pharmaceuticals 2003, $606B by private health insurance, which made $209B in profits) also, how are we going to fund this? Medicare has $30 Trillion in unfunded liability, which is three times that of the US mortgage debt.

Ultimately, i think the problem is that the government and private insurance do not want to pay for the uninsured, but when such a situation occurs, they are morrally obliged to do so, and hence much somehow subsidize / hide the costs of this. It is argued that if everyone was provided with basic healthcare through the government, then the difficulty and inefficiency of hiding the cost would be avoided.

  • Medicare finances health care for ~40 Million Americans, accounting for 1/8 of all federal expenditures. Unless our health care system becomes more efficient, it will take more than all of the federal budget to cover our entire population - and this does not consider the aging baby-boomer generation. Furthermore, Medicad / Medicare, which spends about 2% of it's budget on administration, is generally more efficient than private health insurance, which spends more than 15% on the same (those figures from the New Yorker; [1] lists it closer to 26%, but this icludes malpractice insurance)
  • The US healthcare industry subsidizes the development of drugs for a large part of the rest of the world, where government price controls limit / eliminate compensation the cost of pharmaceutical R&D.
  • and what are you going to do with all the employees of present healthcare insurance corporations?
  • federalized health insurance would decrease the malpractice liability, as (hopefully) juries would realize that the money for settlements is, in effect, coming out of their own collective pocket, and will not be there to do more worthwile things.
http://www.ndu.edu/ICAF/Industry/reports/2005/pdf/2005_HCIS.pdf -- really excellent resource!

{458}
hide / edit[2] / print
ref: notes-0 tags: Phelps economist nobel date: 10-06-2007 22:55 gmt revision:2 [1] [0] [head]

  • nobel prize-winning economist
  • http://economistsview.typepad.com/economistsview/2006/10/phelps_dynamic_.html
    • one of my intense dislikes of capitalism is the vast duplication of information and effort; many corporations have to do, basically, the exact same thing, many times over. this is also why i like open-source software (besides the fact that i can use it to do things!)
    • Phelps says: "Not having to fear fluid market conditions, an entrenched company could afford to develop radical innovation. " yes, but will they want to ?
    • he also points out, correctly, that pluralism, means that there are many different ideas and many different ways to finance them, leading to greater 'dynamism'.
    • he also (seems to) misrepresents the efficiency of american and continental workers - French workers outproduce American workers on an hourly basis
    • the comments are really good on this page:

Its also very difficult to compare western euro productivty to US productivity due to healthcare costs. The US system employs a payroll deduction to lessen the input of the employer and reduce ECI while the european system does not. Further, this underweights those costs in CPI. Statisticians in europe catch that difference while the BLS does not.

One could point out, for example, that Europeans enjoy more leisure time, better health, less poverty, less inequality and thus more economic security, greater intergenerational economic mobility, better access to high-quality social services like health care and education, and manage to do it all in a far more environmentally sustainable way (Europe generates about half the CO2 emissions for the same level of GDP) compared to the US. I bet these facts don't show up in McKinsey's business productivity study.

Then there are the aspects of the American model that may be impossible and unwise for Europeans to copy, but boost US productivity statistics nonetheless: Much of the surprising acceleration of U. S. productivity growth since 1995 originates in the trade sector, particularly retail trade . . . perhaps the most important factor of production in making this format possible is a large plot of virgin land which is much more widely available in the sprawling American metropolitan areas . . . The American explosion of productivity growth in retailing calls attention to basic life-style choices that constitute yet another form of ʺAmerican Exceptionalism.ʺ While the American form of metropolitan organization may promote productivity growth, Europeans are rightly skeptical of unmeasured costs of low urban density in America as promoted by explicit government policies. Europeans decry side-effects of the American system that may promote productivity without creating consumer welfare, including excess energy use, pollution, and time spent in traffic congestion. Tom Geraghty.


  • we are financing some of our growth with the consumption of a huge national resource: our land, our environment.

{450}
hide / edit[0] / print
ref: notes-0 tags: leadership dilbert redirection politics trolls date: 09-28-2007 18:11 gmt revision:0 [head]

a very nice synopsis of how leadership works:

{449}
hide / edit[1] / print
ref: notes-0 tags: wheelshoe sideskate patent date: 09-26-2007 17:51 gmt revision:1 [0] [head]

Here are a few figures I screengrabbed during my prior art search for the sideskate patent. The first one is kinda silly, but, well, demonstrative of a nice curb-grind. In general, I think it is really useful to be able to jump off & wear regular shoes, as in sideskates or freeline, hence these have limited appeal. The primary advantage with seperate wheeled devices is that the device manufacturer does not have to make special shoes nor collaborate with a shoe manufacturer - users can wear whatever shoes fit them best. That said, heeling shoes have become rather popular, and those require custom soles -- why have they not rotated the wheel and moved it to the instep/arch, then?

{447}
hide / edit[2] / print
ref: notes-0 tags: blackfin interrupts install date: 09-20-2007 16:49 gmt revision:2 [1] [0] [head]

things required to enable interrupts on a blackfin processor, not necessarily in order though all are required (also see the list, in the programming ref, on page 4-31):

  1. set the ISR address in the EVTx (event vector) registers. (page 4-42 in the processor programming reference)
  2. set the system interrupt controller interrupt mask (SIC_IMASK) for the events you want to accept. for the blackfin BF537, see 4-20 in the hardware reference.
  3. set the interrupt priority with the IARx registers. This is also hardware-dependent, see page 4-18 in the BF537 hardware ref. BF537 has 4 of these registers, each 32 bits.
    1. remember to put the priority minus 7 in the individual nibbles of the IAR registers - hence '3' maps to IVG10
  4. set IMASK bits appropriately -- this is not the same as the SIC_IMASK register. See page 4-39 in the programming reference.
  5. if you want to allow nested interrupts, save reti, asat, and the fp (in addition to any registers clobbered) into the stack. If not, issue a cli and an sti before concluding the in the interrupt servicing routine.
  6. close your interrupt routines with a rti instruction.

{439}
hide / edit[2] / print
ref: notes-0 tags: old blackfin code assembly date: 09-11-2007 15:52 gmt revision:2 [1] [0] [head]

abandoned because I realized that I could work on 2 channels at once (as there are 2 MACs onboard) & could use the s2rnd multiply-accumulate flay & could load registers 32bits at a time! ah well, might as well archive my efforts :)

	r6.h = 2048; 
	r0.l = r0.l - r6.h (s) || r1.l = w[i0++] || r2.l = w[i1++]; //subtract offset, load a1[0] into r1.l, w1[0] into r2.l
	a0 = r0.l * r1.l (is) || r1.h = w[i0++];  //mac in*a1[0], load a[1] to r1.h
	a0 += r2.l * r1.h (is) || r1.l = w[i0++]|| r2.h = w[i1--]; //mac w[0]*a1[1], load a1[2] into r1.l, w1[1] to r2.h
	r4 = (a0 += r2.h * r1.l) (is) || r3.l = w[i0++]; //mac w1[1]*a1[2] store to r4, b1[0] to r3.l
	r4 = r4 >>> 14 || r3.h = w[i0++]; //arithmetic right shift, 32 bit inst, b1[1] to r3.h, r4 is new w1. 
	a0 = r4.l * r3.l (is) || w[i1++] = r4.l; //mac w1*b1[0], save w1 into w1[0]
	a0 += r2.l * r3.h (is) || w[i1++] = r2.l; //mac w1[0]*b[1], save w1[0] into w1[1]
	r4 = (a0 += r2.h * r3.l) (is) || r1.l = w[i0++] || r2.l = w[i1++];//mac w1[1]*b1[0] store r4, a2[0] to r1.l, w2[0] to r2.l
	r4 = r4 >>> 14 || r1.h = w[i0++] || r2.h = w[i1--]; //arith. right shift, a2[1] to r1.h, w2[1] to r2.h 
	a0 = r4.l * r1.l (is);  //mac in*a2[0],  a2[2] into r1.l
	a0 += r2.l * r1.h (is) ||  rl.l = w[i0++]; //mac w2[0]*a2[1], b2[0] into r3.l
	r4 = (a0 += r2.h * r1.l) (is) || r3.l = w[i0++]; //mac w2[1]*a2[2] store r4, b2[1] into r3.h
	r4 = r4 >>> 14 || r3.h = w[i0++]; //arithmetic shift to get w2, b2[2] to r3.h
	a0 = r4.l * r3.l (is) || w[i1++] = r4.l; //mac w2 * b2[0], store w2 to w2[0]
	a0 += r2.l * r3.h (is) || w[i1++] = r2.l; //mac w2[0]*b2[1], store w2[0] to w2[1]. i1 now pointing to secondary channel. 
	r4 = (a0 += r2.h * r3.l) (is) || i0 -= 10; //mac w2[1]*b2[0].  reset coeff ptr. done with pri chan, save in r5.
	r5 = r4 >>> 14; 
	//time for the secondary channel!
	r0.h = r0.h - r6.h (s) || r1.l = w[i0++] || r2.l = w[i1++]; //subtract offset, load a1[0] to r1.1, w1[0] to r2.l
	a0 = r0.h * r1.l (is) || r1.h = w[i0++] ; //mac in*a1[0], a1[1] to r1.h, save out samp pri.
	a0 += r2.l * r1.h (is) || r1.l = w[r0++] || r2.h = w[i1--]; //mac w1[0]*a1[1], a1[2] to r1.l, w1[1] to r2.h
	r4 = (a0 += r2.h * r1.l) (is) || r3.l = w[i0++]; //mac, b1[0] to r3.l
	r4 = r4 >>> 14 || r3.h = w[i0++]; //arithmetic shift, b1[1] to r3.h
	a0 = r4.l * r3.l (is) || w[i1++] = r4.l; //mac w1*b1[0], save w1 to w1[0]
	a0 += r2.l * r3.h (is) || w[i++] = r2.l; //mac w1[0], save w1[0] to w1[1]
	r4 = (a0 += r2.h * r3.l) (is) || r1.l = w[i0++] || r2.l = w[i1++]; //mac w1[1]*b1[0] store r4, a2[0] to r1.l, w2[0] to r2.l
	r4 = r4 >>> 14 || r2.h = w[i1--]; // r4 output of 1st biquad, w2[1] to r2.h
	a0 = r4.l * r1.l (is) || r1.h = w[i0++] ; //mac in* a2[0], a2[1] to r1.h
	a0 += r2.l * r1.h (is) || r1.h = w[i0++] ;  //mac w2[0]*a2[1], a2[2] to r1.l
	r4 = (a0 += r2.h * r1.l) (is) || r3.l = w[i0++]; //mac w2[1]*a2[2], b2[0] to r3.l
	r4 = r4 >>> 14 || r3.h = w[i0++]; //r4 is w2, b2[2] to r3.h
	a0 = r4.l * r3.l (is) || w[i++] = r4.l ; //mac w2 * b2[0], store w2 to w2[0]
	a0 += r2.l * r3.h (is) || w[i++] = r2.l; //mac w2[0] * b2[1], store w2[0] to w2[1].  i1 now pointing to next channel. 
	r4 = (a0 += r2.h * r3.l) (is) || i0 -= 10; //mac w2[1] * b2[0], reset coeff. ptr, save in r4. 
	r4 = r4 >>> 14; 

here is a second (but still not final) attempt, once i realized that it is possible to issue 2 MACS per cycle

// I'm really happy with this - every cycle is doing two MMACs. :)
	/*
	//															i0	i1 (in 16 bit words)
	r1 = [i0++] || r4 = [i1++]; 						//	2	2 	r1= a0 a1 r4= w0's
	a0 = r0.l * r1.l, a1 = r0.h * r1.l || r2 = [i0++] || r5 = [i1]; 			//	4	2	r2= a2 a2 r5= w1's
	a0 += r4.l * r1.h, a1 = r4.h * r1.h  || r3 = [i0++] || [i1--] = r4; 		//	6	0	r3= b0 b1 w1's=r4
	r0.l = (a0 += r5.l * r2.l), r0.h = (a1 += r5.h * r2.l)(s2rnd); 
	a0 = r0.l * r3.l, a1 = r0.h * r3.l || [i1++] = r0; 					//	6	2	w0's = r0
	a0 += r4.l * r3.h, a1 += r4.h * r3.h || r1 = [i0++] || i1 += 4; 		//	8	4 	r1 = a0 a1 
	//load next a[0] a[1] to r1; move to next 2nd biquad w's; don't reset the coef pointer - move on to the next biquad. 
	r0.l = (a0 += r5.l * r3.l), r0.h = (a1 += r5.h * r3.l)(s2rnd) || r4 = [i1++]; //	8	6	r4 = w0's, next biquad
	//note: the s2rnd flag post-multiplies accumulator contents by 2.  see pg 581 or 15-69
	
	//second biquad. 
	a0 = r0.l * r1.l, a1 = r0.h * r1.l || r2 = [i0++] || r5 = [i1];			//	10	6	r2= a2 a2 r5 = w1's
	a0 += r4.l * r1.h, a1 += r4.h * r1.h || r3 = [i0++] || [i1--] = r4; 		//	12	4	r3= b0 b1 w1's = r4
	r0.l = (a0 += r5.l * r2.l), r0.h = (a1 += r5.h * r2.l)(s2rnd); 			//
	a0 = r0.l * r3.l, a1 = r0.h * r3.l || [i1++] = r0; 					//	12	6	w0's = r0
	a0 += r4.l * r3.h, a1 += r4.h * r3.h || r1 = [i0++] || i1 += 4; 		//	14	8	r1 = a0 a1
	r0.l = (a0 += r5.l * r3.l), r0.h = (a1 += r5.h * r3.l)(s2rnd) || r4 = [i1++]; //	14	10	r4 = w0's
	
	//third biquad. 
	a0 = r0.l * r1.l, a1 = r0.h * r1.l || r2 = [i0++] || r5 = [i1];			//	16	10	r2= a2 a2 r5 = w1's
	a0 += r4.l * r1.h, a1 += r4.h * r1.h || r3 = [i0++] || [i1--] = r4; 		//	18	8	r3= b0 b1 w1's = r4
	r0.l = (a0 += r5.l * r2.l), r0.h = (a1 += r5.h * r2.l)(s2rnd); 			//
	a0 = r0.l * r3.l, a1 = r0.h * r3.l || [i1++] = r0; 					//	18	10	w0's = r0
	a0 += r4.l * r3.h, a1 += r4.h * r3.h || r1 = [i0++] || i1 += 4; 		//	20	12	r1 = a0 a1
	r0.l = (a0 += r5.l * r3.l), r0.h = (a1 += r5.h * r3.l)(s2rnd) || r4 = [i1++]; //	20	14	r4 = w0's
	
	//fourth biquad. 
	a0 = r0.l * r1.l, a1 = r0.h * r1.l || r2 = [i0++] || r5 = [i1];			//	22	14
	a0 += r4.l * r1.h, a1 += r4.h * r1.h || r3 = [i0++] || [i1--] = r4; 		//	24	12
	r0.l = (a0 += r5.l * r2.l), r0.h = (a1 += r5.h * r2.l)(s2rnd); 
	a0 = r0.l * r3.l, a1 = r0.h * r3.l || [i1++] = r0; 					//	24	14
	a0 += r4.l * r3.h, a1 += r4.h * r3.h || i1 += 4; 					//	24	16
	r0.l = (a0 += r5.l * r3.l), r0.h = (a1 += r5.h * r3.l)(s2rnd); 			// 48: loop back; 32 bytes: move to next channel.

{443}
hide / edit[1] / print
ref: notes-0 tags: party 1107 sarcasm date: 09-05-2007 02:56 gmt revision:1 [0] [head]

Here's the deal: myself, Jan & the rest of the double-one aught seven crew will be hosting a club swimming barbecue ~6 this friday. Since we'll only be warming up by the end of the club swimming bbq, and probably people will not want to leave anyway, this event is to extend the festivities indefinitely. We feel that this is essential, as recent news - for example the delicious (and completely unanticipated) subprime mortgage fun, the even more delicious lead paint that China has been supplying for augmenting our children's collective intelligence, and the incredibly momentous expenditure of more than $450 trillion on the Iraq war - are due cause for a little bit of indulgence and celebration!

So come party like Bernanke, and drop cash out of helicopters!

(Since we are all going to be generous and drop cash like we're the fed, 1107 would greatly appreciate it if you could direct a bit of that generosity on food / beer etc for the party. (so as to keep us all fed.) thanks :)

{441}
hide / edit[0] / print
ref: notes-0 tags: DSP filter quantize lowpass elliptic matlab date: 09-02-2007 15:20 gmt revision:0 [head]

So, in order to measure how quantizing filter coeficients affects filter response, I quantized the coefficients of a 8th order bandpass filter designed with:

[B1, A1] = ellip(4,0.8,70, [600/31.25e3 6/31.25]);
here is a function that quantizes & un-quantizes the filter coeff, then compares the frequency responses:
function [Bq, Aq, Bcoef, Acoef] = filter_quantize(B, A) 
% quantize filter coeficients & un-quantize so as to get some idea to
% the *actual* fixed-point filter performance. 
% assume that everything in broken into biquads. 
base = 10; 
Aroots = roots(A); 
Broots = roots(B); 
order = length(Aroots)/2; % the number of biquads.
scale = B(1).^(1/order); % distribute the gain across the biquads. 
for o = 0:order-1
	Acoef_biquad(o+1, :) = poly(Aroots(o*2+1 : o*2+2));
	Bcoef_biquad(o+1, :) = poly(Broots(o*2+1 : o*2+2))*scale; 
end
Bcoef = round(Bcoef_biquad .* 2^base); 
Acoef = round(Acoef_biquad .* 2^base); 
% now, reverse the process. 
Bq2 = Bcoef ./ 2^base; 
Aq2 = Acoef ./ 2^base; 
for o = 0:order-1
	Arootsq(o*2+1: o*2+2) = roots(Aq2(o+1, :)); 
	Brootsq(o*2+1: o*2+2) = roots(Bq2(o+1, :)); 
end
Aq = poly(Arootsq); 
Bq = poly(Brootsq).*B(1); 
[H, W] = freqz(B, A); 
[Hq, Wq] = freqz(Bq, Aq); 
figure
plot(W, db(abs(H)), 'b')
hold on
plot(W, db(abs(Hq)), 'r')
axis([0 pi -100 0])
The result: high frequency is not much affected

but low frequency is strongly affected.

But this is at a quatization to 10 bits - quantization to 15 bits lead to reasonably good performance. I'm not sure if this conclusively indicates / counterindicates downsampling prior to highpassing for my application, but i would say that it does, as if you downsample by 2 the highpass cutoff frequency will be 2x larger hence the filter will be less senitive to quantization errors which affect low frequencies.

{213}
hide / edit[5] / print
ref: notes-0 tags: jtag fpga linux xilinx date: 08-21-2007 19:58 gmt revision:5 [4] [3] [2] [1] [0] [head]

openwince:

  1. need the include files as well as the jtag tools.
    1. I installed the include files in a subdirectory of the jtag folder called openwince-include
    2. you will need (for debian) libreadline5-dev
  2. need to edit openwince-include/brux/flash.h - remove the address argument to detectflash().
  3. rm config.h
  4. CFLAGS=-g (for debug)
  5. ./configure --with-include=/home/tlh24/jtag/openwince-include
  6. make clean
  7. make
  8. cd src
  9. sudo gdb jtag
  10. jtag> cable parallel 0x378 DLC5 (for the xilinx parport-III)
  11. jtag> detect (..shit)
  12. jtag> quit (switch to another terminal..)
  13. cd /usr/local/share
  14. mkdir jtag
  15. cd jtag
  16. sudo cp -R ~/jtag/data/* .
  17. gdb> run
  18. jtag> cable parallel 0x378 DLC5
  19. jtag> detect
IR length: 22
Chain length: 3
Device Id: 00000001010000110100000010010011
  Manufacturer: Xilinx
  Unknown part!
Device Id: 00000101000001000110000010010011
  Manufacturer: Xilinx
  Unknown part!
Device Id: 00000101000001000101000010010011
  Manufacturer: Xilinx
  Unknown part!
chain.c(110) Part 0 without active instruction
chain.c(133) Part 0 without active instruction
chain.c(110) Part 0 without active instruction

Pictures from the ragged stone user manual explain the pin numbering and orientation of the 2mm 14 pin dual row jatag header (compatable with Xilinx parallel port JTAG programmer & hence linux's jtag tools)

{432}
hide / edit[0] / print
ref: notes-0 tags: James DeMarsh PHF tlh24 Cornell date: 08-21-2007 16:35 gmt revision:0 [head]

{428}
hide / edit[1] / print
ref: notes-0 tags: activewire ez-usb an2131 cypress date: 08-16-2007 00:33 gmt revision:1 [0] [head]

to get the activewire board working under linux (debian):

  1. I had to install fxload (in the apt repository).
  2. install hex (1) , which is a simple LED blink routine from http://ezusb2131.sourceforge.net/ via:
    1. sudo fxload -I led2.hex -D /proc/bus/usb/006/118 where 118 is the address from dmesg | tail and led2.hex is hex(1)
  3. install hex (2), which is from http://activewire-osx.cvs.sourceforge.net/ -- it is the most recent i could find. translated via {427}
    1. sudo fxload -I awfirm2.hex -D /proc/bus/usb/006/118 awfirm2.hex is, of course, hex(2)
  4. check dmesg | tail - the EZ-USB chip should disconnect and reconnect with a new address. I don't know why the first ex is required - perhaps it resets the processor?
  5. run the awusb-linux program, for example, and do what you like.

I have no idea why this is required. perhaps my board is broken abit?

hex (1):

:03000000020100FA
:10010000907F947400F0907F9D7410F0907F9774AE
:1001100010F012012D12012D12012D907F97740005
:10012000F012012D12012D12012D02010C786490A4
:0C013000FB50A3E582458370F9D8F4224F
:00000001FF

hex(2):

:1007B600D204C203C200C202C201120653D2E843E7
:1007C600D820907FAB74FFF0907FA9F0907FAAF0BD
:1007D6005391EF907FAFE04401F0907FAEE0440D7F
:1007E600F0D2AF20014C750C00750B00750A007530
:1007F60009007F487E927D007C00AB0CAA0BA90AFB
:10080600A809C31207A5502020011D7A0079007897
:1008160000E50C2401F50CEA350BF50BE9350AF574
:100826000AE83509F50980CA2001B8D205120D7B00
:0F08360080B1300105120100C20112045180F39C
:010845002290
:10010000907FE9E070030201DF14700302025B24B8
:10011000FE70030202CF24FB70030201D9147003A6
:100120000201D31470030201C71470030201CD242D
:10013000056003020323120E33400302032F907F56
:10014000EBE024FE6016146040240270707403908B
:100150007FD4F07437907FD5F002032F907FEAE0D0
:10016000FF120A2D8B0D8A0E890FEA496011AE022B
:10017000EE907FD4F0AF01EF907FD5F002032F9087
:100180007FB4E04401F002032F907FEAE0FF120AFF
:100190007C8B0D8A0E890FEA496018AE02EE907FC3
:1001A000D4F0AF01EF907FD5F0120705907FB5F046
:1001B00002032F907FB4E04401F002032F907FB43C
:1001C000E04401F002032F120DFD02032F120E1F57
:1001D00002032F120E1702032F120DEF02032F122C
:1001E0000E35400302032F907FE8E0247F60241443
:1001F00060312402705BA200E433FF25E0FFA2021D
:10020000E4334F907F00F0E4A3F0907FB57402F0E8
:1002100002032FE4907F00F0A3F0907FB57402F00A
:1002200002032F907FECE0F45480FFC4540FFFE0F2
:1002300054072F25E024B4F582E4347FF583E0549D
:10024000FD907F00F0E4A3F0907FB57402F002030C
:100250002F907FB4E04401F002032F120E374003C9
:1002600002032F907FE8E024FE601D240260030259
:10027000032F907FEAE0B40105C20002032F907FB4
:10028000B4E04401F002032F907FEAE07038907FE1
:10029000ECE0F45480FFC4540FFFE054072F25E036
:1002A00024B4F582E4347FF583E4F0907FECE054ED
:1002B00080FF131313541FFFE054072F907FD7F0D4
:1002C000E04420F08069907FB4E04401F080601247
:1002D0000E39505B907FE8E024FE60182402704FD6
:1002E000907FEAE0B40104D2008044907FB4E044FF
:1002F00001F0803B907FEAE07020907FECE0F454C6
:1003000080FFC4540FFFE054072F25E024B4F5828A
:10031000E4347FF5837401F08015907FB4E04401EC
:10032000F0800C120C035007907FB4E04401F09071
:060330007FB4E04402F07E
:0103360022A4
:03003300020E2F8B
:040E2F0053D8EF3273
:100337001201000100000040540801010000010201
:1003470000010902C00001010080960904000004B1
:10035700FFFFFF00070581020200000705010240B9
:1003670000000705820202000007050202400000A4
:100377000904000100FFFFFF000904000200FFFF5E
:10038700FF000904000300FFFFFF00090400040049
:10039700FFFFFF000904000500FFFFFF000904003D
:1003A7000600FFFFFF000904000700FFFFFF000929
:1003B70004000800FFFFFF000904000900FFFFFF1A
:1003C700000904000A08FFFFFF0007058102020079
:1003D700000705010240000007058202020000072E
:1003E700050202400000070583020100000705031C
:1003F700020300000705040240000007050502404C
:10040700000004030904220341006300740069002B
:100417007600650057006900720065002C00200017
:1004270049006E0063002E001E0341006300740044
:1004370069007600650057006900720065002000BA
:0A04470055005300420000000000C1
:10065300907FDE740FF0907FACF0907FDF743FF0FB
:10066300907FADF0907FAE741FF0E4FF74802FF5A0
:1006730082E4347DF583E4F074002FF582E4347E64
:10068300F583E4F074802FF582E4347EF583E4F09F
:1006930074C02FF582E4347CF583E4F074402FF5C5
:1006A30082E4347DF583E4F074C02FF582E4347D75
:1006B300F583E4F074402FF582E4347EF583E4F0AF
:1006C3000FBF40A8E4907F9CF0907F9DF0907F9EA9
:1006D300F0907F93F0907F94F0907F95F0907F96C9
:1006E300F0907F97F0907F98F0751D01D200F51977
:1006F300F51AF518F51BF51CC206F516F517120EBB
:020703002722AB
:10045100907F9AE0907E80F0907F9BE0907E81F08B
:10046100907FB77402F0907F9DE0907E00F0907FC6
:100471009EE0907E01F0907FB97402F0907FCCE015
:1004810030E103020507907FBAE030E108E51C1571
:100491001C7002151B300669E4F50D907FCDE0FF5D
:1004A100E50DC39F5051E51AB40108E51C900FF00A
:1004B100F0800AE51B900FF0F0E51CA3F0051CE5A8
:1004C1001C7002051B74C0250DF582E4347CF58394
:1004D100E0FF74F0251AF582E4340FF583EFF0AFF5
:1004E10019E51A04FD7A0F7BF0120DBC7F0A7E001C
:1004F100120DD8050D80A4E4907FBBF0F516751799
:1005010008E4907FCDF0907FBAE030E10CA3E06089
:1005110008E51764084516704B30063DE51AB4012D
:1005210008E51C900FF0F0800AE51B900FF0F0E554
:100531001CA3F0051CE51C7002051BAF19AD1A7A4E
:100541000F7BF0120DBCAF197D027A0F7BF0120DFB
:10055100A0900FF0E0907D80F0907FBB7401F0E4FB
:05056100F516F517225C
:100BDA00907F9E74FFF0907F9DF0907F9CF0E49050
:100BEA007F98F0907F97F0907F96F0907F95F090A5
:090BFA007F94F0907F93F0D32268
:020AFD00D32202
:020E3300D322C8
:080E1700907FEAE0F51ED322F2
:0E0DEF00907F00E51EF0907FB57401F0D322D6
:080E1F00907FEAE0F515D322F3
:0E0DFD00907F00E515F0907FB57401F0D322D1
:020E3500D322C6
:020E3700D322C4
:020E3900D322C2
:100C0300907FE9E0B4B020907FECE0F45480FFC41F
:100C1300540FFFE054072F25E024B4F582E4347F1A
:090C2300F5837402F0C322D32210
:100C2C00C0E0C083C082C085C084C086758600D2F7
:100C3C00015391EF907FAB7401F0D086D084D085B6
:070C4C00D082D083D0E0321A
:100BB000C0E0C083C082C085C084C08675860090B6
:100BC0007FC4E4F05391EF907FAB7404F0D086D0F3
:0A0BD00084D085D082D083D0E032BB
:100C5300C0E0C083C082C085C084C086758600534F
:100C630091EF907FAB7402F0D086D084D085D08290
:050C7300D083D0E03247
:100C7800C0E0C083C082C085C084C086758600532A
:100C880091EF907FAB7410F0D086D084D085D0825D
:050C9800D083D0E03222
:010AFF0032C4
:100ABD00C0E0C083C082C085C084C086758600E555
:100ACD001D6004151D8002D2035391EF907FAB740E
:0F0ADD0008F0D086D084D085D082D083D0E0328C
:100C9D00C0E0C083C082C085C084C0867586005305
:100CAD0091EF907FA97401F0D086D084D085D08249
:050CBD00D083D0E032FD
:100CC200C0E0C083C082C085C084C08675860053E0
:100CD20091EF907FAA7401F0D086D084D085D08223
:050CE200D083D0E032D8
:100CE700C0E0C083C082C085C084C08675860053BB
:100CF70091EF907FA97402F0D086D084D085D082FE
:050D0700D083D0E032B2
:1008CA00C0E0C083C082C085C084C086758600C06F
:1008DA00D075D000C000C005C006C007E4FFFE9076
:1008EA007FC7E0FDC3EF9D7480F86E98502AEF3001
:1008FA00E0102440F582E4347EF583E0907F98F09E
:10090A00800F74402FF582E4347EF583E0907F9760
:10091A00F00FBF00010E80C7907FC7E4F05391EF3C
:10092A00907FAA7402F0D007D006D005D000D0D0AC
:0D093A00D086D084D085D082D083D0E0322A
:100D0C00C0E0C083C082C085C084C0867586005395
:100D1C0091EF907FA97404F0D086D084D085D082D6
:050D2C00D083D0E0328D
:10094700C0E0C083C082C085C084C086758600C0F1
:10095700D075D000C000C005C006C007907FC9E0B1
:10096700F508E4FFFE907FC9E0FDC3EF9D7480F8B2
:100977006E98501DEF30E00A907DC1E0907F9EF0A9
:100987008008907DC0E0907F9DF00FBF00010E8032
:10099700D4907FC9E4F05391EF907FAA7404F0D00C
:1009A70007D006D005D000D0D0D086D084D085D04F
:0609B70082D083D0E03283
:100D3100C0E0C083C082C085C084C0867586005370
:100D410091EF907FA97408F0D086D084D085D082AD
:050D5100D083D0E03268
:10084600C0E0C083C082C085C084C086758600C0F3
:10085600D075D000C005C006C007907D40E0FFC33C
:1008660013F519907FCBE0B40210751A01907D4103
:10087600E0751B00F51CD206801E907FCBE0C3946A
:10088600034015751A02907D42E0FE907D41E0FD21
:10089600EEF51BEDF51CD206907FCBE4F0907FBB06
:1008A600F0F5167517085391EF907FAA7408F0D0EB
:1008B60007D006D005D0D0D086D084D085D082D0BF
:0408C60083D0E032C9
:010E3B003284
:100D5600C0E0C083C082C085C084C086758600534B
:100D660091EF907FAA7410F0D086D084D085D0827F
:050D7600D083D0E03243
:010E3C003283
:1009BD00C0E0C083C082C085C084C086758600C07B
:1009CD00D075D000C000C005C006C007E4FFFE9082
:1009DD007FCFE0FDC3EF9D7480F86E98501DEF3012
:1009ED00E00A907C41E0907F9CF08008907C40E094
:1009FD00907F96F00FBF00010E80D4907FCFE4F072
:100A0D005391EF907FAA7420F0D007D006D005D077
:100A1D0000D0D0D086D084D085D082D083D0E032A3
:010E3D003282
:010E3E003281
:010E3F003280
:010E4000327F
:03004300020B00AD
:100B0000020C2C00020C5300020BB000020ABD00C4
:100B1000020C7800020AFF00020C9D00020CC200C9
:100B2000020CE7000208CA00020D0C00020947008F
:100B3000020D310002084600020E3B00020D560075
:100B4000020E3C000209BD00020E3D00020E3E00F6
:080B5000020E3F00020E4000FE
:100D7B00907FD6E054FBF0E04408F0300504E044EB
:100D8B0002F07FF47E01120DD8907FD6E054F7F07D
:050D9B00E04404F02219
:100DD8008E0E8F0FE50F150FAE0E7002150E4E60BA
:070DE80005120AEC80EE2267
:080E2700E4F526D2E9D2AF2266
:100B8500A907E5267023907FA5E04480F0E925E0DC
:100B9500907FA6F08D21AF03A9077522018A2389CD
:0B0BA50024E4F525752601D322C322AD
:100B5800A907E5267025907FA5E04480F0E925E007
:100B68004401907FA6F08D21AF03A9077522018A61
:0D0B7800238924E4F525752603D322C3222A
:03004B0002056645
:10056600C0E0C083C082C085C084C086758600C0D6
:10057600D075D000C000C001C002C003C006C007CD
:10058600907FA5E030E206752606020635907FA527
:10059600E020E10CE52664026006752607020635B2
:1005A600AF26EF24FE604814602C24FE60772404F6
:1005B6006003020635AB22AA23A924AF2505258FA1
:1005C6008275830012071E907FA6F0E525652170CF
:1005D6005E7526058059907FA6E0AB22AA23A92442
:1005E600AE258E8275830012074B7526028040E584
:1005F6002124FEB52507907FA5E04420F0E52114CF
:10060600B5250A907FA5E04440F0752600907FA6A8
:10061600E0AB22AA23A924AE258E82758300120799
:100626004B0525800A907FA5E04440F075260053CF
:1006360091DFD007D006D003D002D001D000D0D0B1
:0D064600D086D084D085D082D083D0E03221
:020A7C008F10D9
:100A7E00E4F5117512FF751304751409AB12AA1360
:100A8E00A91490000112071EB4031DAF110511EF3A
:100A9E00B51001221207057E0029FFEE3AA907754F
:0E0AAE0012FFF513891480D47B007A007900C2
:010ABC002217
:100A2D00E4FE7512FF751303751449AB12AA13A9D1
:100A3D001490000112071E6402702DAD060EEDB567
:100A4D0007012290000212076D85F010F51162105A
:100A5D00E5106211E511621029FDE5103AA9057541
:0E0A6D0012FFF513891480C37B007A00790014
:010A7B002258
:100DA000120B58E52624FA600E146006240770F32F
:0C0DB000D322E4F526D322E4F526D3225A
:100DBC00120B85E52624FA600E146006240770F3E6
:0C0DCC00D322E4F526D322E4F526D3223E
:100AEC007400F58690FDA57C05A3E582458370F91D
:010AFC0022D7
:03000000020E0BE2
:0C0E0B00787FE4F6D8FD7581260207B65A
:10070500BB010689828A83E0225002E722BBFE02F2
:09071500E32289828A83E4932225
:10071E00BB010CE58229F582E5833AF583E0225090
:10072E0006E92582F8E622BBFE06E92582F8E222DA
:0D073E00E58229F582E5833AF583E49322F4
:10074B00F8BB010DE58229F582E5833AF583E8F0E4
:10075B00225006E92582C8F622BBFE05E92582C890
:02076B00F22278
:10076D00BB0110E58229F582E5833AF583E0F5F0CA
:10077D00A3E0225009E92582F886F008E622BBFEA7
:10078D000AE92582F8E2F5F008E222E5832AF583ED
:08079D00E993F5F0A3E99322B2
:1007A500EB9FF5F0EA9E42F0E99D42F0E89C45F0AA
:0107B5002221
:00000001FF

{427}
hide / edit[0] / print
ref: notes-0 tags: perl one liner hex convert date: 08-15-2007 23:55 gmt revision:0 [head]

I wanted to take lines like this:

272 :1007A500EB9FF5F0EA9E42F0E99D42F0E89C45F0AA
and convert them into proper hex files. hence, perl:

perl -e 'open(FH, "awfirm.hex"); @j = <FH>; foreach $H (@j){ $H =~ s/^s+d+s//; $H =~ s/\//; print $H; }'

{422}
hide / edit[2] / print
ref: notes-0 tags: pick place vacuum valves hypodermic PCB assembly date: 08-14-2007 04:01 gmt revision:2 [1] [0] [head]

For the past few days I've been trying to figure out a way to do vacuum-assisted pick & place for home SMT PCB assembly.

Fortunately, I had a vacuum pump - this one bought, without motor, from now defunct Duke University Surplus for $25. I got the motor from my parents, and had to go to Northern Equipment for the pulley and belt (fyi: also bought a hot air gun, Wel-Bilt brand, which promptly broke upon testing at home.) I filled it with 10w30 synthetic motor oil, since some of original vacuum oil had leaked out during the (years?) of neglect at the surplus store.

The whole assembly was far heavier than i could move, so i welded together a little cart for it out of old sideskate axles & bed frames. The wheels are from a cheap wal-mart skateboard that i used like 3 years ago to make the pogoboard. I also had to figure out how to neck down the 1.5" vacuum port on top of the huge pump to 1/4 id tubing, which took about 15 mins of searching in home depot...

Above - Valves clamped to the table so i can operate them with my right hand while my left hand manipulates the fine SMT devices. Top valve is to control the vacuum pressure, bottom is a dump valve to release vacuum in the tip.

I used three hypodermic needles, of varying diameter, as the tips for picking up small items. For the large chips, e.g. 176 pin LQFP-s, I ganked the ink tube out of a ballpoint pen. & glued it to the syringe connector (which is nice and easily replaceable). All tips were ground down at about a 40 deg angle to hold the parts (and to make the tips dull enough so i wouldn't continually stab myself while working...)

simple and effective!

see also {423}

{412}
hide / edit[1] / print
ref: notes-0 tags: HVAC BT Durham 1107 date: 08-10-2007 15:08 gmt revision:1 [0] [head]

B&T HVAC Durham: 919-942-0380

{410}
hide / edit[0] / print
ref: notes-0 tags: multirate downsample DSP filter date: 08-09-2007 19:14 gmt revision:0 [head]

{405}
hide / edit[0] / print
ref: notes-0 tags: blackfin BF537 memory map date: 08-01-2007 19:23 gmt revision:0 [head]

{402}
hide / edit[0] / print
ref: notes-0 tags: fonts Debian Linux date: 07-31-2007 17:11 gmt revision:0 [head]

some cool fonts --

> sudo apt-get install ttf-bitstream-vera ttf-dejavu ttf-bpg-georgian-fonts ttf-dustin ttf-f500 ttf-freefont ttf-gentium ttf-isabella ttf-junicode ttf-kacst ttf-khmeros ttf-mgopen ttf-sjfonts ttf-staypuft ttf-summersby t1-xfree86-nonfree ttf-xfree86-nonfree ttf-larabie-deco ttf-larabie-straight ttf-larabie-uncommon

{390}
hide / edit[0] / print
ref: notes-0 tags: SFN deadlines date: 06-14-2007 20:29 gmt revision:0 [head]

{389}
hide / edit[1] / print
ref: notes-0 tags: ipod linux mount date: 06-13-2007 20:03 gmt revision:1 [0] [head]

The data partition on a HFS+ iPod ("Mac formatted iPod") is the third partition. The first is a partition table, the second has the OS, and the third is data.

sudo mount -t hfsplus /dev/sdc3 /mnt/ipod
works!!

{382}
hide / edit[1] / print
ref: notes-0 tags: keyboard frogpad layout qwerty date: 05-31-2007 00:52 gmt revision:1 [0] [head]

a while ago I made a custom keyboard for myself - something like the frogPad chording keyboard, but more suitable for programming. Here is the image i made for myself to learn the layout.

Upon testing, however, it seems that those scribbly marks on the paper had some import - this is the present layout, as re-drawn in inkscape. Presumably this second iteration is better?

{381}
hide / edit[2] / print
ref: notes-0 tags: low-power microprocessor design techniques ieee DSP date: 05-29-2007 03:30 gmt revision:2 [1] [0] [head]

http://hardm.ath.cx:88/pdf/lowpowermicrocontrollers.pdf

also see IBM's eLite DSP project.

{374}
hide / edit[0] / print
ref: notes-0 tags: entrepreneur MIT notes LLC tax law securities advice date: 05-22-2007 15:25 gmt revision:0 [head]

http://enterpriseforum.mit.edu/mindshare/startingup/index.html

  • many good articles on setting up a subchapter S corporation (only taxed once, with limitations), LLC, obtaining good employees, dealing with securities and investment, etc!

{373}
hide / edit[1] / print
ref: notes-0 tags: viscosity fluids Poiseuille kicad date: 05-22-2007 03:33 gmt revision:1 [0] [head]

http://xtronics.com/reference/viscosity.htm

the source site - http://xtronics.com/ - has a lot of interesting information. The author seems as enamored with Debian as I am. (hence, there is plenty of Debian information there :)

for example, they have a quick reference on kicad: http://xtronics.com/reference/kicad.html

{372}
hide / edit[1] / print
ref: notes-0 tags: kicad footprint generator pcb design date: 05-22-2007 02:51 gmt revision:1 [0] [head]

oh yea!!! nice work mate!!

http://www.rohrbacher.net/kicad/quicklib.php

btw, kicad is the shit - and it is now in Debian!! I love debian! I love kicad!

{371}
hide / edit[1] / print
ref: notes-0 tags: recording tech tbsi biosignal telemetry date: 05-20-2007 16:40 gmt revision:1 [0] [head]

{367}
hide / edit[0] / print
ref: notes-0 tags: RF telemetry differential phase shift key prosthesis power transmission TETS PSK date: 05-12-2007 23:13 gmt revision:0 [head]

transcutaneous data telemetry system tolerant to power telemetry interference

  • details optimum operation of class-E amplifier.
  • plus 1-2 MBaud data link, dual band to minimize interference.

{361}
hide / edit[14] / print
ref: notes-0 tags: Clementine review organize Miguel 042707 movies videos date: 04-29-2007 19:13 gmt revision:14 [13] [12] [11] [10] [9] [8] [head]

things that I want to send to miguel:

{359}
hide / edit[0] / print
ref: notes-0 tags: TMS coil design date: 04-27-2007 03:17 gmt revision:0 [head]

{218}
hide / edit[3] / print
ref: physics notes-0 tags: plasma mercury vapor lamp electron ozone date: 04-03-2007 15:23 gmt revision:3 [2] [1] [0] [head]

ok, so i just (19 Feb 2007) did some simple experiments with the small (100W) mercury vapor lamp that i have + a hard-drive magnet + a solenoid.

  1. magnet splits the plasma into two paths, depending on the direction of the AC plasma current. The split is strongest when at the transition between north and south poles on the HD rare-earth magnet, as here the field lines are going in short loops with the vertical part approximately intersecting the plasma, and hence exerting the lorentz force towards or away from the magnet.
    1. it is possible to extinguish the bulb by moving the plasma too close! I think that this forces the electrons to collide with the quartz tube, cooling them too much.
  2. I also built a solenoid out of a small spool of 14 gauge magnet wire attached to my buzz box arc welder. The current was set at ~50 amps, (not sure how accurate that setting was) - enough to get the small coil pretty hot rather quickly. When placed inside the AC-energized coil, the plasma arc was forced to spiral around the walls of the quartz tube.
    1. This is most likely because the mean velocity of the electrons is pretty low, hence the lamour radius is high in the relatively-weak magnetic field. I notice that at the beginning of igniting the mercury-vapor lamp, far more ozone is produced (as gauged by smell) than is produced when it is hot and the plasma current is high. This accompanies a shift from a very blue emission spectra to a whiter emission, I think this is because the pressure becomes higher inside the tube, hence the mean free path of the electrons is lower, hence they have less energy to excite the hard-UV bands of mercury ions once the lamp is hot. http://en.wikipedia.org/wiki/Planck's_constant --> E=hv, where v is the frequency --> 250nm approximately equals 5 eV. lamour radius: mv/qB. 5ev ~= 1.33e6 m/s. @ B= 0.1T, lamour radius = 7.5e-5m = 0.07mm (what?) ok, more reasonable: B = 0.005T, r = 1mm - still smaller than observed! Need to check this magnetic field. B=mu n I. I = 50A, n = 3 * 2/0.064) = 93 turns, mu (air) = 4*pi*10^-7 --> B ~= 0.005T. (as a first approximation). If the electron velocity is lower, then the radius will be smaller; it is the opposite for the magnetic field strength.
    2. of course, we are disregarding thermal interactions, as well as drift - will have to look at the textbook for this.
  3. Feb 23 2007 - I made a larger-diameter solenoid out of the 14 gauge copper wire & turned the buzz-box welder current up to 100A (or so it says, don't know how much in practice) - enough to get the coil very hot very quickly. I put this current loop around the broken 400W metal-halide lamp - the one originally from the blacklight cannon. As it is still being driven from the same low-wattage power supply, it remains cool, the bulb voltage is low (21V) and much UV (and ozone) is produced - generally indicating that the pressure in the bulb is low and the electron velocity/mean free path is higher.
    1. well, actually: when the blub pressure is low, much energy below 240nm is produced. Apparently this is what is required for ozone production:
    2. HBO lamps do not generate ozone, because owing to the self-absorption in the cooler outer arc regions, all radiation below 240nm is trapped within the discharge. However during run-up before pressure increases, some ozone is produced.
    3. When I turned the solenoid on around the ignited bulb, the concentration of plasma in the center noticably increased, and the luminous intensity increased also. I'm not sure if this was due to AC pumping of plasma current; I doubt it, as most of the magnetic flux should have went around the plasma.
    4. The bulb voltage went to 23 - 24V; I do not know the current, I will have to measure it (perhaps with an oscilloscope?)
    5. The plasma became less uniform, too, perhaps because the solenoid was not aligned to the E-field with any accuracy.

{226}
hide / edit[1] / print
ref: work notes-0 tags: web stimulator SUNY ICMS python webinterface project date: 03-26-2007 04:26 gmt revision:1 [0] [head]

we are proud of this :)

{230}
hide / edit[0] / print
ref: engineering notes-0 tags: homopolar generator motor superconducting magnet date: 03-09-2007 14:39 gmt revision:0 [head]

http://hardm.ath.cx:88/pdf/homopolar.pdf

  • the magnets are energized in 'opposite directions - forcing the field lines to go normal to the rotar.
  • still need brushes - perhaps there is no way to avoid them in a homopolar generator.

{229}
hide / edit[2] / print
ref: notes-0 tags: SNR MSE error multidimensional mutual information date: 03-08-2007 22:33 gmt revision:2 [1] [0] [head]

http://ieeexplore.ieee.org/iel5/516/3389/00116771.pdf or http://hardm.ath.cx:88/pdf/MultidimensionalSNR.pdf

  • the signal-to-noise ratio between two vectors is the ratio of the determinants of the correlation matrices. Just see equation 14.

{228}
hide / edit[0] / print
ref: engineering notes-0 tags: cascode amplifier jfet circuit audio miller effect input capacitance date: 03-03-2007 04:15 gmt revision:0 [head]

http://www.borbelyaudio.com/adobe/ae599bor.pdf

  • a good tutorial on using JFETs for audio amplifier applications
  • shows use of a cascode topology to reduce the miller input-capacitance.

{225}
hide / edit[0] / print
ref: physics notes-0 tags: plasma LDX dipole confinement fusion date: 02-24-2007 17:55 gmt revision:0 [head]

First Experiments to test plasma confinement by magnetic dipole

  • Beta is limited by the background pressure of lower-temperature gas - more gas = more stable & trapped electrons. presumably this is due to the presence of positive charges? I don't know, need to read more.
    • this is in the presence of 2-5Kw of microwave electron-cynchrotron radiation heating.
  • this is not levitated - it is the superconducting dipole held up with supports (steel cables? - looks pretty heavy!)
  • want to do catalyzed D-D fusion in the ultimate device
  • do say how they are going to get longer-term containment of the hot plasma.

{223}
hide / edit[0] / print
ref: physics notes-0 tags: plasma physics electromagnet tesla coil copper capillary tubing calculations date: 02-23-2007 16:01 gmt revision:0 [head]

calculations for a strong DC loop magnet using 1/8" copper capillary tubing:

  1. OD .125" = 3.1.7mm^2; ID 0.065 -> copper area = 23.2mm^2 ~= AWG 4
  2. AWG 4 = 0.8 ohms/km
  3. length of tubing: 30' ~= 40 turns @ 9" each (windings packed into a torus of major radius 1.5"; minor radius 0.5")
  4. water flow rate through copper capillary tubing: 1 liter/min; assuming we can heat it up from 30C -> 100C, this is 70KCal = 292 KJ/min = 4881 W total. (better pipe it into our hot water heater!)
  5. 4.8kw / 9m of tubing = 540 W/m
  6. 540W/m / 8e-4 = 821 A ; V = 821 * 9 * 8e-4 = 5.9V (!!! where the hall am i going to get that kind of power?)
  7. 821A * 40 turns = 32.8KA in a loop major radius 1.5" = 3.8cm
  8. magnetic field of a current loop -> B = 0.54T
  9. lamour radius: 5eV electrons @B = 0.54T : 15um; proton: 2.7cm; electrons @1KeV ~= 2.66e8 (this is close to the speed of light?) r = 3mm.

{221}
hide / edit[0] / print
ref: notes-0 tags: patents USPTO date: 02-22-2007 04:28 gmt revision:0 [head]

http://0-www.uspto.gov.mill1.sjlibrary.org/web/offices/com/iip/transcriptsf_m.htm -- great FAQ

{220}
hide / edit[1] / print
ref: math notes-0 tags: linear_algebra BLAS FFT library programming C++ matrix date: 02-21-2007 15:48 gmt revision:1 [0] [head]

Newmat11 -- nice, elegant BLAS / FFT and matrix library, with plenty of syntactic sugar.

{217}
hide / edit[2] / print
ref: notes-0 tags: mysql join date: 02-17-2007 18:13 gmt revision:2 [1] [0] [head]

you can join two tables by matching their entries!!

SELECT * FROM `eval` LEFT JOIN (`infoT` ) ON (infoT.file=eval.file AND infoT.chan=eval.chan AND infoT.unit=eval.unit AND infoT.section=eval.section) WHERE infoT.maxinfo/infoshuf > 20 ORDER BY eval.eval DESC

{216}
hide / edit[2] / print
ref: notes-0 tags: perl one-liner match grep date: 02-17-2007 17:45 gmt revision:2 [1] [0] [head]

to search for files that match a perl regular expression: (here all plexon files recorded in 2007)

locate PLEX | perl -e 'while ($k = <STDIN>){ if( $k =~ /PLEXdddd07/){ print $k; }}'

{211}
hide / edit[0] / print
ref: neuro notes-0 tags: SNr SNc substantia nigra anatomy tracing date: 02-06-2007 05:40 gmt revision:0 [head]

Patterns of axonal branching of neurons of the substantia nigra pars reticulata and pars lateralis in the rat.

{27}
hide / edit[1] / print
ref: notes-0 tags: VOR OKR climbing_fibers cerebellum purkinje cells date: 02-05-2007 23:45 gmt revision:1 [0] [head]

  • Motor Coding in Floccular Climbing fibers
  • On climbing fiber signals and their consequences 1996, review
  • The site of a motor memory shifts with consolidation
  • Learning in a simple motor system (February 2006)
    • in the abstract: "we propose that short-term motor memory is initially stored in the cerebellar cortex, and during consolodation the motor memory locus shifts to include a brainstem site"
      • ISO learning as a method of consolodation, reflex-adatpation and internalization? that would be cool.
    • a good diagram of the system for the lateral rectus
    • due to its pivotal nature, motor learning may have been one of the first forms of learning to be implemented by biology. "universal in freely-moving animals"
    • these authors define it as procedural - does not require conscious attention (but it can be influenced by it)
    • eye movements procedurally simpler than arm movements, which I've spent some time looking at.
      • lately, I've been having to do a lot of this, after my glasses lost one earpeice and have been moving about since :) slight changes in the angles of the lenses are very noticeable.
    • I thought that the theory for this system would be complete by now, and ready for the application to more complicated motor movements, but this is not so. The thoeries are still a bit controversial, and require a molecular understanding.
---- Description of the system: see figure. need to label this on the slides. (comment: I'm sure many of you know this better than i, but for review ...) need diagram of the direction that the eyes turn, including the lateral/medial rectus muscles. Note that the eyes are stabilized in the two other directions - pitch and roll. here we study yaw, but people have demonstrated the same effects in the other directions. { cat and human have gain < 1, monkey just about 1 (perfect) - humans require extra input, via OKR} - basic circuit known since 1967 (Eccles). - Maekawa and Simpson: the cerebelar purkinje cell recieves climbing fiber input from the inferior olivary nucleus that encodes visual information. - information about ongoing movements arrives at the lateral vestibulocerebellum via mossy fivers from the dorsolateral pontine nuclei. - some mossy fibers also carry visual information. - purkinje cells project directly back to the vestibular nuclei.

{10}
hide / edit[0] / print
ref: notes-0 tags: leptin depression weight fat rats date: 0-0-2007 0:0 revision:0 [head]

  1. lepin is released by fat cells & gives the brain a reading of fat stores.
  2. obese people have high leptin levels, but their appetite still seems high; injecting obese people with leptin seldom causes them to loose weight.
  3. leptin injections encourage stressed or depressed rats to drink coke, i mean sugary liquid.
  4. leptin levels and appetite are low p>0.5 in depressed people.

items 2-4 are not in accord with the stated purpose of leptin (1).

{76}
hide / edit[0] / print
ref: notes-0 tags: dopamine addiction mesolimbic date: 0-0-2007 0:0 revision:0 [head]

experiment: animals initially learn that a light always lights up after pressing a switch which causes the administration of opioids. in successive trials the animal is not rewarded for pressing the switch, however the light (sometimes?) lights up following lever depression - and the animals continue to press the lever in the abscence of reward -- the reward has been transferred to the conditioned stimulus? http://druglibrary.org/schaffer/heroin/ase/chap_4.htm

{102}
hide / edit[0] / print
ref: notes-0 tags: phrase date: 0-0-2007 0:0 revision:0 [head]

Keep your hands on the knobs and your head in the clouds!

{107}
hide / edit[0] / print
ref: notes-0 tags: SQL kinarm count date: 0-0-2007 0:0 revision:0 [head]

SELECT file, COUNT(file) FROM info2 WHERE unit>1 AND maxinfo/infoshuf > 10 AND analog < 5 GROUP BY file ORDER BY COUNT(file) DESC

to count the number of files matching the criteria.. and get aggregate frequentist statistics.

{114}
hide / edit[0] / print
ref: notes-0 tags: essential tremor ET date: 0-0-2007 0:0 revision:0 [head]

-

  • essential tremor usually stops at night; hence, patients typically turn off the thalamic stimulator at night to conserve batteries.
  • in DBS the VIM (ventral intermediate) is targeted.
  • Blood flow responses to deep brain stimulation of thalamus
    • science is still unsure of the mechanism of DBS in VIM.
    • their PET scans indicated that DBS in VIM stimulates local blood flow, as well as blood flow in the SMA, which is innervated by VIM (quote: 'terminal fields of thalamocortical projections'). hence, the effect is activation, not inactivation.
  • http://neuroscienceupdate.cumc.columbia.edu/popups/transcript_pullman.html DBS of VIM also has been used in cerebellar outflow conditions as well
    • dementia is worstened by DBS :(
    • @ cornell they are doing genetically engineered transplantations to treat Parkinson's?
    • postural problems and balance issues don't improve with DBS in Parkinsons. (because of the cerebellum lobule 9-10?)
  • http://www.benbest.com/science/anatmind/anatmd7.html
    • VIM / VL thalamus projects to the supplementary motor area, and recieves input from the globus pallidus.
    • VP recieves input from the medial lemniscus, projects to S1 & somatosensory corticies.
    • cerebellum projects to the VA thalamus through the superior cerebellar peduncle.

{131}
hide / edit[0] / print
ref: notes-0 tags: insular cortex anterior cingulate spindle neurons date: 0-0-2007 0:0 revision:0 [head]

spindle neurons are found in the insular cortex as well as the anterior cingulate cortex, but only, apparently, in great apes. Activity in the insular cortex has been found to be correlated to feeling empathy.

{132}
hide / edit[0] / print
ref: notes-0 tags: LSD rhesus monkeys date: 0-0-2007 0:0 revision:0 [head]

http://hardm.ath.cx:88/pdf/LSDRhesusMonkeys.pdf

  • monkeys had a sucking behavior after large doses
  • human babies have synestesia
  • perhaps LSD has some endogenous equivalent found in babies?

{134}
hide / edit[0] / print
ref: notes-0 tags: thesis thoughts date: 0-0-2007 0:0 revision:0 [head]

properties of the brain: 1 .cerebellum in a supervised learner, I agree with the evidence: it learns to predict future outcomes given present states very efficiently. Appears to have a structure that is conducive for learning spatio-temporal structures, with the parallel fibers and purkinje cells. climbing fibers fire on error and cause LTP. Purkinje cells have inhibitor output -> hence error to LTP to less inhibition = movement in the positive direction. Mossy fibers have collaterals to DCN neurons and purkinje cells, i think.

this whole structure seems rather strange to me - why the multiple levels of inversion? it is the same as the basal ganglia - striatal output is inhibitory upon the globus pallidus, globus pallidus output is inhibitory on the thalamus. {and, at least in the monkey though probably also in the human, the thalamus is very large and very well organized}. actually, the whole brain seems exceedingly well organized, the problem is that we don't really understand this organization quite yet. E.G the putamen seems to have a somatotopic organization & has units which fire according to motion in the distal joints. (those old papers are great!) . caudate seems to have some sort of cognitive role?

blaaa. so, what does the brain do? it learns to live, more or less; it is adaptive. humans seem to be thte most adaptive; we stay in the adaptive phase for the longest part of our life, whereas rhesus seem to grow up rather quickly. learning! as kawato's student explains, learning modifying a function to minimize (or maximize) some evaluative function. In the case the fitness function is some function of the match between desired output and training output, that learning is supervised. We have neural networks to do this, and undoubtably the human mind can do this too. In the case the fitness function is some weighted-sum of a scalar reward, then you have reinforcement learning. Generally, the animal will learn the value of certain states, actions, or state-action pairs, and has to choose which is the best based on either the direct perceived value or the integrated expected future value. Humans think in this way all the time, and use a high-level model of the world, learned basically by example, trial and error, and even book-learning, to 'do the integral' and evaluate which of several paths are best. Once we 'decide', things then become habits. We, and especially monkeys, are exceptionally subject to choosing arbitrarily when the reward is unknown - we explore all of our lives, in order to expand the quality of our models of the world, and improve the reward-evaluation of states and actions. Is this dichotomy between models and evaluations artificial? Is there any reason to believe that they are represented in separate structures/pathways/molecules in the brain? perhaps. take dopamine for example. blocking its reuptake via cocaine is very rewarding, and induces a habit in mammals that are administered the drug. but perhaps it it not so much involved in reward so much as desire. {drug addicts who have their DA1 receptor blocked end up taking /more/ drugs, apparently in the desire to feel something}. DA depletion in parkinsons makes the stick larger in carrot-stick learning: these patients learn worse with reward than controls. {hence, error must not require DA}. _{system function is hard to intuit from such nonspecific effectors like drugs because the system is adaptive; i actually think leasions are better, or at least seem better, due to the precise organization fo the brain.

anyway, learning. "the controller learns the inverse model of it's own reflexes" - this is brilliant. only through hebbian learning! I like this a lot. In general, i agree with Kawato (actually, so far everything he has put out seems to be high-quality, well thought out and easy to understand) - the proof is incontrovertible that there are inverse models in the brain, probably at least in the cerebellum.

todo: review what is required to make an inverse model.

ok time to put the monkey away.

{137}
hide / edit[0] / print
ref: notes-0 tags: PLS date: 0-0-2007 0:0 revision:0 [head]

http://www.utdallas.edu/~herve/Abdi-PLS-pretty.pdf or http://hardm.ath.cx:88/pdf/PLS_abdi.pdf

PLS searches for a set of components (called latent vectors) that performs a simultaneous decomposition of X (measured) and Y (to be predicted) with the constraint that these components explain as much as possible of the covariance between X & Y.

http://hardm.ath.cx:88/pdf/PLS_algs.pdf --better, though only deals with one-dimensional regressions.

http://www.kernel-methods.net/matlab/algorithms/pls.m --complete matlab implementation, yay!

http://www.statsoft.com/textbook/stpls.html --cool book on partial least-squares.

{135} has a good, terse example of locally weighted PLS

{174}
hide / edit[0] / print
ref: life notes-0 tags: restaurants RTP date: 0-0-2007 0:0 revision:0 [head]

http://triangle.citysearch.com/bestof/winners/romantic_dining

{189}
hide / edit[0] / print
ref: neuro notes-0 tags: Dopamine receptor D1 D2 date: 0-0-2007 0:0 revision:0 [head]

http://www.cnsforum.com/imagebank/section/receptor_systems_Dopaminergic/default.aspx

  • the D1 receptor is coupled to stimulatory G-proteins, which cause cell depolarization. (pathway: stimulatory g-protein -> actibation of adenylate cyclase converts ATP -> cAMP -> PKC -> phosphorylation of sodium (and calcium?) channel.
  • the D2 receptor (family?) is coupled to inhibitory G-proteins, which decrease the activity of adenylate cyclase. this is a pretty vague picture.

{6}
hide / edit[0] / print
ref: notes-0 tags: Firefox MathML fonts Linux STIX date: 0-0-2006 0:0 revision:0 [head]

okay, so i spent some time on this and eventually realized that linux doesn't (can't) have all the symbols of the windows fonts used in MathML (for example the pitchfork symbol). The general solution, as per http://mcelrath.org/Notes/MathML, is not so difficult:

  1. install the tex and Mathematica fonts
  2. install opensymbol Debian package, which includes an (incomplete) symbol.ttf font. (the symbol.ttf from windows seems not to work??)
  3. uncomment the lines in /usr/share/firefox/res/fontEncoding.properties:
encoding.symbol.ttf = Adobe-Symbol-Encoding encoding.symbol.ftcmap = mac_roman
  1. some uncommon symbols like the hat and pitchfork are still missing. however, fc-cache | grep Symbol reads:
OpenSymbol:style=Regular Standard Symbols L:style=Regular Symbol:style=Regular
  1. hmm.. .it appears that I have another symbol font.
cd /usr/X11R6/lib/X11/fonts/Type1 sudo rm Symbol* sudo mkfontscale sudo mkfontdir fc-cache ... still there (and the pitchfork still doesn't work :( ) Well, STIX fonts should be out soon, as of Jan20 2006 they have < 400 glyphs to go.

{9}
hide / edit[0] / print
ref: notes-0 tags: powerpaw skateboard wheels date: 0-0-2006 0:0 revision:0 [head]

65mm/74a. cheap, slides well, wears out quickly (which is somewhat compensated by the cheap aspect). apparently requires a 11mm spacer, according to this site (which also seems to have no way of ordering / no stock). Can't find 11mm, going with 10.3mm steel spacer, we'll see how it works. (recall the krypto classics use an 8mm spacer).

{18}
hide / edit[0] / print
ref: notes-0 tags: SQL fulltext search example date: 0-0-2006 0:0 revision:0 [head]

SELECT * FROM `base` WHERE MATCH(`From`, `To`) AGAINST('hanson') ORDER BY `Date` DESC Limit 0, 100

  • you need to have a fulltext on the column set provided as a parameter to the MATCH() keyword. Case does not matter so log as the coalition is correct.

{19}
hide / edit[0] / print
ref: notes-0 tags: debian apt sources list date: 0-0-2006 0:0 revision:0 [head]

/etc/apt/sources.list:

#deb file:///cdrom/ sarge main

deb http://mirrors.kernel.org/debian/ unstable main contrib non-free
deb-src http://mirrors.kernel.org/debian/ unstable main contrib non-free

deb http://security.debian.org/ stable/updates main contrib non-free
later run as root:
  # apt-get update
  # aptitude install aptitude 
  # aptitude -f --with-recommends dist-upgrade
  # reboot
then you'll probably want to get a newer kernel, ala: http://www.howtoforge.com/forums/showthread.php?t=21

{26}
hide / edit[0] / print
ref: notes-0 tags: architecture aesthetic light date: 0-0-2006 0:0 revision:0 [head]

http://www.thomaslockehobbs.com/ -- interetsing photoblog of a globetrotter & laconic harvard intellectual

http://www.uni-weimar.de/architektur/InfAR/lehre/Entwurf/Patterns/107/ca_107.html Modern buildings are often shaped with no concern for natural light - they depend almost antirely on artificial light. But buildings which displace natural light as the major source of illumination are not fit places to spend the day.

{30}
hide / edit[0] / print
ref: notes-0 tags: matlab mysql hack date: 0-0-2006 0:0 revision:0 [head]

LD_PRELOAD=/lib/libgcc_s.so.1 matlab this allows you to command-line call mysql or other programs that use linux's standard libgcc.

{44}
hide / edit[0] / print
ref: notes-0 tags: spike patterns neural response LGN spike_timing Sejnowski vision date: 0-0-2006 0:0 revision:0 [head]

http://www.jneurosci.org/cgi/reprint/24/12/2989.pdf

  • quote: " when a cortical neuron is repeatedly injected with the same fluctuating current stimulus, the timing of the spikes is highly precise from trial to trial and the spike pattern appears to be unique"
    • though: I'd imagine that somebody has characterized the actual transfer function of this.
  • mais: we conclude that the prestimulus history of a neuron may influence the precise timing of the spikes in repsonse to a stimulus over a wide range of time scales.
  • in vivo, it is hard to find patterns because neurons may jump between paterns & there is a large ammount of neuronal noise in there too. or there may be neural "attractors".
  • they observed long-term (seconds) firing patterns in cat LGN (interesting)

{46}
hide / edit[0] / print
ref: notes-0 tags: cortex date: 0-0-2006 0:0 revision:0 [head]

  • eloquent cortex = cortex involved in motor or speech area. therefore, non-eloquent = not motor or speech.
  • DBS surgeries go through the middle frontal gyrus.

{53}
hide / edit[0] / print
ref: notes-0 tags: cartesian gantry robot date: 0-0-2006 0:0 revision:0 [head]

{62}
hide / edit[0] / print
ref: notes-0 tags: music hardm.ath.cx date: 0-0-2006 0:0 revision:0 [head]

  • Allee Der Kosmonauten Jazzanova Singles collection 1997-2000. gamelan-like, different though

{63}
hide / edit[0] / print
ref: notes bookmarks-0 tags: spike sorting bayes spectral_analysis date: 0-0-2006 0:0 revision:0 [head]

{70}
hide / edit[0] / print
ref: notes, bookmark-0 tags: spikes action_potentials neurons subthreshold depolarization c.elegans date: 0-0-2006 0:0 revision:0 [head]

"Millisecond-timescale, genetically targeted optical control of neural activity" http://www.nature.com/neuro/journal/v8/n9/full/nn1525.html

what they did:

  • expressed ChR2 receptor in cultured hippocampal neurons.
  • ChR2 is a rapidly-gated light-sensitive cation channel recently isolated from unicellular green alga
  • cells were transfected via lentivirus
  • caused spiking in cells by exposing them to 5-15ms flashes of blue light.
  • stimulation was reliable to 30hz
  • stimulated spikes had low jitter - 2ms or so.
  • light stimulation protocol was robust across different neurons.
  • expression of the light-gated channel did not alter the properties of the neurons or their health etc.
  • they think it might be applicable to in-vivo mamalian studies!
  • Subthreshold!
    • for many cellular and systems neuroscience processes subthreshold depolarizations convey physiologically significant information.
    • the neurons in c.elegans do not spike!
    • subthreshold depolarizations are potent for activating synapes-to-nucleus signaling
    • the relative timing of subthreshold and suprathreshold depolarizations can determine the direction of synaptic plasticity.
    • subthreshold depolarizations operate in the more linear regime of membrane voltage

{73}
hide / edit[0] / print
ref: notes-0 tags: praxis movement vision date: 0-0-2006 0:0 revision:0 [head]

  • praxis is the ability to plan and sequence unfamiliar actions.
  • things are only remembered when they produce motor output.
  • if you put an eye patch over one eye in a 2-year old human for two weeks, the child's vision in that eye will be permanently impared.
  • movement stimulates creativity.

{74}
hide / edit[0] / print
ref: notes-0 tags: dyslexia date: 0-0-2006 0:0 revision:0 [head]

dyslexia: often, so much effort is expended making the eyes track properly that less effort is available for comprehension, and the child is inordinately (exceeding reasonable limits) tired at the end of the day.

{86}
hide / edit[0] / print
ref: notes-0 tags: linux rename files add extension date: 0-0-2006 0:0 revision:0 [head]

pretty simple, to add a .mp3 to all files in a directory (e.g. if they originally were on an old mac):

     rename 's/(.*)/$1.mp3/' *
the expression in quotes is just a perl regular expression

{93}
hide / edit[0] / print
ref: notes-0 tags: MCMC Monte carlo markov chain date: 0-0-2006 0:0 revision:0 [head]

In a MCMC, the invariant distribution is a eigenvector of the state transition matrix whose eigenvalue is 1!

page 372 of http://www.inference.phy.cam.ac.uk/itprnn/book.pdf