3:36:45 am on 7/30/10
Menu
» Home
» About Scott
» QRSS VD
» Old Stuff
» Archive
» Contact

Categories
» C/C++
» Circuitry
» Dentistry
» DIY ECG
» General
» Linux
» Microcontrollers
» Molecular Biology
» My Website
» PHP
» Prime Numbers
» Python
» Radio
» UCF Lab
» Everything
Writings
» MD Labels
» Streamrip
» AIM Thoughts
» WindowsXP?
» Partitioning
» CD/DVD Repair
» Monitor Info
» CRT Deflection
» Venomcrack
» Flash Thing
» Heart/Brain
» Diabetes
» Triops
» Biomed

Friends
» Fred
» Kyle W
» Nick
» Louis
» Tom
» Kyle H




Archives
» July 2010
» June 2010
» May 2010
» April 2010
» March 2010
» February 2010
» January 2010
» December 2009
» September 2009
» August 2009
» July 2009
» June 2009
» May 2009
» April 2009
» March 2009
» February 2009
» January 2009
» December 2008
» November 2008
» October 2008
» September 2008
» September 2007
» December 2006
» August 2006
» January 2006
» August 2005
» July 2005
» June 2005
» May 2005
» April 2005
» March 2005
» February 2005
» January 2005
» December 2004
» November 2004
» October 2004
» September 2004
» August 2004
» July 2004
» June 2004
» May 2004
» April 2004
» March 2004
» February 2004
» January 2004
» December 2003
» November 2003
» October 2003
» September 2003
» August 2003
» July 2003
» June 2003
» May 2003
» April 2003
» March 2003
» February 2003
» January 2003
» December 2002
» November 2002
» October 2002
» September 2002
» June 2001

You are currently browsing the The Blogging Protagonist weblog archives for June, 2009.

Archive for June, 2009



Prime Schematics
Posted by
Scott June 30th, 2009 | 5,253 words | No Comments »


Scott was 23.77 years old when he wrote this!

Here’s a rough approximation of the current schematic of the prime number calculator I’m working on. Last night I finished wiring all 12 shift registers for the primary display, so now it’s time to start working on software. Notice that we have a lot of pins free still. This will be advantageous if I decide to go crazy adding extraneous functionality, such as fancy displays (LCD?, 7-segment LEDs?, VFD?, all 3?!) or creative input systems (how about a numerical keypad?). After feeling the stink of paying almost $15 for 100′ of yellow, 24 gauge, solid-core wire from DigiKey I was relieved (and a little embarrassed) to find I could score 1,000′ of yellow, 24 gauge, threaded wire for $10 at Skycraft! Anyway, here’s the current schematic:
text5130



Field Day 2009
Posted by
Scott June 29th, 2009 | 5,253 words | 2 Comments »


Scott was 23.76 years old when he wrote this!

Last weekend was field day, a disaster simulation / competition for amateur radio operators. In a sentence, people are encouraged to make as many contacts as they can around the world (earning points) using emergency radio preparations (battery and solar powered radios, temporary antennas, etc) for a full 24 hours (2pm to 2pm). I spent the time with the UCF Amateur Radio Club who set up big antennas in a grassy field on campus. It was a fun experience, and the first time I ever got to see a HF rig in operation. A representative for the UCF newspaper showed up, took some interviews, and I ended-up being quoted in the article. I can also be seen in the photo, if you look close enough (yellow square).
scottpaper

Being that amateur radio was something I got into independently (I didn’t know anyone else with a license) I was (and still am) very isolated in the hobby. I’m really thankful I found the UCF ARC, even though it wasn’t until I’d already been going to UCF for 2 years and was already on my way out. scottpaperzoomSeeing (and actually get to use) a HF rig was an eye-opening experience for me, and one I’m a little regretful I participated in. Before yesterday, I had already come to terms with my situation (going to dental school in a few weeks and virtually dropping all of my hobbies) and was content with my summer accomplishments so far. My summer goal was to get into radio, and before yesterday I felt I had. I studied for my exam, got my license, learned how to use repeaters on VHF to easily make local contacts, and I was satisfied. I knew HF was out there, and that it allowed communication over thousands of miles, but I ignored it knowing I wouldn’t get into it this summer (the equipment is just too expensive for me to justify purchasing). Now, after sitting in front of a rig for several hours, I wish I had the time to upgrade my license, earn a little cash to blow on a HF radio, and spend a few weeks sitting in front of it scouring the waves for random voices around the world. I know it’s a little morbid, but I’d probably have to compare the feeling I’m experiencing with what an old person feels like when they realize their end is near and that they won’t be able to do the things they always dreamed they would. Oh well, at least I’ll be able to fill holes in teeth soon. [smiles convincingly]



Jedi Soldering Skills – Part 2
Posted by
Scott June 25th, 2009 | 5,253 words | No Comments »


Scott was 23.75 years old when he wrote this!

I’ll update my progress on this project as I go. I added a lot more light bars to the shift registers on my prime number generator project. I’m up to 5 daisy-chained shift registers completed (powering 40 LEDs) with 7 more to go! I’m using 22 gauge solid-core (fancy and expensive, from digikey, 100′ 14$!) wire for the back of this project. Being that I plan to keep it for many years, I want it to look crazy awesome. Remember, I’m only about 1/3 done so far…
img_2445

I powered the device up and it produced proper output. Yay! I was so discouraged yesterday when I wired-up an entire row (the top one), powered it on, and 1/2 the LEDs didn’t work. At first I thought it was software, but then I realized that I burned the LEDs out in the soldering process by getting them too hot. I had to de-solder EVERYTHING, rip out the destroyed LED bars, and start over. I’ll have to pick up some more light bars at Skycraft soon. This is what it looks like currently:
img_2453

I’m making this project a priority because I only have a few weeks before I move to Gainesville, FL for dental school (the cutoff date for all electronics/radio/programming projects). I’ll be busy the next few days with other obligations (work, apartment hunting, field day, etc.) but I hope to resume this project soon.

UPDATE (June 26, 2009 @ 7:30pm): I finished wiring all the light bars I have. I need to purchase 3 more 10-led bars at Skycraft to replace the ones I melted with my soldering iron. D’oh! Anyway, here’s the beaut:
dark_bars
wires1



Reading, Writing, and Flipping Bits in C
Posted by
Scott June 24th, 2009 | 5,253 words | No Comments »


Scott was 23.75 years old when he wrote this!

Bitwise programming techniques (manipulating binary numbers) is simple in theory, but it’s often hard to remember how to do specific tasks if you don’t do them often. Recently in my microcontroller programming endeavors (where you’re pressed to conserve every bit of memory) I’ve needed to perform a lot of bitwise operations. If I’m storing true/false (1-bit) information in variables, it’s a waste to assign a whole variable to the task (even a char, the smallest variable in C is a waste because it uses 8 bits of memory!). When cramming multiple values into individual variables, it’s nice to know how to manipulate each bit of a variable.

Questions like “how do I retrieve the value of a certain bit in a variable”, “how do I set the value of a certain bit in a variable”, and “how do I flip a certain bit in a variable” can eventually be answered by twiddling around with bitwise operators in C, but often the solutions you randomly discover this way are not elegant or efficient. This afternoon I ran across the following chart on an Arduino help site and although I’m not a fan of Arduino, I can certainly appreciate the chart. I hope you find it as useful as I did.

y = (x>>n)&1;    // stores nth bit of x in y.  y becomes 0 or 1.

x&=~(1<<n);      // forces nth bit of x to be 0.  all other bits left alone.

x&=(1<<(n+1))-1;   // leaves lowest n bits of x; all higher bits set to 0.

x|=(1<<n);       // forces nth bit of x to be 1.  all other bits left alone.

x^=(1<<n);       // toggles nth bit of x.  all other bits left alone.

x=~x;              // toggles ALL the bits in x.


Jedi Soldering Skills
Posted by
Scott June 22nd, 2009 | 5,253 words | No Comments »


Scott was 23.74 years old when he wrote this!

I’m currently challenging myself by creating a microcontroller-based project a few orders of magnitude more complex than anything I’ve ever done before. Although this is probably on par with projects you might see being created by senior electrical engineering seniors, keep in mind that I have no formal training in engineering, and that my MS is in molecular biology. I just started learning about circuitry / microcontrollers a few months ago, and challenge myself to learn more by continually attacking greater and greater challenges. Here’s what I began working on last night:
layout

