Saturday, December 13, 2014

Baby monitor antenna fix

Our three year old son woke up early one morning this week. Before my wife and I were able to wake up, he had already somehow snapped the antenna casing off of his sister's baby monitor on the nightstand.

Through the course of the morning, the casing became lost in the shuffle. It's either in the garbage or somewhere in the house behind a heavy piece of furniture. I waited a few days to see if it would  turn up. For all I know it's on another planet by now. This morning I decided to make an attempt at covering up the fragile antenna wire. Some hot glue and an old pen seemed to do the trick. Here's a video of the fix:

Pretty much anything would have worked fine for fixing this, as long as it didn't conduct electricity. Conductive materials would attenuate the radio signal and decrease the range of the device. I had even considered hot gluing the antenna wire to a piece of wood, but I think this solution will make my wife happier.

This is the second time I've written about fixing baby monitors. In my other post about a different baby monitor I fixed a bad power port. The first fix was much tougher than this cheap pen trick.

If you've been following my videos or blog for a while, you might notice the antenna wire looks like a tiny coaxial co-linear. The size of the segments looks about right for the higher frequencies these monitors use. Here's an old video of me building a co-co antenna to capture ADS-B traffic. That was a fun project that worked, but I never ended up writing much about it. There's already great resources on the Internet about that if  you're interested in ADS-B and I didn't add much to what others have done.

Tuesday, December 9, 2014

Building strings in Python

The Saturday morning Python Christmas tree was fun and brought up a few interesting questions. A friend, Chris, made the comment that building strings as a list and then joining is more efficient than concatenating as you go along (like I did). I'm sitting in a room waiting for new tires to be placed on my truck, so this is a great little problem to take a look at.

Here's the code in question:

We build each line of the tree by concatenating strings together. This is a common thing to do and worthy of closer examination.

Here's an example of what I did in the Christmas tree code:
string = "" # start with a blank string
for _ in xrange(i): # make a loop
    string += " " # for each iteration of the loop, redefine the string

Here's what I think Chris recommended:
appendlist = [] # start with an empty list
for _ in xrange(i): # make a loop
  appendlist.append(" ") # append to the list
string = string.join(appendlist) # join the list into a string

As a first step, I wrote each of these and timed them using the Linux time command. By just picking random sizes of strings and timing the results, it seemed like my version was faster.

I then used Python's cProfile module to take a closer look, but wasn't able to discover anything useful with it. Plotting the two methods over a range of string lengths seemed like a logical next step and ended up making things much more clear. With a timing decorator that wrote results to csv files and another loop to iterate over a range of string lengths, I was able to create the data to make this chart:

It appears that "append as you go" does outperform "build a list" up until a point. The erratic behavior of appending to larger strings probably has to do with how memory is allocate for strings vs lists. Lists are made to grow smoothly, while strings are more difficult to allocate memory for because growing them in this manner isn't something that happens often. Even though strings can be abstracted as a list of characters, they aren't the same thing according to this. All that said, if your concatenating a string that's under 6 million characters (even on my little XPS12 laptop), it seems there's no real benefit to either method.

The work on my truck is complete, so I have to end this post. Maybe I'll pick this back up some other time and try it on different computers. If you end up looking at this, share your code or thoughts on the github repository.

Here's the code I used to generate the data for the chart which I made with OpenOffice Calc:

(thanks reddit user dangerbird2)
The better performance of += operations can be explained by optimizations in the CPython compiler. This might not hold true for other compilers (but probably does). However, the Python Style guidelines recommend against relying on compiler specific optimizations. So it's still good form to use list based string concatenation.

There's also a great reference to an article by Spolsky with a joke about a painter that illustrates the problem we'd expect to see by concatenating strings poorly.

Here's the article:

