Author Archives: Jason Milldrum

Wideband Transmission #1

This is the first in a series of blog posts covering a wide variety of topics. In the past, I have used Twitter for my microblogging needs. For a variety of reasons, I'm on a Twitter hiatus right now, so I'll be using this series to convey some of the disconnected (and possibly connected) random thoughts that I feel I need to get out there. I don't think I'll be abandoning Twitter completely, but I will be reworking the ways in which I use it once I come back.

I'm also in the process of disconnecting completely from Google, so I wanted to give fair warning to those who correspond with me via my Gmail account that I will be abandoning that service very soon. I've already deleted my Google+ profile, and will be deactivating the rest shortly. I'll probably describe my rationale for this later, but keep in mind that I've been a Google customer data mine for nearly a decade, so this is not something that I undertake lightly. I'll try to get alternate contact information to those of you who regularly correspond with me.

It is an age of new beginnings.

Clackamas 2 Prototype

With the introduction out of the way, let's get down to the good stuff. Above, you can see the latest project on the Etherkit bench. It's a re-work of the receiver from the Clackamas transceiver (the rig that I submitted to the 2010 FDIM 72-part challenge). I've decided to make this receiver into a cheap & cheerful little kit to get people warmed up for building the CC1. It's currently for 40 meters only, is a superhet, and is VXO tuned (covers 7.030 MHz plus a bit more). It is 100% discrete component (you can see a TDA7052 IC above, but I've abandoned it for a different AF amp) and will be SMT construction. The receiver itself is pretty simple, but you can see there's a fair bit of other circuitry on there. That stuff is mute and sidetone circuits. It's easy enough to design a standalone receiver, but most of them will probably just gather dust after being built unless they can interface to a transmitter easily. With this extra circuitry, you can just split off your transmitter's key line and connect it to this receiver to have built-in muting and sidetone. My goal is to make this project cheap and fun to build. I'll be fast-tracking this one so I can get back to the CC1 soon.

Oddly enough, another project from the FDIM Class of 2010 is also coming out soon. As spotted on The QRPer, the Cyclone 40 transceiver is based on the rig that Dave Cripe, NM0S submitted as his 2010 FDIM 72-part challenge entry. I recall that the rig had a very unique design and that the specs were impressive. Dave's a great designer, so be sure to buy one to get a rig unlike anything else you've seen before and to support 4SQRP.

Choking off the Internet firehose that I had previously directed at me has allowed me to devote a bit more time to enjoyable activities that I've neglected, one of those being reading. I'm currently enjoying a book I've had on my shelf for a while now called Seeing in the Dark by Timothy Ferris. It's billed about being about amateur astronomers, but it does get into the professional side quite a bit as well. It's a good read and very entertaining, and I can't help but see a lot of parallels between amateur radio and amateur astronomy.

That's a great segue to the final item, which is a bit of fun from our favorite Canuck astronaut, Cmdr Hadfield. He's leaving ISS in a few days and just released a surprisingly touching (although obviously light-hearted) rendition of Space Oddity by David Bowie (one of my guilty favorites). Cmdr Hadfield may not be on the level of Neil Armstrong or Yuri Gagarin, but he's definitely making a play for Coolest Astronaut Ever.

Stuff 'n Things

As a mild winter turns into an unusually nice spring here in Beaverton (last week we had multiple days with clear skies and highs in the upper 70s °F), a young ham's thoughts turn to portable activations, Field Day, SOTA, and the like. I've been looking forward to this summer for the opportunity to take the CC1 out in the field, but I may not get to be quite as adventurous as I hoped. Last winter, I slipped in a wet patch on the concrete in the garage and hurt my knee. As a typical guy, I didn't go to the doctor to have it checked out, I decided to "walk it off". It did heal, but not completely. So I finally gave in and saw my doctor about it a few weeks ago. She strongly suspects a torn meniscus, and ordered an MRI to confirm it. Unsurprisingly, my insurance company denied coverage on the MRI, instead expecting me to do a bunch of physical therapy based on at best a guess on what the problem is. Coming from a technical background such as mine, this boggles my mind. When you have a problem and you have the tools to make a measurement, you make the measurement to see what's wrong, not just take a course of action based on a guess! I understand that money is the driving factor behind this decision, but it still seems like a waste of resources for both myself and the insurance company. Not to mention that I don't have the faith in the efficacy of physical therapy that consensus medicine does.

So now I have to decide whether to shell out beaucoup bucks on physical therapy that probably won't do anything other than siphon money from our family to their coffers. And if that fails to miraculously heal the non-specific "knee pain" referred to by the insurance company, then I guess I get the privilege of paying for the MRI that I should have had in the first place.

I'm completely fed up with politics, so I have no desire for a political battle in my comments. I'm quite aware of the history of employer-provided health insurance in the US, and the effect of government distortions in the medical marketplace. There's plenty of blame to be handed out all around, so let's just leave it at that.

Anyway, I may not get to do any SOTA summits this year (except for perhaps a super-easy one such as Cooper Mountain right on the outskirts of Beaverton), but hopefully I can at least get out with the CC1 for portable ops to the park or while camping.

Speaking of the CC1, it's at a bit of a lull in its development right now. I'm waiting for all of the beta builders to complete their construction so I can be sure that I have all of the major hardware bugs worked out (which looks tentatively promising right now). I still have quite a bit of firmware coding to work on, then I'll be ready for the next (and hopefully last) PCB spin. With any luck, that should come in about 8-10 weeks.

In the meantime, I want to work on some side projects, and perhaps some opportunities to raise more capital to fund CC1 development. In that regard, I've been looking at a neat part recently. It's a MEMS VCXO from SiTime called the SiT3808. What's cool about this part is that it has linear voltage tuning, so that you don't have the uneven tuning response like you would from a varactor-tuned VCXO. The phase noise on the spec sheet also looks very good. I ordered some samples for 7.030 MHz and 28.060 MHz and breadboarded them to test the frequency stability. It was nothing short of amazing. The 7.030 MHz part had a long term drift of 5 Hz in 1.5 hours. The 28.060 MHz part drifted only about 20 Hz in 2 hours. That's pretty spectacular for CW use.

Since the 28 MHz part was so stable, I created a QRP transmitter for it by adding on a keying circuit and a couple of BD139 amplifiers. It outputs a very clean and stable 2 watt signal and has a tuning range of about 20 kHz. I also was fairly easily able to create a TX offset circuit, so that the transmitter can be paired with a direct conversion receiver (which I plan to do soon). Since tuning is linear, the offset is the same anywhere in the tuning range, unlike a typical varactor-tuned crystal oscillator.

I've been thinking about a way to introduce these parts to the ham community, since I don't believe that I've seen them mentioned by any homebrewers or used in any kits. Last week on the qrp-tech listserv, K7QO proposed a group build of the venerable NE602/LM386 direct conversion receiver (this one from chapter 1 in Experimental Methods in RF Design). Since this design is so well known, it seems like a "remix" of this design using the SiT3808 as the local oscillator might be a fun way to spread the word about the product. I breadboarded a version with the 7.030 MHz SiT3808 sample, which you can see below (the SiT3808 is in the upper-right corner, and it obscured by the tuning pot wiring).

NE602/LM386 Prototype Receiver with SiT3808

NE602/LM386 Prototype Receiver with SiT3808

It works exactly as expected. Wide open band signals directly dumped down to baseband, and a nice, stable LO. This particular SiT3808 part number only tunes about 4 kHz, but I will be able to get parts with a greater tuning range. I'm consulting with SiTime right now about bulk pricing, and hopefully I'll be able to do a kit run of at least 100 of these bad boys in the near future. Let me know in the comments if this is something that may interest you.

So that's my big rant for the day. Stay tuned for further updates on all of these projects in the near future.

Quick Impressions of the Rigol DSA815-TG

Needing to upgrade my spectrum analysis capability, I recently sold my trusty boatanchor HP 8558B to help finance a portion of a new Rigol DSA815-TG spectrum analyzer. Last week I was able to order the 815, and today it finally showed up on my doorstep. I first came across the 815 last year, at the 2012 Dayton Hamvention. I believe that it had just been released at that time, and I don't recall hearing any buzz in the ham radio world about it. I was very intrigued by it, and vowed to look into it further. A bit later, videos of the 815 in operation started showing up on YouTube, which got me even more intrigued (there's lots of very good, detailed videos available via search). The final nail in the coffin was the product review in a recent issue of QST, which was quite favorable.