This if the first entry describing the creation of my non-prototype microcontroller-powered prime number generator. I made a proof of concept device a few weeks ago which calculates prime numbers (up to 2^25, about 33.5 million) and displays the results in binary form using 25 LEDs assembled in a 5×5 matrix. I added an extra column of 5 LEDs for a final matrix size of 6×5, illuminated by multiplexing through 11 IO pins of an ATMEL ATTiny2313. My new project will do the same thing, except it can calculate prime numbers up to 2^30 (over 1 billion!). Instead of only displaying 1 number, it will display 3 numbers (last prime, test number, and the divisor) using 90 LEDs. The picture above is of the main circuit board before I began soldering. The empty sockets will house a combination of 8-bit shift registers, binary-to-digital converters, and 7-segment display drivers all powered by an ATMEL ATMega8 microcontroller crystal-clocked at 10.042 MHz (arbitrary, but stable). Here’s what the underside looked like before I began soldering:
underside

I anticipate that this project will develop into a soldering nightmare. The board is nearly too small as it is, and I don’t have good wire for soldering. (I’m actually using the small wires from an old phone cord right now.) I included a potentiometer, 2 buttons, and 3 switches to aid with various settings (brightness, menus, etc). 3 Rows of LEDs (60 pins each) requires 12 shift registers (16 pins each) plus the 28-pin microcontroller makes about 400 solder points (YIKES!), so I anticipate the underside of this project will quickly grow to become a daunting mess of wires. Last night I finished the connections necessary to program the microcontroller, and for the microcontroller to control a single 8-bit shift register, allowing the first 8 LEDs of the first number to be controlled. Here’s what the soldering looked like. Remember, the dense clump of connections only controls 8 LEDs, so multiply this by more than 10 and that’s what I’ll have to do JUST to power the display.
wires

After programming with a straight-through DAPA style parallel-port programmer, I was able to shift data out to the single HC595 I had wired. I spent hours banging my head against the wall because nothing I did in the software would make the LEDs illuminate. I thought I was sending signals to the shift register wrong, or that I soldered something wrong. I finally concluded that somehow (probably when I was troubleshooting by applying 5v of power directly to the pins of the shift registers) I managed to burn out all 8 LEDs of the first light bar. I had to de-solder ALL of the connections you see in that picture, replace the bar with a new one (thank goodness I had an extra), and re-solder everything. I have a feeling that by the end of this project, I’ll be an expert at soldering. Here’s the program running controlling the first 8 bits only:
running

Supposedly the hard part is done for the display. The software was written in such a way that it will automatically begin lighting-up more LEDs as I wire them. The small node for the first shift register and 8 LEDs will be identical to the other 11, and as I solder them one by one I’ll get closer to my end goal. It will probably be many hours of soldering. In retrospect, I wish I purchased a bigger perfboard. Actually, in retrospect I wish I made a PCB!!

Update: After a few more hours (of soldering, troubleshooting, desoldering, and rewiring, and resoldering) I have my second 8-bit segment working. Note all the yellow (newly-added) wires. Multiply this by 10, and that’s what I have left to wire for the display alone!
img_2336
img_2326



Reading PCM Audio with Python
Posted by
Scott June 19th, 2009 | 5,253 words | 2 Comments »


Scott was 23.74 years old when he wrote this!

When I figured this out I figured it was simply way too easy and way to helpful to keep to myself. Here I post (for the benefit of friends, family, and random Googlers alike) two examples of super-simplistic ways to read PCM data from Python using Numpy to handle the data and Matplotlib to display it. First, get some junk audio in PCM format (test.pcm).

import numpy
data = numpy.memmap("test.pcm", dtype='h', mode='r')
print "VALUES:",data

This code prints the values of the PCM file. Output is similar to:
VALUES: [-115 -129 -130 ..., -72 -72 -72]

To graph this data, use matplotlib like so:

import numpy, pylab
data = numpy.memmap("test.pcm", dtype='h', mode='r')
print data
pylab.plot(data)
pylab.show()

This will produce a graph that looks like this:
audiograph

Could it have been ANY easier? I’m so in love with python I could cry right now. With the powerful tools Numpy provides to rapidly and efficiently analyze large arrays (PCM potential values) combined with the easy-to-use graphing tools Matplotlib provides, I’d say you can get well on your way to analyzing PCM audio for your project in no time. Good luck!

FOR MORE INFORMATION AND CODE check out the highly-relevant posts:
Linear Data Smoothing In Python
Signal Filtering With Python
Circuits Vs. Software
and pretty much anything in the DIY ECG category of entries.

Let’s get fancy and use this concept to determine the number of seconds in a 1-minute PCM file in which a radio transmission occurs. I was given a 1-minute PCM file with a ~45 second transmission in the middle. Here’s the graph of the result of the code posted below it. (Detailed descriptions are at the bottom)
secpermin
Figure description: The top trace (light blue) is the absolute value of the raw sound trace from the PCM file. The solid black line is the average (per second) of the raw audio trace. The horizontal dotted line represents the threshold, a value I selected. If the average volume for a second is above the threshold, that second is considered as “transmission” (1), if it’s below the threshold it’s “silent” (0). By graphing these 60 values in bar graph form (bottom window) we get a good idea of when the transmission starts and ends. Note that the ENTIRE graphing steps are for demonstration purposes only, and all the math can be done in the 1st half of the code. Graphing may be useful when determining the optimal threshold though. Even when the radio is silent, the microphone is a little noisy. The optimal threshold is one which would consider microphone noise as silent, but consider a silent radio transmission as a transmission.

### THIS CODE DETERMINES THE NUMBER OF SECONDS OF TRANSMISSION
### FROM A 60 SECOND PCM FILE (MAKE SURE PCM IS 60 SEC LONG!)
import numpy
threshold=80 # set this to suit your audio levels
dataY=numpy.memmap("test.pcm", dtype='h', mode='r') #read PCM
dataY=dataY-numpy.average(dataY) #adjust the sound vertically the avg is at 0
dataY=numpy.absolute(dataY) #no negative values
valsPerSec=float(len(dataY)/60) #assume audio is 60 seconds long
dataX=numpy.arange(len(dataY))/(valsPerSec) #time axis from 0 to 60
secY,secX,secA=[],[],[]
for sec in xrange(60):
    secData=dataY[valsPerSec*sec:valsPerSec*(sec+1)]
    val=numpy.average(secData)
    secY.append(val)
    secX.append(sec)
    if val>threshold: secA.append(1)
    else: secA.append(0)
print "%d sec of 60 used = %0.02f"%(sum(secA),sum(secA)/60.0)
raw_input("press ENTER to graph this junk...")

### CODE FROM HERE IS ONLY USED TO GRAPH THE DATA
### IT MAY BE USEFUL FOR DETERMINING OPTIMAL THRESHOLD
import pylab
ax=pylab.subplot(211)
pylab.title("PCM Data Fitted to 60 Sec")
pylab.plot(dataX,dataY,'b',alpha=.5,label="sound")
pylab.axhline(threshold,color='k',ls=":",label="threshold")
pylab.plot(secX,secY,'k',label="average/sec",alpha=.5)
pylab.legend()
pylab.grid(alpha=.2)
pylab.axis([None,None,-1000,10000])
pylab.subplot(212,sharex=ax)
pylab.title("Activity (Yes/No) per Second")
pylab.grid(alpha=.2)
pylab.bar(secX,secA,width=1,linewidth=0,alpha=.8)
pylab.axis([None,None,-0.5,1.5])
pylab.show()

The output of this code:46 sec of 60 used = 0.77



pySquelch – Frequency Activity Reports via Python
Posted by
Scott June 18th, 2009 | 5,253 words | No Comments »


Scott was 23.73 years old when he wrote this!

I’ve been working on the pySquelch project which is basically a method to graph frequency usage with respect to time. The code I’m sharing below listens to the microphone jack on the sound card (hooked up to a radio) and determines when transmissions begin and end. First, I’ll entice you by showing some nice graphs of the output! I ran the code below for 24 hours and this is the result…
1png
Pretty good ‘eh? This graph represents traces of the frequency activity with respect to time. The semi-transparent gray line represents the raw frequency usage in fractional minutes the frequency was tied-up by transmissions. The solid blue line represents the same data but smoothed by 10 minutes (in both directions) by the Gaussian smoothing method modified slightly from my linear data smoothing with Python page.
2png

I used the code below to generate the log, and the code further below to create the graph from the log file. Assuming your microphone is enabled and everything else is working, this software will require you to determine your own threshold for talking vs. no talking. Read the code and you’ll figure out how test your sound card settings.

If you want to try this yourself you need a Linux system (a Windows system version could be created simply by replacing getVolEach() with a Windows-based audio level detection system) with Python and the alsaaudio, numpy, and matplotlib libraries. Try running the code on your own, and if it doesn’t recognize a library “aptitude search” for it. Everything you need can be installed from packages in the common repository.

#pySquelchLogger.py
import time, random, alsaaudio, audioop
inp = alsaaudio.PCM(alsaaudio.PCM_CAPTURE,alsaaudio.PCM_NONBLOCK)
inp.setchannels(2)
inp.setrate(1000)
inp.setformat(alsaaudio.PCM_FORMAT_S8)
inp.setperiodsize(100)
addToLog=""
lastLogTime=0

testLevel=False ### SET THIS TO 'True' TO TEST YOUR SOUNDCARD

def getVolEach():
        # this is a quick way to detect activity.
        # modify this function to use alternate methods of detection.
	while True:
		l,data = inp.read() # poll the audio device
		if l>0: break
	vol = audioop.max(data,1) # get the maximum amplitude
	if testLevel: print vol
	if vol>10: return True ### SET THIS NUMBER TO SUIT YOUR NEEDS ###
	return False

def getVol():
        # reliably detect activity by getting 3 consistant readings.
	a,b,c=True,False,False
	while True:
		a=getVolEach()
		b=getVolEach()
		c=getVolEach()
		if a==b==c:
			if testLevel: print "RESULT:",a
			break
	if a==True: time.sleep(1)
	return a

def updateLog():
        # open the log file, append the new data, and save it again.
	global addToLog,lastLogTime
	#print "UPDATING LOG"
	if len(addToLog)>0:
        	f=open('log.txt','a')
        	f.write(addToLog)
        	f.close()
        	addToLog=""
	lastLogTime=time.mktime(time.localtime())

def findSquelch():
        # this will record a single transmission and store its data.
	global addToLog
	while True: # loop until we hear talking
		time.sleep(.5)
		if getVol()==True:
			start=time.mktime(time.localtime())
			print start,
			break
	while True: # loop until talking stops
		time.sleep(.1)
		if getVol()==False:
			length=time.mktime(time.localtime())-start
			print length
			break
	newLine="%d,%d "%(start,length)
	addToLog+=newLine
	if start-lastLogTime>30: updateLog() # update the log

while True:
	findSquelch()

The logging code (above) produces a log file like this (below). The values represent the start time of each transmission (in seconds since epoch) followed by the duration of the transmission.

#log.txt
1245300044,5 1245300057,4 1245300063,16 1245300094,13 1245300113,4 1245300120,14 1245300195,4 1245300295,4 1245300348,4 1245300697,7 1245300924,3 1245301157,4 1245301207,12 1245301563,4 1245302104,6 1245302114,6 1245302192,3 1245302349,4 1245302820,4 1245304812,13 1245308364,10 1245308413,14 1245312008,14 1245313953,11 1245314008,6 1245314584,4 1245314641,3 1245315212,5 1245315504,6 1245315604,13 1245315852,3 1245316255,6 1245316480,5 1245316803,3 1245316839,6 1245316848,11 1245316867,5 1245316875,12 1245316893,13 1245316912,59 1245316974,12 1245316988,21 1245317011,17 1245317044,10 1245317060,6 1245317071,7 1245317098,33 1245317140,96 1245317241,15 1245317259,14 1245317277,8 1245317298,18 1245317322,103 1245317435,40 1245317488,18 1245317508,34 1245317560,92 1245317658,29 1245317697,55 1245317755,33 1245317812,5 1245317818,7 1245317841,9 1245317865,25 1245317892,79 1245317972,30 1245318007,8 1245318021,60 1245318083,28 1245318114,23 1245318140,25 1245318167,341 1245318512,154 1245318670,160 1245318834,22 1245318859,9 1245318870,162 1245319042,57 1245319102,19 1245319123,30 1245319154,18 1245319206,5 1245319214,13 1245319229,6 1245319238,6 1245319331,9 1245319341,50 1245319397,71 1245319470,25 1245319497,40 1245319540,8 1245319551,77 1245319629,4 1245319638,36 1245319677,158 1245319837,25 1245319865,40 1245319907,33 1245319948,92 1245320043,26 1245320100,9 1245320111,34 1245320146,8 1245320159,6 1245320167,8 1245320181,12 1245320195,15 1245320212,14 1245320238,18 1245320263,46 1245320310,9 1245320326,22 1245320352,27 1245320381,15 1245320398,24 1245320425,57 1245320483,16 1245320501,40 1245320543,43 1245320589,65 1245320657,63 1245320722,129 1245320853,33 1245320889,50 1245320940,1485 1245322801,7 1245322809,103 1245322923,5 1245322929,66 1245323553,4 1245324203,15 1245324383,5 1245324570,7 1245324835,4 1245325200,8 1245325463,5 1245326414,12 1245327340,12 1245327836,4 1245327973,4 1245330006,12 1245331244,11 1245331938,11 1245332180,5 1245332187,81 1245332573,5 1245333609,12 1245334447,10 1245334924,9 1245334945,4 1245334971,4 1245335031,9 1245335076,11 1245335948,16 1245335965,27 1245335993,113 1245336107,79 1245336187,64 1245336253,37 1245336431,4 1245336588,5 1245336759,7 1245337048,3 1245337206,13 1245337228,4 1245337309,4 1245337486,6 1245337536,8 1245337565,38 1245337608,100 1245337713,25 1245337755,169 1245337930,8 1245337941,20 1245337967,6 1245337978,7 1245337996,20 1245338019,38 1245338060,127 1245338192,30 1245338227,22 1245338250,15 1245338272,15 1245338310,3 1245338508,4 1245338990,5 1245339136,5 1245339489,8 1245339765,4 1245340220,5 1245340233,6 1245340266,10 1245340278,22 1245340307,7 1245340315,28 1245340359,32 1245340395,4 1245340403,41 1245340446,46 1245340494,58 1245340554,17 1245340573,21 1245340599,3 1245340604,5 1245340611,46 1245340661,26 1245340747,4 1245340814,14 1245341043,4 1245341104,4 1245341672,4 1245341896,5 1245341906,3 1245342301,3 1245342649,6 1245342884,5 1245342929,4 1245343314,6 1245343324,10 1245343335,16 1245343353,39 1245343394,43 1245343439,62 1245343561,3 1245343790,4 1245344115,3 1245344189,5 1245344233,4 1245344241,6 1245344408,12 1245344829,3 1245345090,5 1245345457,5 1245345689,4 1245346086,3 1245347112,12 1245348006,14 1245348261,10 1245348873,4 1245348892,3 1245350303,11 1245350355,4 1245350766,5 1245350931,3 1245351605,14 1245351673,55 1245351729,23 1245351754,5 1245352123,37 1245352163,21 1245352186,18 1245352209,40 1245352251,49 1245352305,8 1245352315,5 1245352321,6 1245352329,22 1245352353,48 1245352404,77 1245352483,58 1245352543,17 1245352570,19 1245352635,5 1245352879,3 1245352899,5 1245352954,4 1245352962,6 1245352970,58 1245353031,21 1245353055,14 1245353071,52 1245353131,37 1245353170,201 1245353373,56 1245353431,18 1245353454,47 1245353502,13 1245353519,106 1245353627,10 1245353647,12 1245353660,30 1245353699,42 1245353746,28 1245353776,29 1245353806,9 1245353818,21 1245353841,10 1245353853,6 1245353862,224 1245354226,4 1245354964,63 1245355029,4 1245355036,142 1245355180,148 1245355330,7 1245355338,23 1245355363,9 1245355374,60 1245355437,142 1245355581,27 1245355609,5 1245355615,2 1245355630,64 1245355700,7 1245355709,73 1245355785,45 1245355834,85 1245355925,9 1245356234,5 1245356620,6 1245356629,12 1245356643,29 1245356676,120 1245356798,126 1245356937,62 1245357001,195 1245357210,17 1245357237,15 1245357258,24 1245357284,53 1245357339,2 1245357345,27 1245357374,76 1245357452,28 1245357482,42 1245357529,14 1245357545,35 1245357582,74 1245357661,30 1245357693,19 1245357714,38 1245357758,11 1245357777,37 1245357817,49 1245357868,19 1245357891,31 1245357931,48 1245357990,49 1245358043,24 1245358082,22 1245358108,17 1245358148,18 1245358168,7 1245358179,6 1245358186,19 1245358209,17 1245358229,5 1245358240,9 1245358252,10 1245358263,6 1245358272,9 1245358296,26 1245358328,49 1245358381,6 1245358389,38 1245358453,19 1245358476,24 1245358504,21 1245358533,76 1245358628,24 1245358653,10 1245358669,105 1245358781,20 1245358808,14 1245358836,6 1245358871,61 1245358933,0 1245358936,44 1245358982,11 1245358996,25 1245359023,15 1245359040,32 1245359076,19 1245359099,13 1245359117,16 1245359138,12 1245359161,33 1245359215,32 1245359249,14 1245359272,7 1245359314,10 1245359333,36 1245359371,21 1245359424,10 1245359447,61 1245359514,32 1245359560,42 1245359604,87 1245359700,60 1245359762,23 1245359786,4 1245359791,8 1245359803,6 1245359813,107 1245359922,29 1245359953,22 1245359978,86 1245360069,75 1245360147,22 1245360170,0 1245360184,41 1245360239,15 1245360256,34 1245360301,37 1245360339,1 1245360342,28 1245360372,20 1245360394,32 1245360440,24 1245360526,3 1245360728,3 1245361011,4 1245361026,35 1245361064,137 1245361359,5 1245362172,11 1245362225,21 1245362248,51 1245362302,20 1245362334,42 1245362418,12 1245362468,7 1245362557,9 1245362817,3 1245363175,4 1245363271,4 1245363446,3 1245363539,4 1245363573,4 1245363635,1 1245363637,3 1245363740,5 1245363875,3 1245364075,4 1245364354,14 1245364370,19 1245364391,49 1245364442,34 1245364478,23 1245364502,80 1245364633,15 1245364650,8 1245364673,16 1245364691,47 1245364739,53 1245364795,39 1245364836,25 1245365353,4 1245365640,11 1245365665,5 1245365726,8 1245365778,7 1245365982,4 1245366017,13 1245366042,6 1245366487,4 1245366493,4 1245366500,4 1245366507,3 1245366622,5 1245366690,5 1245366946,4 1245366953,16 1245366975,8 1245366996,7 1245367005,7 1245367031,6 1245367040,9 1245367051,7 1245367059,23 1245367084,76 1245367166,158 1245367740,4 1245367804,3 1245367847,4 1245367887,9 1245369300,10 1245369611,12 1245370038,10 1245370374,8 1245370668,5 1245370883,5 1245370927,7 1245370945,9 1245370961,16 1245370978,414 1245371398,135 1245371535,252 1245371791,238 1245372034,199 1245372621,4 1245372890,5 1245373043,7 1245373060,9 1245373073,6 1245373081,68 1245373151,10 1245373162,49 1245373212,79 1245373300,12 1245373313,38 1245373353,20 1245373374,59 1245373435,28 1245373465,94 1245373560,11 1245373574,53 1245373629,22 1245373654,6 1245373662,334 1245373998,169 1245374176,41 1245374219,26 1245374246,51 1245374299,31 1245374332,57 1245374391,55 1245374535,4 1245374759,7 1245374769,200 1245374971,215 1245375188,181 1245375371,81 1245375455,59 1245375516,33 1245375552,19 1245375572,56 1245375629,220 1245375850,32 1245375884,26 1245375948,7 1245375964,114 1245376473,4 1245376810,13 1245378296,10 1245378950,12 1245379004,3 1245379569,4 1245379582,4 1245379615,6 1245380030,3 1245380211,4 1245380412,14 1245380727,4 1245380850,4 

This log file is only 7.3 KB. At this rate, a years’ worth of log data can be stored in less than 3MB of plain text files. Awesome! The data presented here can be graphed (producing the image at the top of the page) using the following code:

#pySquelchGrapher.py
print "loading libraries...",
import pylab, datetime, numpy
print "complete"

def loadData(fname="log.txt"):
	print "loading data...",
	# load signal/duration from log file
	f=open(fname)
	raw=f.read()
	f.close()
	raw=raw.replace('\n',' ')
	raw=raw.split(" ")
	signals=[]
	for line in raw:
		if len(line)<3: continue
		line=line.split(',')
		sec=datetime.datetime.fromtimestamp(int(line[0]))
		dur=int(line[1])
		signals.append([sec,dur])
	print "complete"
	return signals

def findDays(signals):
	# determine which days are in the log file
	print "finding days...",
	days=[]
	for signal in signals:
		day = signal[0].date()
		if not day in days:
			days.append(day)
	print "complete"
	return days

def genMins(day):
	# generate an array for every minute in a certain day
	print "generating bins...",
	mins=[]
	startTime=datetime.datetime(day.year,day.month,day.day)
	minute=datetime.timedelta(minutes=1)
	for i in xrange(60*60):
		mins.append(startTime+minute*i)
	print "complete"
	return mins

def fillMins(mins,signals):
	print "filling bins...",
	vals=[0]*len(mins)
	dayToDo=signals[0][0].date()
	for signal in signals:
		if not signal[0].date() == dayToDo: continue
		sec=signal[0]
		dur=signal[1]
		prebuf = sec.second
		minOfDay=sec.hour*60+sec.minute
		if dur+prebuf<60: # simple case, no rollover seconds
			vals[minOfDay]=dur
		else: # if duration exceeds the minute the signal started in
			vals[minOfDay]=60-prebuf
			dur=dur+prebuf
			while (dur>0): # add rollover seconds to subsequent minutes
				minOfDay+=1
				dur=dur-60
				if dur< =0: break
				if dur>=60: vals[minOfDay]=60
				else: vals[minOfDay]=dur
	print "complete"
	return vals

def normalize(vals):
	print "normalizing data...",
	divBy=float(max(vals))
	for i in xrange(len(vals)):
		vals[i]=vals[i]/divBy
	print "complete"
	return vals

def smoothListGaussian(list,degree=10):
	print "smoothing...",
	window=degree*2-1
	weight=numpy.array([1.0]*window)
	weightGauss=[]
	for i in range(window):
		i=i-degree+1
		frac=i/float(window)
		gauss=1/(numpy.exp((4*(frac))**2))
		weightGauss.append(gauss)
	weight=numpy.array(weightGauss)*weight
	smoothed=[0.0]*(len(list)-window)
	for i in range(len(smoothed)):
	  smoothed[i]=sum(numpy.array(list[i:i+window])*weight)/sum(weight)
	while len(list)>len(smoothed)+int(window/2):
		smoothed.insert(0,smoothed[0])
	while len(list)>len(smoothed):
		smoothed.append(smoothed[0])
	print "complete"
	return smoothed

signals=loadData()
days=findDays(signals)
for day in days:
	mins=genMins(day)
	vals=normalize(fillMins(mins,signals))
	fig=pylab.figure()
	pylab.grid(alpha=.2)
	pylab.plot(mins,vals,'k',alpha=.1)
	pylab.plot(mins,smoothListGaussian(vals),'b',lw=1)
	pylab.axis([day,day+datetime.timedelta(days=1),None,None])
	fig.autofmt_xdate()
	pylab.title("147.120 MHz Usage for "+str(day))
	pylab.xlabel("time of day")
	pylab.ylabel("fractional usage")
	pylab.show()

If you have any questions, Google first, then feel free to contact me if you still can’t get it. Good luck!!



Updated pySquelch Code
Posted by
Scott June 18th, 2009 | 5,253 words | No Comments »


Scott was 24.84 years old when he wrote this!

While working to improve the python-based frequency activity logger I wrote a couple of entries back, I greatly increased its accuracy. I won’t go into the details other than saying that it simply polls the sound card a few times a second to listen for when a transmission begins and ends. The new data file format appears like this…

1245316480,5
1245316803,3
1245316839,6
1245316848,11
1245316867,5
1245316875,12
1245316893,13

The major change is that the date and time is recorded as seconds since epoch (Unix time) and the duration of the transmission is given after the comma. This greatly simplifies post-processing. Here is the revised python code to poll the sound card and generate such a log file:

##################################
##### UPDATED CODE IS IN A NEWER ENTRY #####
### CHECK THE PYTHON AND RADIO CATEGORIES ###
##################################
import time, random, alsaaudio, audioop
inp = alsaaudio.PCM(alsaaudio.PCM_CAPTURE,alsaaudio.PCM_NONBLOCK)
inp.setchannels(2)
inp.setrate(1000)
inp.setformat(alsaaudio.PCM_FORMAT_S8)
inp.setperiodsize(100)
addToLog=""
lastLogTime=0

testLevel=False ### SET THIS TO TRUE TO TEST YOUR SOUNDCARD

def getVolEach():
        # this is a quick way to detect activity.
        # modify this function to use alternate methods of detection.
	while True:
		l,data = inp.read() # poll the audio device
		if l>0: break
	vol = audioop.max(data,1) # get the maximum amplitude
	if testLevel: print vol
	if vol>10: return True ### SET THIS NUMBER TO SUIT YOUR NEEDS ###
	return False

def getVol():
        # reliably detect activity by getting 3 consistant readings.
	a,b,c=True,False,False
	while True:
		a=getVolEach()
		b=getVolEach()
		c=getVolEach()
		if a==b==c:
			if testLevel: print "RESULT:",a
			break
	if a==True: time.sleep(1)
	return a

def updateLog():
        # open the log file, append the new data, and save it again.
	global addToLog,lastLogTime
	#print "UPDATING LOG"
	if len(addToLog)>0:
        	f=open('log.txt','a')
        	f.write(addToLog)
        	f.close()
        	addToLog=""
	lastLogTime=time.mktime(time.localtime())

def findSquelch():
        # this will record a single transmission and store its data.
	global addToLog
	while True: # loop until we hear talking
		time.sleep(.5)
		if getVol()==True:
			start=time.mktime(time.localtime())
			print start,
			break
	while True: # loop until talking stops
		time.sleep(.1)
		if getVol()==False:
			length=time.mktime(time.localtime())-start
			print length
			break
	newLine="%d,%d\n"%(start,length)
	addToLog+=newLine
	if start-lastLogTime>30: updateLog() # update the log

while True:
	findSquelch()

To test the functionality of the code visually, you can use this quick and dirty method of graphing the log files output by this program. Keep in mind THIS IS NOT INTENDED TO BE USED other than to simply test the program.

##################################
##### UPDATED CODE IS IN A NEWER ENTRY #####
### CHECK THE PYTHON AND RADIO CATEGORIES ###
##################################
import pylab
import time, datetime
f=open('log.txt')
raw=f.read()
f.close()
raw=raw.split("\n")
pylab.figure()
for line in raw:
        if len(line)<5:continue
        line=line.split(",")
        sec=datetime.datetime.fromtimestamp(int(line[0]))
        dur=int(line[1])
        sec2=datetime.datetime.fromtimestamp(int(line[0])+int(line[1]))
        pylab.fill([sec,sec,sec2,sec2],[0,1,1,0],'k',lw=0,alpha=.5)
pylab.show()


UCF Tailgate June 2009
Posted by
Scott June 13th, 2009 | 5,253 words | 2 Comments »


Scott was 23.72 years old when he wrote this!

This morning I woke up at 4:45am, hopped out of bed, and raced to the university parking lot for field day. It’s pretty much a flea market with an emphasis in ham radio and associated electronics. This is a panorama of the parking lot the tailgate was held in, taken from the roof of a parking garage at about 9am. The UCF ARC (the amateur radio club which sponsored the event) is stationed under the white tent.
ucf_tailgate_2009

My goal was to purchase a [working] oscilloscope, and I lucked-out. I ended-up purchasing two, and I’m glad I did! The 1st one (the one with the green circular screen) crapped-out on me after literally 1 minute. (By crapped-out I mean it started spurring thick gray smoke and made my whole apartment smell like a burned marshmallow). At $5, I’m not crying over it. The second one is a 1969 Tektronix 561A 10 MHz oscilloscope. Just think, these things just started started being produced the same year Neil Armstrong walked on the moon. I tested it and it seems to be functioning well. At $10, I’m very happy!
scopes
The back one there is the one that died on me. The closer one works beautifully, but a lot of the knobs are staticky and there’s a lot of dirt/dust all over it. Inside it looks like a dust bomb detonated. It’ll take enough of my time to restore that I’m thinking of ignoring the older, non-working one. I don’t want to trash it, but I don’t want to store it. Maybe I’ll salvage parts from it? Hmm, vacuum tubes.
scope_box

Here you can see it attached to my prime number generator described in agonizingly-boring detail over the last several weeks’ posts. It’s attached to one of the microcontroller pins responsible for multiplexing the LED display. Finally, a way to assess high speed power output as a function of time. The output of the microcontroller isn’t performing like I expected, and since it’s a series of pulses I can’t use a volt meter to measure its output. Thus, the need [more like desire] for an oscilloscope.



Python-Powered Frequency Activity Logger
Posted by
Scott June 12th, 2009 | 5,253 words | 1 Comment »


Scott was 23.72 years old when he wrote this!

As anyone who visits this website can tell you, I’m inexplicably drawn toward inventing new ways of using Python (often in conjunction with MatPlotLib) to graphically visualize data in new ways. When I found out a fellow ham in Orlando was using his computer to stream (and serve recorded streams of) a popular local repeater frequency over the internet. I got excited because of the potential for generating [quasi-useful, and at least interesting] data from the existing setup. Since this guy already has his radio connected to his PC’s microphone jack, I figured I could write a Python app. to check the microphone input to determine if anyone is using the frequency. By recording when people start and stop talking, I can create a log of frequency activity. Later I can write software to visualize this data. I’ll talk about that in a later post. For now, here’s how I used Python and a Linux box (Ubuntu, with the python-alsaaudio package installed) to generate such logs.

We can visualize this data using some more simple Python code. Long term it would be useful to visualize frequency activity similarly to how I graphed computer usage at work over the last year but for now since I don’t have any large amount of data to work with. I’ll just write cote to visualize a QSO (conversation) with respect to time. It should be self-explanatory. This data came from data points displayed in the video (provided at the end of this post too).
qsographpng

And, of course, the code I used to generate the log files (seen running in video above): Briefly, this program checks the microphone many times every second to determine if its state has changed (talking/no talking) and records this data in a text file (which it updates every 10 seconds). Matplotlib can EASILY be used to graph data from such a text file.

##################################
##### UPDATED CODE IS IN A NEWER ENTRY #####
### CHECK THE PYTHON AND RADIO CATEGORIES ###
##################################
import alsaaudio, time, audioop, datetime
inp = alsaaudio.PCM(alsaaudio.PCM_CAPTURE,alsaaudio.PCM_NONBLOCK)
inp.setchannels(1)
inp.setrate(4000)
inp.setformat(alsaaudio.PCM_FORMAT_S16_LE)
inp.setperiodsize(1)

squelch = False
lastLog = 0
dataToLog = ""

def logIt(nowSquelch):
	global dataToLog, lastLog
	timeNow = datetime.datetime.now()
	epoch = time.mktime(timeNow.timetuple())
	if nowSquelch==True: nowSquelch=1
	else: nowSquelch=0
	logLine="%s %d\n"%(timeNow, nowSquelch)
	print timeNow, nowSquelch
	dataToLog+=logLine
	if epoch-lastLog>10:
		#print "LOGGING..."
		f=open('squelch.txt','a')
		f.write(dataToLog)
		f.close()
		lastLog = epoch
		dataToLog=""

while True:
	l,data = inp.read()
	if l:
		vol = audioop.max(data,2)
		#print vol #USED FOR CALIBRATION
		if vol>800: nowSquelch = True
		else: nowSquelch = False
		if not nowSquelch == squelch:
			logIt(nowSquelch)
			squelch = nowSquelch
	time.sleep(.01)

To use this code make sure that you’ve properly calibrated it. See the “vol>800″ line? That means that if the volume in the microphone is at least 800, it’s counted as talking, and less than it’s silence. Hopefully you can find a value that counts as silence when the squelch is active, but as talking when the squelch is broken (even if there’s silence). This is probably best achieved with the radio outputting at maximum volume. You’ll have to run the program live with that line un-commented to view the data values live. Find which values occur for squelch on/off, and pick your threshold accordingly.

After you run the code, it should output data like this:

##################################
##### UPDATED CODE IS IN A NEWER ENTRY #####
### CHECK THE PYTHON AND RADIO CATEGORIES ###
##################################
2009-06-12 17:13:28.347551 1
2009-06-12 17:13:29.306556 0
2009-06-12 17:13:30.176076 1
2009-06-12 17:13:41.533238 0
2009-06-12 17:13:45.435846 1
2009-06-12 17:14:21.890423 0
2009-06-12 17:14:25.605424 1
2009-06-12 17:14:41.904548 0
2009-06-12 17:14:43.903870 1
2009-06-12 17:14:55.981045 0
2009-06-12 17:14:59.377337 1
2009-06-12 17:15:12.365393 0
2009-06-12 17:15:15.773681 1
2009-06-12 17:15:33.165695 0
2009-06-12 17:15:36.155376 1
2009-06-12 17:16:04.181281 0
2009-06-12 17:16:07.423343 1
2009-06-12 17:16:15.724043 0
2009-06-12 17:16:18.411122 1
2009-06-12 17:16:35.304314 0
2009-06-12 17:16:36.371054 1
2009-06-12 17:16:50.818980 0
2009-06-12 17:16:53.995472 1
2009-06-12 17:17:26.675227 0
2009-06-12 17:17:29.969474 1
2009-06-12 17:17:47.907444 0
2009-06-12 17:17:50.361119 1
2009-06-12 17:18:04.630950 0
2009-06-12 17:18:05.565729 1
2009-06-12 17:18:11.225585 0
2009-06-12 17:18:14.787122 1
2009-06-12 17:18:41.261046 0
2009-06-12 17:18:43.819297 1
2009-06-12 17:18:52.164121 0
2009-06-12 17:18:53.100013 1
2009-06-12 17:19:05.348166 0
2009-06-12 17:19:09.316964 1
2009-06-12 17:19:19.107860 0
2009-06-12 17:19:19.941314 1
2009-06-12 17:19:26.254173 0
2009-06-12 17:19:33.844900 1
2009-06-12 17:19:46.501087 0
2009-06-12 17:19:49.360008 1
2009-06-12 17:19:59.917436 0
2009-06-12 17:20:04.335205 1
2009-06-12 17:20:17.622417 0
2009-06-12 17:20:18.501208 1
2009-06-12 17:20:26.866216 0
2009-06-12 17:20:28.694763 1
2009-06-12 17:20:36.097119 0

After that you can visualize the data with the following code. Note that this is SEVERELY LIMITED and is only useful when graphing a few minutes of data. I don’t have hours/days of data to work with right now, so I won’t bother writing code to graph it. This code produced the graph seen earlier in this page. Make sure matplotlib is installed on your box.

##################################
##### UPDATED CODE IS IN A NEWER ENTRY #####
### CHECK THE PYTHON AND RADIO CATEGORIES ###
##################################
import pylab

def loadData():
	#returns Xs
	import time, datetime, pylab
	f=open('good.txt')
	raw=f.readlines()
	f.close()
	onTimes=[]
	timeStart=None
	lastOn=False
	for line in raw:
		if len(line)<10: continue
		line = line.strip('\n').split(" ")
		t=line[0]+" "+line[1]
		t=t.split('.')
		thisDay=time.strptime(t[0], "%Y-%m-%d %H:%M:%S")
		e=time.mktime(thisDay)+float("."+t[1])
		if timeStart==None: timeStart=e
		if line[-1]==1: stat=True
		else: stat=False
		if not lastOn and line[-1]=="1":
			lastOn=e
		else:
			onTimes.append([(lastOn-timeStart)/60.0,\
							(e-timeStart)/60.0])
			lastOn=False
	return onTimes

times = loadData()
pylab.figure(figsize=(8,3))
for t in times:
	pylab.fill([t[0],t[0],t[1],t[1]],[0,1,1,0],'k',lw=0,alpha=.5)
pylab.axis([None,None,-3,4])
pylab.title("A little QSO")
pylab.xlabel("Time (minutes)")
pylab.show()


Prime-ary Prototype: Complete!
Posted by
Scott June 10th, 2009 | 5,253 words | No Comments »


Scott was 23.71 years old when he wrote this!

For the last several weeks I’ve been hacking together a small prototype of a microcontroller (ATTiny2313)-powered prime number generator. I can finally say that it (the prototype) is complete, functional, and elegant [get the song I'm referencing while it's up!]. The name says what it does, so I won’t waste time describing it. If you’re interested in how it does what it does, check out the other posts with the same category tag for a full (and I mean full as in “more than you ever wanted to know”) description. A schematic is soon to come. Code is below. For now, here’s a video of the completed project:

And the source code I used. I chose the ATTiny2313 because it was cheap (~$2) and has 18 IO pins to work with. I had to fight memory usage every step of the way. I’m limited to 2kb, and this program compiles within 1% of that! For future projects (more LEDs, more menus) I’ll use the 20-pin and/or 40-pin ATMega series. I’m thinking about having one be in charge of the display (multiplexing) leaving the other to think about generating prime numbers.

#define F_CPU 10240000
#include <avr/interrupt.h>
#include <util/delay.h>
#include <math.h>

// ~~~ PORT D ~~~
#define r1 0b00000100
#define r2 0b00000010
#define r3 0b00001000
#define r4 0b00100000
#define r5 0b00010000
#define f1 0b01000000
#define id 0b00000001
#define f0 0b10111111

// ~~~ PORT B ~~~
#define c1 0b00010000
#define c2 0b00000001
#define c3 0b00000010
#define c4 0b00000100
#define c5 0b00001000

char delay=1;
int redo=0;

char rows[] = {r1,r2,r3,r4,r5};
char cols[] = {c1,c2,c3,c4,c5};
char vals[] = {0,0,0,0,0};
char funcs=f1+id;
unsigned long showNum=5;//33554431;

void displayNum();
void incrimentNum();
void menu_pause();
void menuCheck();
char button();
char isPrime(unsigned long);
unsigned int twoTo(char);

int main(void) {
  DDRD = r1+r2+r3+r4+r5+f1+id;
  DDRB = c1+c2+c3+c4+c5;
  DDRB &= ~_BV(DDB7);
  PORTB = 0;
  PORTD = 0;
  unsigned int i=0;
  int j;
  //convertNum();
  //showNum=5;
  while (1) {

    showNum+=1;   

    if (isPrime(showNum)){
      convertNum();
    }

    for (j=0;j<redo;j++) {
      displayNum();
      menu();
      }
    if (i%10==0){funcs^=r1;
      funcs^=id;
      if (i%100==0){funcs^=r2;
        if (i%1000==0){funcs^=r3;i=0;
        }
      }
    }
    i++;
  }
  return 0;
}

char isPrime(unsigned long test){
  if (test%2==0) return 0;
  unsigned long div = 3;
  while(div*div<test+1){
    if (test%div==0) return 0;
    div+=2;
    displayNum();
  }
  return 1;
}

void menu(){
  //return;
  char j,but;
  but = button();
  if (but==0) return;
  else if (but==1){
    while (1) {
      PORTD=id;
      if (PINB & _BV(PB7)) {
        funcs=f1;
        for (j=0;j<200;j++){
          if (j%25==0) funcs^=r1;
          displayNum();
        }
      }
      else {
        if (redo==0) redo=200;
        else redo=0;
        _delay_ms(300);
        return;
      }
    }
  }
  return;
}

char button(){
  PORTD=id;
  if (PINB & _BV(PB7)) return 0; // not pressed
  _delay_ms(1000);
  if (PINB & _BV(PB7)) return 1; // pressed
  return 2; // held down
}

void convertNum(){
  char col,row,rowcode;
  unsigned long msk=1;
  for (col=0;col<5;col++){
    rowcode=0;
    for (row=0;row<5;row++){
      if (showNum&msk) rowcode+=rows[row];
      msk = msk < < 1;
    }
    vals[col]=rowcode;
  }
  return;
}

void displayNum(){
  char i,j;
    PORTB = 0b0;
    PORTD = funcs;
    _delay_ms(delay);
    for (i=0;i<5;i++){
      PORTD = vals[i];
      PORTB = cols[i];
      _delay_ms(delay);
    }
  return;
}


Time Prediction by Curve Fitting
Posted by
Scott June 10th, 2009 | 5,253 words | 1 Comment »


Scott was 24.84 years old when he wrote this!

I decided to crank up the power on my prime number identifier and attempt to document its efficiency in both C (GCC) and Python. I used the [very inefficient] code from the previous entry, modified it to test every integer up to 1×10^8, and let them both run on my laboratory computer overnight (an AMD Athlon 64-bit X2 Dual Core 2 GHz PC with 2GB of ram). The Python program took 3.24 processor hours, and the C program took 1.85 processor hours to complete. Each step along the way each program recorded how long it took to test the last 10,000 integers, creating a logfile with 1,000 data points, which can be easily graphed (see previous entry). On this nice, fast computer the data look very clean and curve-like. I curve-fitted the data using my new favorite website, ZunZun.com. Here’s what I came up with…
curve_fit2

Coeffecients:

### C (GCC) ###
a =  1.4193535434065586E-03
b = -1.2708466972699874E-07
c = -4.9489218065978358E-16
d =  1.3032518272036044E-11
e =  1.3231610935638881E-06

### PYTHON ###
a =  2.6579973323520396E-03
b = -2.8299592901357803E-07
c = -1.2080374779761445E-15
d =  3.0281624700595501E-11
e =  2.4778595094623538E-06

### Generating Data Points: ###
Ys=[]
for x in range(len(values)):
     Ys.append(a*(x**.5)+b*(x)+c*(x**2)+d*(x**1.5)+e)

Note that this fitted curve is the representation of how long (in seconds, vertical axis) it takes to systematically test 10,000 integers for primeness (starting at an integer on the horizontal axis), This does NOT represent how long it takes to reach a certain X. To properly calculate this, one would need to integrate the equation. This would allow for the easy prediction of how long it would take to reach a certain integer (the solution would be the integral of the provided equation from 0 to the integer). I’ll let someone else attack that. It’s time for me to get back to work!



Determining the Prime-ary Language
Posted by
Scott June 9th, 2009 | 5,253 words | No Comments »


Scott was 23.71 years old when he wrote this!

While working on my current microcontroller project I’ve become a little obsessed with the prospect of rapidly generating lists of prime numbers. I’ve been testing various strategies for speeding up the process using logic modifications to a base concept. I’ve been doing my conceptual work in Python because it’s so fast and easy to rapidly develop applications with. Now that I have a good understanding of my strategy (code scheme) of choice, I’m starting to wonder how much better the same code would run in C. It’s no secret that Python’s strength is its versatility and ease of development of scritps, not its speed. C on the other hand can be very cumbersome and awkward to develop with, but its compiled code is very efficient so it’s better suited for mathematical applications which require billions of repetitive tasks.

To visualize the speed difference between C and Python, I wrote the same prime-number-testing code in both languages and timed their output. Basically I wrote identical code in each language (variable names and functions are the same, almost a line-by-line translation) and timed how long it took to find all prime numbers up to 10,000,000. (It reported the length of runtime at every 100,000 integers, totalling 100 time points).

The results:
findingspng
The black line is code written in C and the blue line is Python. According to this output, Pythin is about 4 times slower than C at identifying primes utilizing the identical method. I’m not a coding expert, and there may be better ways to code/compile things in each language, so I’ll asy this is an indication of speed rather than a detailed, scientific study comparing the two languages. For fairness, I’ll provide my code.

Python code to generate prime numbers up to 10^7:

import time
def isPrime(testPrime):
	for div in xrange(2,int(testPrime**.5)+1):
		if testPrime%div==0: return False
	return True

def testSpeed(startAt, stopAt):
	primesFound=0
	startTime = time.clock()
	for testPrime in xrange(startAt,stopAt):
		if isPrime(testPrime):
			primesFound+=1
	s="%d,%d,%d,%fn"%(primesFound,startAt,stopAt,time.clock()-startTime)
	print s
	f=open("log_py.txt",'a')
	f.write(s)
	f.close()
	return 

for i in range(100):
	testSpeed(100000*i,100000*(i+1))
raw_input()

C code to generate prime numbers up to 10^7:

#include <stdio.h>
#include <math.h>
#include <time.h>

char isPrime(int testPrime){
     int div;
     for (div=2;div<(int)sqrt(testPrime)+1;div++){
         if (testPrime%div==0) return 0;
         }
     return 1;
     }

void testSpeed(unsigned int startAt, unsigned int stopAt){
    int primesFound=0;
	char buf[256],len;
	unsigned int testPrime;
    clock_t startTime = clock();
    for(testPrime=startAt;testPrime<stopAt;testPrime++){
        if (isPrime(testPrime)) primesFound++;
        }
	len=sprintf(buf,"n%i,%u,%u,%f",primesFound,startAt,stopAt,
		(float)(clock()-startTime)/CLOCKS_PER_SEC);
	printf("%s",buf);
	FILE *fptr = fopen("log_c.txt","a");
	fputs(buf,fptr);
	fclose(fptr);
    return;
}

int main(){
	char i;
	for (i=0;i<100;i++){
		testSpeed(100000*i,100000*(i+1));
	}
    return 0;
}

Python code to graph the difference utilizing MatPlotLib:

import pylab

def graphIt(fname,col):
	f=open(fname,'r')
	data=f.readlines()
	f.close()
	val,time=[],[]
	for line in data:
		if line.count(',')<3: continue
		line=line.strip('n').split(',')
		val.append(int(line[1]))
		time.append(float(line[3]))
	pylab.plot(val,time,color=col)
	return [val,time]

pylab.figure()
pylab.subplot(311)
v,tc=graphIt('log_c.txt','k');
v,tp=graphIt('log_py.txt','b');
pylab.title("C vs Python: test 10,000 numbers for primeness")
pylab.ylabel("time (seconds)")
pylab.xlabel("starting value")
pylab.grid(alpha=.3)
pylab.subplot(312)
pylab.grid(alpha=.3)
graphIt('log_c.txt','k');
graphIt('log_py.txt','b');
pylab.ylabel("time (seconds)")
pylab.xlabel("starting value")
pylab.semilogy()
pylab.subplot(313)
ratios=[]
for x in range(len(v)):
	ratios.append(float(tp[x])/tc[x])
pylab.plot(v,ratios,'k')
pylab.ylabel("speed ratio")
pylab.xlabel("starting value")
pylab.axis([None,None,None,5])
pylab.grid(alpha=.3)
pylab.show()


McPPNG Nearing completion
Posted by
Scott June 7th, 2009 | 5,253 words | No Comments »


Scott was 23.70 years old when he wrote this!

I don’t think I’ll keep the slang title McPPNG for my Microcontroller Powered Prime Number Generator, however I have some good news to report. I have a FULLY FUNCTIONAL prototype of this project and it looks better than I ever could have imagined, especially for the prototype. There are a few more features I want to add, and I want to work on the code some more, but I hope to be done tomorrow. I have a ton more photos taken and some videos in the works, but I’m saving them until this prototype is complete before I share it. The coolest part is that I’ve included an internal button which drives a pause/resume and speed-controller menu based upon the length of button presses! There’s a lot of awesome stuff I want to write, but once again, I’ll save it for the completed project page. Here are some pics to entice your curiosity…