Here's the joke:
This code uses the Shlemiel the painter's algorithm. Who is Shlemiel? He's the guy in this joke:
Shlemiel gets a job as a street painter, painting the dotted lines down the middle of the road. On the first day he takes a can of paint out to the road and finishes 300 yards of the road. "That's pretty good!" says his boss, "you're a fast worker!" and pays him a kopeck.
The next day Shlemiel only gets 150 yards done. "Well, that's not nearly as good as yesterday, but you're still a fast worker. 150 yards is respectable," and pays him a kopeck.
The next day Shlemiel paints 30 yards of the road. "Only 30!" shouts his boss. "That's unacceptable! On the first day you did ten times that much work! What's going on?"
"I can't help it," says Shlemiel. "Every day I get farther and farther away from the paint can!"
If you ever hear the term "Schlemiel the Painter algorithms" this is what is being referenced.

Sunday, December 7, 2014

Leather axe sheath

Tonight I made a sheath for the axe I posted about a few days ago. Here is a picture of the completed project.

Below is a list of supplies to do this type of leather work. It's fairly straight forward once you have the basic tools and doesn't take very long for small projects like this.

Here's the steps I took:

  1. Draw your design on the leather with a pencil and cut it out.
  2. Use a hollow punch to make a hole for the first rivet. Secure the first rivet before doing the rest, this will keep everything aligned.
  3. Draw a line where you want the stitches, then follow the line with the leather stitch hole punchers.
  4. Follow the directions include with the sewing awl to insert the threads and tie it off.
  5. Place grommets.

Some lessons learned:

  • Placing the rivets before sewing was a good idea. It would be difficult to keep everything straight without them.
  • Wherever possible, leave extra leather so that the pieces can be trimmed together after the project is complete.

Although I've horded leather scraps for years, I used this stuff from Amazon and it worked fine.

Leather stitch hole punchers (my name for them). They look like this:

A sewing awl. They usually come with string.

Some small rivets.

Small gromets.

A small hollow punch set, like this. I got mine at Harbor Freight for slightly less, quality of steel isn't a big deal since we're just punching leather.

Oil to protect the leather.


Saturday, December 6, 2014

Python Christmas tree

I woke up this morning and meant to clean my office. But I ended up drinking coffee and writing this program to avoid doing that.

It works, and I learned how to record my desktop to show an animation I created by looping it in a bash command. But there are several places it can be optimized. Can you spot them? Comment on the youtube video if see the places for improvement.

# Prints a christmas tree on the terminal made up of ascending and descending integers
# 2014
import sys
import random

size = int(sys.argv[1]) # first argument is an integer which is the height of the tree
probability_green = .7 # how much of the tree will be green vs a random ornament

class colors: # colors
    purple = '\033[95m'
    blue = '\033[94m'
    green = '\033[92m'
    yellow = '\033[93m'
    red = '\033[91m'
    end = '\033[0m'
ornaments = [colors.purple,, colors.yellow,, '']
def decorate(s):
  if random.random() > probability_green:
    color = random.choice(ornaments)
    return color + str(s) + colors.end
    return + str(s) + colors.end
for i in range(1,size+1):
  line = ""
  for s in range(i, size): # this will loop over each digit left
    for c in range(0,len(str(s))): # prepend a space for each character of each digit
      line += " "
  for j in range(1,i+1):
    line += decorate(j)
  for j in range(i-1,0,-1):
    line += decorate(j)
  print line
trunk_length = 3 #TODO: if this wasn't a joke I'd make this an argument
for i in range(0, trunk_length):
  line = ""
  for s in range(1, size): # this will loop over each digit left
    for c in range(0,len(str(s))): # prepend a space for each character of each digit
      line += " "
  print line + "00"


 Getting in the spirit, a friend (Sage) sent me this bash version a few hours after I posted this.

to run: ./ 10

declare -a a=('.' '~' "'" 'O' "'" '~' '.' '*')
[[ $# = 0 ]] && s=9 || s=$1
[[ $s -gt 5 ]] || s=5
for (( w=1, r=7, n=1; n<=$s; n++ )) ; do
  for (( i=$s-n; i>0; i-- )) ;  do
    echo -n " "
  for (( i=1; i<=w; i++ )) ; do
    echo -n "${a[r]}"
    [[ $r -gt 5 ]] && r=0 || r=$r+1
  echo " "
echo " "

Update 2:
A new post to follow up on concatenating strings in python: