The personal website of Scott W Harden

Summer's End is Nearing

My favorite summer yet is reaching its end. With about a month and a half before I begin dental school, I pause to reflect on what I've done, and what I still plan to do. Unlike previous summers where my time was devoted to academic requirements, this summer involved a 9-5 job with time to do whatever I wanted after. I made great progress in the realm of microcontroller programming, and am nearing the completion of my prime number calculator. I'm very happy with its progress.

Most of the LEDs are working but I'm still missing a few shift registers. It's not that they're missing, so much as I broke them. (D'oh!) I have to wait for a dozen more to come in the mail so I can continue this project. Shift registers are also responsible for powering the binary-to-7-segment chips on the upper left, whose sockets are currently empty.

Since this project is on pause, I began work hacking a VFD I heard about at Skycraft. It's a 20x2 character display (forgot to photograph the front) and if I can make it light up, it will be gorgeous.

Here's a high resolution photo of the back panel of the VFD. I believe it used to belong to an old cash register, and it has some digital interfacing circuitry between the driver chips (the big OKI ones) and the 9-pin input connector. I think my best bet for being able to control this guy as much as I want is to attack those driver chips, with help from the Oki C1162A datasheet. It looks fairly straightforward. As long as I don't screw up my surface-mount soldering, and assuming that I come up with 65 volts to power the thing (!) I think it's a doable project.

Prime Number Generator Schematics

Here's a 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.

Field Day 2009

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).

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. Seeing (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]

After the tents, antennas, and radios were mostly set up, everyone was exhausted. I was ready to make some contacts! I fired-up my 'ol netbook and tried communicating over 40m using psk (a digital mode), a mode I've never used, with software I've never used, on a band I've never used. It wasn't working either. I spent the first several hours in frustration because what I was trying to do wasn't working, and I couldn't figure out why. This photo was taken at the height of my frustration.

Flipping Bits in C

Bitwise programming techniques (manipulating the 1s and 0s of binary numbers) are simple, but hard to remember if you don't use them often. Recently 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 of memory to assign a whole variable to the task (the smallest variable in C is a char, and it contains 8 bits). When cramming multiple values into individual variables, it's nice to know how to manipulate each bit of a variable.

// set the Nth bit of x to 0
x &= ~(1 << n);

// set the Nth bit of x to 1
x |= (1 << n); 

// store the Nth bit of x in y (y becomes 0 or 1)
y = (x >> n) & 1; 

// leave the lowest N bits of x alone and set higher bits to 0.
x &= (1 << (n + 1)) - 1;

// toggle the Nth bit of x
x ^= (1 << n);

// toggle every bit of x
x = ~x;
⚠️ Warning: This article is obsolete.
Articles typically receive this designation when the technology they describe is no longer relevant, code provided is later deemed to be of poor quality, or the topics discussed are better presented in future articles. Articles like this are retained for the sake of preservation, but their content should be critically assessed.

Reading PCM Audio with Python

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:

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:

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)

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

page 1, page 2, page 3, page 4, page 5, page 6, page 7, page 8, page 9, page 10, page 11, page 12, page 13, page 14, page 15, page 16, page 17, page 18, page 19, page 20, page 21, page 22, page 23, page 24, page 25, page 26, page 27, page 28, page 29, page 30, page 31, page 32, page 33, page 34, page 35, page 36, page 37, page 38, page 39, page 40, page 41, page 42, page 43, page 44, page 45, page 46, page 47, page 48, page 49
All Blog Posts