A quick overview of the banner specs include a 1.5 GHz bandwidth, standard preamp, DANL of -135 dBm, 100 Hz minimum RBW, and the -TG option includes a built-in 1.5 GHz tracking generator (an absolute must-buy). It comes in a compact, yet solid, portable enclosure; about the size of a larger portable oscilloscope. The LCD display is clear, ample, and well-backlit. The unit also has a nice variety of connectivity, including LAN, USB host, and USB device, as well as 10 MHz reference in and out.

I had a chance to briefly run it through some measurements this evening, which I'll share with you below.

This first image is a capture of a local FM broadcast station on 100.3 MHz. You can see the standard FM modulation, along with the very blocky digital HD radio subcarrier.

test

The next capture is a tracking generator sweep of a narrow CW filter that I had lying in my junkbox. It only has 3 crystals, which you can tell by the fairly shallow skirts. I was concerned that the 100 Hz minimum RBW might be too limiting for measuring narrow CW filters, but by all appearances it seems to do a good job in conjunction with the tracking generator. You can also see the very handy automatic 3 dB bandwidth marker measurement, which makes the process quick and simple.

cwfilt

Here's a sweep of a 6-crystal SSB filter that I also found in my junkbox. Again, you can see how useful the 815 can be with this type of measurement. It only takes a few moments to get this result once you get familiar with the basic functions of the 815.

ssbfilt

Finally, I paired the 815 with a homebrewed return-loss bridge so that I could make a wideband sweep of my main station ZS6BKW antenna. Here you can see return loss plot from 2 to 30 MHz. The resonances in the ham bands are quite obvious (some are indicated with markers). I never did any trimming on the antenna since I use it with an autotuner, but you can see that it came in pretty closely on the first try.

antenna

Only having used the 815 for a few hours, I'm already quite addicted to it. It's going to be a hugely useful addition to my stable of test equipment. I'm sure you'll see many measurements from the 815 in the years to come on this blog.

Fancier Minecraft Pi Game of Life

IMG_20130218_012053.jpg

I spiffed up my last bit of Minecraft Pi Edition code by making the Game of Life fit into a smaller area of the world, making the world grid and live cells easier to see (by making dead cells Obsidian and live cells Diamond Blocks), and even adding a nifty little stepped wall around the playing field. In the two photos, you can see the new Game of Life as seen from the ground inside of the playing field and hovering above it. It runs a fair amount faster now that it's only updating a 64x64 grid. Still not going to break any speed records (even from 1980) but it's a bit more fun to play with now.

IMG_20130218_011949.jpg

 

# pilife.py
#
# Jason Milldrum
# 18 Feb 2013
#
# www.nt7s.com/blog

import minecraft.minecraft as minecraft
import minecraft.block as block
import numpy
import random

mc = minecraft.Minecraft.create()

# World size in x and z axes
#worldSize = 64

# Bounds of x and z axes
negLimit = -32
posLimit = 31

# Bounds of y axis
yNegLimit = -64
yPosLimit = 64

# Y coord of Life world floor
worldFloor = 0

# Number of steps in the surrounding wall
maxWallHeight = 5

# Initialize the Life world
theWorld = numpy.zeros((posLimit - negLimit + 1, posLimit - negLimit + 1), dtype=numpy.bool)
theNextWorld = numpy.zeros((posLimit - negLimit + 1, posLimit - negLimit + 1), dtype=numpy.bool)
for x in range(posLimit - negLimit):
	for y in range(posLimit - negLimit):
		theWorld[x][y] = random.randint(0,1)

# Clear everything at the world surface and above inside the Life play area
mc.setBlocks(negLimit - (maxWallHeight * 2), worldFloor, negLimit - (maxWallHeight * 2), posLimit + (maxWallHeight * 2) - 1, yPosLimit, posLimit + (maxWallHeight * 2) - 1, block.AIR)

# Let's create stairsteps around the Life world

# Start with the +x direction
x = posLimit
stepHeight = worldFloor
# Up
while stepHeight <= maxWallHeight:
	mc.setBlocks(x, worldFloor, negLimit - stepHeight - 1, x, stepHeight, posLimit + stepHeight, block.BEDROCK)
	x += 1
	stepHeight += 1
# Down
stepHeight = maxWallHeight
while stepHeight >= worldFloor:
	mc.setBlocks(x, worldFloor, negLimit - stepHeight - 1, x, stepHeight, posLimit + stepHeight, block.BEDROCK)
	x += 1
	stepHeight -= 1

# Now the -x direction
x = negLimit - 1
stepHeight = worldFloor
# Up
while stepHeight <= maxWallHeight:
	mc.setBlocks(x, worldFloor, negLimit - stepHeight - 1, x, stepHeight, posLimit + stepHeight, block.BEDROCK)
	x -= 1
	stepHeight += 1
# Down
stepHeight = maxWallHeight
while stepHeight >= worldFloor:
	mc.setBlocks(x, worldFloor, negLimit - stepHeight - 1, x, stepHeight, posLimit + stepHeight, block.BEDROCK)
	x -= 1
	stepHeight -= 1

# Next the +z direction
z = posLimit
stepHeight = worldFloor
# Up
while stepHeight <= maxWallHeight:
	mc.setBlocks(negLimit - stepHeight - 1, worldFloor, z, posLimit + stepHeight, stepHeight, z, block.BEDROCK)
	z += 1
	stepHeight += 1
# Down
stepHeight = maxWallHeight
while stepHeight >= worldFloor:
	mc.setBlocks(negLimit - stepHeight - 1, worldFloor, z, posLimit + stepHeight, stepHeight, z, block.BEDROCK)
	z += 1
	stepHeight -= 1

# Finally the -z direction
z = negLimit - 1
stepHeight = worldFloor
# Up
while stepHeight <= maxWallHeight:
	mc.setBlocks(negLimit - stepHeight - 1, worldFloor, z, posLimit + stepHeight, stepHeight, z, block.BEDROCK)
	z -= 1
	stepHeight += 1
# Down
stepHeight = maxWallHeight
while stepHeight >= worldFloor:
	mc.setBlocks(negLimit - stepHeight - 1, worldFloor, z, posLimit + stepHeight, stepHeight, z, block.BEDROCK)
	z -= 1
	stepHeight -= 1

# Set the player right in the middle of the world
mc.player.setPos(0, worldFloor, 0)

# Main processing loop
while True:
	# Display theWorld
	for x in range(posLimit - negLimit):
		for y in range(posLimit - negLimit):
			if theWorld[x][y] == True:
				mc.setBlock(x + negLimit, worldFloor, y + negLimit, block.DIAMOND_BLOCK)
			else:
				mc.setBlock(x + negLimit, worldFloor, y + negLimit, block.OBSIDIAN)

	# Check number of neighbors alive
	for x in range(posLimit - negLimit):
		for y in range(posLimit - negLimit):
			
			if x == 0:
				xMinus = posLimit - negLimit
			else:
				xMinus = x - 1

			if x == posLimit - negLimit:
				xPlus = 0
			else:
				xPlus = x + 1

			if y == 0:
				yMinus = posLimit - negLimit
			else:
				yMinus = y - 1

			if y == posLimit - negLimit:
				yPlus = 0
			else:
				yPlus = y + 1

			alive = 0			

			if theWorld[xPlus][yPlus]:
				alive += 1
			if theWorld[x][yPlus]:
				alive += 1
			if theWorld[xMinus][yPlus]:
				alive += 1
			if theWorld[xPlus][y]:
				alive += 1
			if theWorld[xMinus][y]:
				alive += 1
			if theWorld[xPlus][yMinus]:
				alive += 1
			if theWorld[x][yMinus]:
				alive += 1
			if theWorld[xMinus][yMinus]:
				alive += 1

			# Calculate which cells live and die in next generation
			if theWorld[x][y] == False:
				if alive == 3:
					theNextWorld[x][y] = True
			else:
				if alive < 2:
					theNextWorld[x][y] = False
				elif alive > 3:
					theNextWorld[x][y] = False
				else:
					theNextWorld[x][y] = True
	# Copy array
	theWorld = theNextWorld.copy()

Conway's Game of Life in Minecraft Pi Edition

Also known as "The slowest implementation of the Game of Life in 2013". This is what happens when you have insomnia.

IMG_20130214_031548.jpg

What I did was first clear out the entire world, then place a plane of glass across the entire world at y=1. The actual Life cells are Cobblestone blocks on the y=0 plane (the grid is on the Minecraft x-z axis). The Life grid is initialized with a random seed, then set off to work. This code for the Game of Life is about the dumbest and slowest implementation there is. I've done no optimization at this point. It only updates about one generation (over the entire world) every few minutes. But it does seem to work, as you can see above.

Next time I need a break from electronics, I'll refine the code and post it again (or you can follow the Gist). It's way too slow to run the entire world as a Life simulation, so I think I'll just clear out a 64x64 space in the middle of the world and confine the world to that size, which should make things run about an order of magnitude faster, I would hope. I know, this is crap code, but I'm still trying to really get into the Python frame of mind and this was a quick hack any way.

I'll let this thing run for a while and post a screenshot of the evolved world to Twitter and G+ later on. Also, thanks to the shoutout from the new http://mcpipy.wordpress.com/ blog!

Exploring Minecraft Pi Edition

If you are a Raspberry Pi enthusiast, you may have seen that Minecraft Pi Edition was officially released yesterday. I don't have the time to game like I used to, so I haven't really played Minecraft, but this version looked intriguing since it's free and it has an open API. So I downloaded it yesterday during a break when both of the boys were napping and give it a quick run. The performance of the game is surprisingly responsive, which shows that the GPU in the Pi is fairly capable, even if stock Raspian X Windows is slow.

With a bit of digging into the very sparse API docs included with the program, and a little Internet help, I was able to get a bit of code up and running. All it does is create a sphere 10 blocks away from the player's location in the Z direction. Here's the quick and dirty code:

You can see the results in this photo:

IMG_20130212_120032.jpg

Pretty fun stuff, even if it's very basic. I know that the hardcore MC fans have already been scripting some pretty fantastic stuff in the PC version. It should be interesting to see what people do with the Pi version.

PJ2/K8ND

The Thrill of QRP DX

Last night after the rest of the family was in bed, I was hacking on the CC1 firmware to add the BFO calibration routine so that I could get an accurate readout of my receive frequency. After successfully completing that task at the late hour of 0130, I decided to cruise 40 meters to see what was going on. Normally the best time for 40 meter DX at my QTH seems to be from about 0200 or so until sunrise, so I thought I might catch something.

Scanning below 7.030 MHz, I came across a very loud station. I figured it was somebody in CONUS, but decided to listen for an ID just in case. It actually turned out to be PJ2/K8ND in Curaçao. Not exactly rare DX, but it's still quite a ways from my QTH and it's a new one for me. So I figured I would take a crack at it with the CC1. Long story short, I set the CC1 in XIT mode and after an hour of trying, my 3 watt signal finally managed to crack the JA-wall. I was pretty excited! Not exactly a heroic snag in the annals of DXing, but it was a good one for me. My single HF antenna is a ZS6BKW only up about 30 feet, so busting a 40 meter pileup to a station 6000 km away made my night. My first DX contact on the CC1! Even better, I woke up to find that the FB op uploaded his log to LoTW immediately, and I've got +1 to my DXCC count.

QRP is fun!

CC1 #1

A brief post to show you the CC1 prototype, now inside of its aluminum enclosure. This is the actual enclosure that will be used for production, but I will have the end caps custom cut and silkscreened, so you won't have to do it yourself. Pardon my questionable metalworking skills, and please note the the production tuning knob will be different (a bit smaller so as to not interfere with the LEDs). At least this will give you some idea of what the final product will look like. The dimensions of the enclosure is 70 x 100 x 29 mm (or 2.75 x 3.93 x 1.14 inches). The first photo shows a size comparison with a standard deck of cards. The weight is 190 grams (6.7 oz).

After the latest circuit tweaks, everything is looking very good with this beta test. I will have more news for the beta testers in the near future. Exciting!

CC1-40 In Enclosure

CC1-40 In Enclosure

CC1-40 Front

CC1-40 Front

CC1-40 Rear

CC1-40 Rear