Before you lose your cool about the number on the screen not being prime, calm down. I mislabeled all of the LEDs. The first LED should be 2^0 (1), and the second should be 2^1 (2), etc. Also, 2^22 and 2^23 are mislabeled – oops! But the thing really does generate, differentiate, and display [only[ prime numbers. Once again, videos (including demonstration of the menus and the programming options) and source code will be posted soon.



Code Monkey Want Cookie
Posted by
Scott June 5th, 2009 | 5,253 words | No Comments »


Scott was 23.70 years old when he wrote this!

This week has been a hectic week of ups and downs, with the stress never letting up. Work is stressful (I’m being challenged to collect representative data to write & submit two manuscripts for publication in JCN ASAP) and home is stressful. My wife and I are down to one car right now, which has no AC and pumps out heat! There’s always stuff I need to do around the house (cleaning, cooking, laundry, etc). Bills are actually getting a little intimidating since I haven’t gotten paid accurately in over a month and a half due to a payroll problem at UCF. On top of everything, I only have a few minutes here and there to devote to my microcontroller projects. When I have time to work on them, I’m rushed, and often make bad mistakes (such a yesterday when I destroyed 6 of my 2222 NPN transistors).

Thankfully, I’ve had a couple lucky breaks lately. Yesterday I finished the hardware enclosure and wiring for my microcontroller-powered prime number generator prototype. The code is sufficient to blink each of the 30 LEDs individually. When I do it fast, they all appear on. I’m golden – all I need to do to finish the [prototype] project is software side. Time to refresh myself on how to pass arrays with pointers in C! In other news, I had a little mental breakthrough this afternoon allowing me to generate prime numbers significantly more sufficiently. The screenshot below shows me identifying the 2,364,346′th prime number (38,790,019) in a little under two and a half hours. Yay! [makes dinner]
prime_screenshot

After a few hours running the code described above (writing down some time points along the way) I decided to try and visualize the curve of the rate of primes discovered with respect to time. I figured it would resemble an inverse exponential curve but it was surprisingly linear. Before I go to bed tonight I’ll re-write the code to make it automatically log time points so I can graph it in higher accuracy tomorrow. For now, this is what it looks like:
primespeedpng

As much as I’d like to toot my own horn about how fast and efficient my computational method is. The linear estimate based upon this data (an overshoot of the actual speed) suggests that it finds 10,000 prime numbers per minute. That sounds lovely, but according to my math in order to get to the 10^12′th prime (the goal) it would take 190 years. I hope I have a full battery.

The code to generate the graph (requires MatPlotLib):

data="""
112.5,2062841
141.0,2364346
168.75,2656766
177.5,2745573
214.5,3123373
232.5,3290106
247.5,3419679
256.5,3493450
"""
import pylab
x,y,fx,fy=[],[],[],[]
for line in data.split('n'):
        if not "," in line: continue
        nx,ny = line.split(",")
        x.append(float(nx))
        y.append(float(ny))
pylab.figure(figsize=(8,4))
pylab.plot(x,y,'k.-',label='real data',lw=1)
pylab.plot([x[0],x[-1]],[y[0],y[-1]],'b:',label='linear estimate')
pylab.ylabel("number of primes found")
pylab.xlabel("time (minutes)")
pylab.title("pyPrime Nth Prime Speed (bin=[2,3,5])")
pylab.legend(loc=8)
pylab.grid(alpha=.2)
pylab.show()

After letting the program run overnight using a larger prime bin (primes=[2,3,5,7]) and recording the progress every 100 bins I have a better idea of the speed (and rate of decay) of this method.
primespeedfancypng



Prime Prototype Construction
Posted by
Scott June 4th, 2009 | 5,253 words | No Comments »


Scott was 23.69 years old when he wrote this!

Now that I’ve worked-out the software side of the ATMEL microcontroller-powered prime number generator, it’s time to start working on the hardware. Mind you that this is a prototype and not the final project. This is far smaller and simpler than the final version. For starters, I’m only multiplexing 30 LEDs (the full version will have at least 80). Also, this is being run by an ATTiny2313 microcontroller, and the full version will be powered by an ATMEega8. I picked up an unfinished wooden box with a magnetic latch from Michaels. I think it’s balsa wood. It’s really delicate and tends to chip when you drill it.

I used InkScape to make the layout of the LEDs. I simply made an 8.5×11” document, measured the box lid, drew a square that size, then made some Xs on a grid. I printed it out, taped it to the top of my box, and used my uber-fancy dremel drill press to drill perfectly-aligned holes. I’m so impressed by how easy this was that I wished I used the hexagonal layout I proposed earlier! Here are some photos:

Dremel Drill Press

I used my dremel drill press to drill nice holes in the lid of the box

The template I designed in InkScape was taped onto the lid of the box so that I'd have a guide to drill the holes - it worked beautifully!

The template I designed in InkScape was taped onto the lid of the box so that I'd have a guide to drill the holes - it worked beautifully!

Holes were enlarged by a hand drill with a bit the size of the cylindrical LEDs

Holes were enlarged by a hand drill with a bit the size of the cylindrical LEDs

After LEDs were inserted I added some little support posts with screw holes in them to the base so I'd have a place to screw-on my perfboard/circuitry down the road

After LEDs were inserted I added some little support posts with screw holes in them to the base so I'd have a place to screw-on my perfboard/circuitry down the road

You can get an idea for how the finished project will look by falsely-illuminating the lEDs (they're tinted plastic after all!)

You can get an idea for how the finished project will look by falsely-illuminating the lEDs (they're tinted plastic after all!)

The circuitry controlling the display involved an ATTiny2313 microcontroller (clocked at 10.2MHz with an oscillator and two capacitors for consistancy) and some transistors controlling grounding

The circuitry controlling the display involved an ATTiny2313 microcontroller (clocked at 10.2MHz with an oscillator and two capacitors for consistancy) and some transistors controlling grounding

I included some extra wires for prototyping/debugging/programming that will be later discarded.  The chip in the breadboard (ATMega8) does nothing.

I included some extra wires for prototyping/debugging/programming that will be later discarded. The chip in the breadboard (ATMega8) does nothing.

This is what it looks like in the light...

This is what it looks like in the light...

... and in the dark

... and in the dark

my incomplete code didn't illuminate the entire display

my incomplete code didn't illuminate the entire display

So you’re pretty close to being done with the prototype, right? Yes and no. Yes in the sense that I’ve made the enclosure, basic circuitry, and basic code. No in the sense that I still have to improve the enclosure, circuitry, and code. For starters, after I took these pictures I touched the microcontroller and burned my finger!! It was running hot. I’m surprised I didn’t fry it altogether! I quickly powered it down and started inspecting the circuitry. Apparently Mr. I-got-a-masters-degree-and-am-going-to-be-a-dentist-soon doesn’t pay attention to detail [I'm losing prospective dental patients by writing this right now] and managed to wire every single one of six transistors backwards [shriek!] I guess I was pumping current out one side of the microcontroller and into the other side. Live and learn I guess. I have to go home tonight, cut all of them out (they were “permanently ghettorigged” in such a way that simple desoldering techniques will not remove them safely), find another batch of NPN transistors and solder them all in correctly.

This is the circuit concept.  The chip is an ATTiny2313, sourced with 5V, where the left pins control the columns (by providing current) and the right pins control the rows (by providing ground).  The "holes" at the top of the circuit represent where I hook up my PC and external power for testing purposes.
This is the circuit concept. The chip is an ATTiny2313, sourced with 5V, where the left pins control the columns (by providing current) and the right pins control the rows (by providing ground). The “holes” at the top of the circuit represent where I hook up my PC and external power for testing purposes.



I Wish I Weren’t Forced to Recycle
Posted by
Scott June 4th, 2009 | 5,253 words | No Comments »


Scott was 24.84 years old when he wrote this!

Being the semi-poor graduate student that I am, I have to be extremely selective what I spend my money on. Non-essential purchases (such as PIC microcontrollers, voltage regulators, wire, switches, buttons, LEDs) always take a back seat to essential purchases (such as food, rent, and ATMEL microcontrollers). Therefore, when I begin a new project, I’m forced to recycle parts from my old projects. This is the secondary reason why I don’t have any good completed projects on display at my house (the primary reason being that I never make them look pretty enough to be considered anything other than an eyesore in the first place). It’s always sad though when I begin tearing something apart. When I began making it, I thought it would be amazing! Here I am, a few months later, caring so little about it that I just want to rip it open for parts. Before I tear this guy apart (I don’t want to even describe what it does – it’s embarrassing) I took some photos so I could remember it. At least it looks pretty! Functionally, I programmed the microcontroller to blink LEDs and output sound in response to button presses. It also has a power supply circuit, which I’m harvesting in addition to the potentiometer.



Timing is Everything
Posted by
Scott June 2nd, 2009 | 5,253 words | 1 Comment »


Scott was 23.69 years old when he wrote this!

While contemplating the feasibility of my most recent project (the microcontroller-powered prime number generator featured in the previous entry) I began to wonder exactly how efficient the current design is. The same chip doing the math is also running a fairly complicated 9-layer multiplexed display. I toyed with the idea of utilizing two microcontrollers – one to handle the display, and another to be the mathematical powerhouse. Theoretically this would be a very efficient way to display data on an LCD, because all of that processing power required to send parallel data to the display could instead be devoted to calculation. However, the bottom line is that in order to accurately determine the best setup for my needs, I need to first determine what my needs are!

Here’s a simple question: “How many calculations will be required?” In other words, if I’m counting from 1 to 2^25 (33.5 million), dividing each number by every integer between 2 and its square root, by the time I get to the end how many calculations will I have run? If I can determine the speed at which the microcontroller calculates divisions I can multiply it by the number of required divisions and have an estimate of how long (years?) it will take to reach 2^25. Finally, a use for basic calculus! Let’s assume that no numbers are eliminated, and every test number is divided by each integer between 0 and its square root. Therefore the number of divisions for each test number (Phi, the squiggly line) is its square root. Summing up the square roots of Phi from 0 to 2^25 requires simple integration:
prime_euqtion

Alas! It appears that approximately 388 billion calculations are required. Let’s round down to 300 billion, considering that many of these numbers are not prime and will be excluded quickly. I know this is a rough estimation, but at least it’s numerical! Before I did the math, my only guess would be “a really big number”. Now, let’s guesstimate some efficiency. If my previous project (with the LCD screen) didn’t require parallel communication with the display and could concentrate just on the path, I’m guessing I could do 1,000 divisions a second. At that rate, 300 billion divisions would take 3472 days (9 and a half years). Yeah, I think that’ll keep me busy for a while. How awesome would it be to wait around for a decade and actually be there watching when it finishes! I wonder if it would accurately loop around to 0, or crash… I’ll have to try it to find out. Look me up in 10 years.

copyright © 2006 swharden@gmail.com