About an hour later, @monwarez@bsd.cafe suggested dropping the following XML in /usr/local/etc/fonts/conf.avail/29-local-noto-mono-fixup.conf and adding a symlink in ../conf.d to enable it:
<?xml version="1.0"?> <!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd"> <fontconfig> <description>Disable ligatures for monospaced fonts to avoid ff, fi, ffi, etc. becoming only one character wide</description> <match target="font"> <test name="family" compare="eq"> <string>Noto Sans Mono</string> </test> <edit name="fontfeatures" mode="append"> <string>liga off</string> <string>dlig off</string> </edit> </match> </fontconfig>
This solved my problem. Hopefully this will help others. if not, it’s a note-to-self for when I need to reapply this fixup :)
]]>About an hour later, @monwarez@bsd.cafe suggested dropping the following XML in /usr/local/etc/fonts/conf.avail/29-local-noto-mono-fixup.conf and adding a symlink in ../conf.d to enable it:
<?xml version="1.0"?> <!DOCTYPE fontconfig SYSTEM "urn:fontconfig:fonts.dtd"> <fontconfig> <description>Disable ligatures for monospaced fonts to avoid ff, fi, ffi, etc. becoming only one character wide</description> <match target="font"> <test name="family" compare="eq"> <string>Noto Sans Mono</string> </test> <edit name="fontfeatures" mode="append"> <string>liga off</string> <string>dlig off</string> </edit> </match> </fontconfig>
This solved my problem. Hopefully this will help others. if not, it’s a note-to-self for when I need to reapply this fixup :)
]]>I thought I’d setup up a similar contraption (VHF instead of HF) to see what exactly happens. I have a 1 meter long RG-8X jumper with BNC connectors, a BNC T, and a NanoVNA with a 50Ω load calibration standard.
But first, let’s analyze the situation!
Imagine you have a transmitter/signal generator and you connect it to a dummy load. Assuming ideal components, absolutely nothing would get radiated. Now, imagine inserting an open stub between the two. In other words, the T has the following connections:
Let’s do trivial math! Let’s call the total load that the generator sees and the impedance provided by the stub . The generator side of the T is connected to the other ports in parallel. Therefore:
So, when would we get a 1:1 SWR? When the generator sees a 50Ω load. When will it see 50Ω? When is very large; the extreme of which is when that side of the T is open.
If you are a ham, you may remember from when you were studying for the Amateur Extra exam that transmission line stubs can transform impedance. A 1/2 wave stub “copies” the impedance. A 1/4 wave stub “inverts” the impedance. For this “experiment” we need a high impedance. We can get that by either:
Since the “design” from the scribble called for an open, we’ll focus on the 1/2 wave open stub.
Now, back to the experiment. I have a 1 m long RG-8X which has a velocity factor of 0.78. So, let’s calculate the frequency for which it is a 1/2 wave—i.e., the frequency where the wavelength is 2 times the length of the coax:
This equals 116.9 MHz. So, we should expect 1:1 SWR at 117-ish MHz. (The cable is approximately 1 m long and the connectors and the T add some length, so it should be a bit under 117.)
Oh look! 1.015:1 SWR at 110.5 MHz.
(Using 1.058 m in the calculation yields 110.5 MHz. I totally believe that between the T and the connectors there is close to 6 cm of extra (electrical) length.)
But wait a minute, you might be saying, if high impedance is the same as an open, couldn’t we just remove the coax stub from the T and get the same result? Yes! Here’s what the NanoVNA shows with the coax disconnected:
The SWR is 1.095:1 at 110.5 MHz and is better than 1.2:1 across the whole 200 MHz! And look at that impedance! It’s about 50Ω across the whole sweep as well!
We can simplify the circuit even more: since we’re only using 2 ports of the T, we can take the T out and connect the 50Ω load to the NanoVNA directly. We just saved $3 from the bill of materials for this “antenna”!
(In case it isn’t obvious, the previous two paragraphs were dripping with sarcasm, as we just ended up with a dummy load connected to the generator/radio and called it an antenna.)
How could a dummy load transmit and receive signals? Glad you asked. In the real world we don’t use ideal components. There are small mismatches between connectors, the characteristic impedance of the coax is likely not exactly 50Ω, the coax shield is not quite 100%, the transmitter’s/generator’s output isn’t exactly 50Ω, and so on.
However, I expect all these imperfections do not amount to anything that will turn this contraption into an antenna. I bet that the ham that suggested this design used an old piece of coax which had even worse characteristics than the “within manufacturing tolerances” specs you get when the coax is new. Another option is that the coax is supposed to be connected in some non-standard way. Mindy accidentally found one as she was packing up when she disconnected the shield but not the center conductor. Either way, this would make the coax not a 1/2 wave open stub, and the resulting impedance mismatch would cause the whole setup to radiate.
I’d like to thank Mindy for posting about this design. It provided me with a fun evening “project” and a reason to write another blog post.
Finally, I’ll leave you with a photo of my experimental setup.
]]>
I thought I’d setup up a similar contraption (VHF instead of HF) to see what exactly happens. I have a 1 meter long RG-8X jumper with BNC connectors, a BNC T, and a NanoVNA with a 50Ω load calibration standard.
But first, let’s analyze the situation!
Imagine you have a transmitter/signal generator and you connect it to a dummy load. Assuming ideal components, absolutely nothing would get radiated. Now, imagine inserting an open stub between the two. In other words, the T has the following connections:
Let’s do trivial math! Let’s call the total load that the generator sees and the impedance provided by the stub . The generator side of the T is connected to the other ports in parallel. Therefore:
So, when would we get a 1:1 SWR? When the generator sees a 50Ω load. When will it see 50Ω? When is very large; the extreme of which is when that side of the T is open.
If you are a ham, you may remember from when you were studying for the Amateur Extra exam that transmission line stubs can transform impedance. A 1/2 wave stub “copies” the impedance. A 1/4 wave stub “inverts” the impedance. For this “experiment” we need a high impedance. We can get that by either:
Since the “design” from the scribble called for an open, we’ll focus on the 1/2 wave open stub.
Now, back to the experiment. I have a 1 m long RG-8X which has a velocity factor of 0.78. So, let’s calculate the frequency for which it is a 1/2 wave—i.e., the frequency where the wavelength is 2 times the length of the coax:
This equals 116.9 MHz. So, we should expect 1:1 SWR at 117-ish MHz. (The cable is approximately 1 m long and the connectors and the T add some length, so it should be a bit under 117.)
Oh look! 1.015:1 SWR at 110.5 MHz.
(Using 1.058 m in the calculation yields 110.5 MHz. I totally believe that between the T and the connectors there is close to 6 cm of extra (electrical) length.)
But wait a minute, you might be saying, if high impedance is the same as an open, couldn’t we just remove the coax stub from the T and get the same result? Yes! Here’s what the NanoVNA shows with the coax disconnected:
The SWR is 1.095:1 at 110.5 MHz and is better than 1.2:1 across the whole 200 MHz! And look at that impedance! It’s about 50Ω across the whole sweep as well!
We can simplify the circuit even more: since we’re only using 2 ports of the T, we can take the T out and connect the 50Ω load to the NanoVNA directly. We just saved $3 from the bill of materials for this “antenna”!
(In case it isn’t obvious, the previous two paragraphs were dripping with sarcasm, as we just ended up with a dummy load connected to the generator/radio and called it an antenna.)
How could a dummy load transmit and receive signals? Glad you asked. In the real world we don’t use ideal components. There are small mismatches between connectors, the characteristic impedance of the coax is likely not exactly 50Ω, the coax shield is not quite 100%, the transmitter’s/generator’s output isn’t exactly 50Ω, and so on.
However, I expect all these imperfections do not amount to anything that will turn this contraption into an antenna. I bet that the ham that suggested this design used an old piece of coax which had even worse characteristics than the “within manufacturing tolerances” specs you get when the coax is new. Another option is that the coax is supposed to be connected in some non-standard way. Mindy accidentally found one as she was packing up when she disconnected the shield but not the center conductor. Either way, this would make the coax not a 1/2 wave open stub, and the resulting impedance mismatch would cause the whole setup to radiate.
I’d like to thank Mindy for posting about this design. It provided me with a fun evening “project” and a reason to write another blog post.
Finally, I’ll leave you with a photo of my experimental setup.
]]>
So I made one.
I put together a project page which talks about the project a little bit but mostly serves to point at the source, binary files, schematic, and a manual. Since it doesn’t make sense for me to repeat myself, just go over to the project page and read more about it there ;)
Finally, this is what the finished circuit looks like:
As always, comments, suggestions, and other feedback is welcome.
]]>So I made one.
I put together a project page which talks about the project a little bit but mostly serves to point at the source, binary files, schematic, and a manual. Since it doesn’t make sense for me to repeat myself, just go over to the project page and read more about it there ;)
Finally, this is what the finished circuit looks like:
As always, comments, suggestions, and other feedback is welcome.
]]>Unfortunately, I didn’t get to participate in the BCRA June fox hunt because it conflicted with the ARRL June VHF contest. As a result, I was rather excited to participate. Just like last time, Holly joined me.
Our goals were:
We were going to keep the last goal to ourselves, but during the fox hunt check-in at 9:45am, Mindy threw some shade in our direction…so, I guess that’s the kind of game we’re playing. ;) (For the record, Marc and Mindy were accompanied by Jeremy. So, they had three hams on their team.)
This time, the two foxes were within a 5-mile radius of Church St in Swansea. I like this. A 5-mile radius is still a lot of ground to cover but avoids having to drive for a long time.
For the most part, this hunt was like the last one. I used the same Alinco handheld with the same home-built yagi. I jotted down the measured vectors on a map on my iPad. The major change since last time is the addition of a second radio—a GT-5R Baofeng handheld with a small loop antenna I threw together a few nights ago. I’m not sure how much it helped, since the Baofeng is both poorly shielded (and therefore picks up strong signals) and kind of deaf (and therefore doesn’t pick up weaker signals).
Inspecting the map while enjoying breakfast in a Dunks parking lot a couple of miles north of Fall River, we concluded that we should start the hunt near I-195 in Fall River. That way, we could quickly get to the other side of the river if it turned out that both foxes were on the other side.
(The higher resolution map resulted in my annotations being kind of small when zoomed all the way out. The ~2MB full-sized image shows them better.)
The first vectors were rather disappointing. The first fox (which we dubbed the red fox), seemed not too far away but not very close. The second fox (blue), was very weak and apparently on the other side of the river. Well, that’s what we got from the Alinco+yagi. The Baofeng+loop got nothing.
Driving to stop number two, Holly picked up a little bit of the red fox’s second transmission. This was encouraging—the loop wasn’t completely useless and hopefully we were getting closer to the fox. Unfortunately, the first and second red fox vectors disagreed a little too much. So, we drove a bit further to see which direction it would confirm.
At stop number three, we concluded that either the red fox was down near the water or somewhere on the other side of the river (but not too far past it). Recalling the back-and-forth driving we did during last year’s hunt, we decided that our next stop would be near the bridge, which should tell us which bank the fox is on.
The signal got a whole lot stronger at the fourth stop. So much so that we thought that the fox must be in or near the nearby cemetery or park. This is why you can see stops 5–8 so close together on the map. After getting a very strong signal (even with 16dB of attenuation) at stop number 8 (and not having too many convenient places to pull over) I started to circle the various blocks looking for parking lots where someone could park for the 4+ hours of the hunt to act as a fox. While I was circling, Holly was trying to use the loop antenna and looking at the map.
Soon enough, we happened onto a parking lot for a strip mall. We drove around the lot, not seeing the Jeep we were expecting. So, I pulled into a spot to regroup and get another yagi vector when I noticed that a car on the other side of parking lot had two antennas on the roof. Sure enough, it was Skip’s Jeep.
We were the third ones to find it. (I didn’t actually note down the time, but it was something like 11:15-11:25, so somewhere between an hour and hour and a half since the start.)
You can see that I stopped jotting down blue fox’s vectors after the 4th stop. That is because we concluded that it was on the other side of the river and because it was weak, it was probably far enough that we’d just continue getting essentially parallel vectors.
Next stop (#10) was Home Depot. Well, their parking lot. It is large and it is easy to get out of the car and swing the yagi around. The signal was stronger, but that’s all the new information we got. So, looking at the map, we picked a spot about halfway between the Home Depot and the edge of the 5-mile circle.
There was not a whole lot in the vicinity of stop #11, so we just pulled over on a side street. Unfortunately, due to a timing error on our behalf, we missed one transmission. So we had to wait for the next one delaying us 5 minutes. The vector we got was confusing. It pointed north, but was weaker than the Home Depot one. On a gut feeling, we chose to ignore it and continue west. Just as we were going to get into our car, we were approached by a woman who lived in the house near which we stopped. After I explained that we were doing a ham radio fox hunt, she wished us luck and headed back inside the house.
Our penultimate stop was the parking lot of a middle school in Warren. There, we got confused because we heard the blue fox transmit 2.5 minutes early, and then right on time. After briefly considering that someone was transmitting a fake fox signal, we decided to trust the vector and follow the RI-136 north, hoping to stop around the middle for another vector.
While driving up RI-136, I started looking for a good place to stop…when suddenly I noticed a blue pickup with a “BCRA” sign in the window. A quick turn into the adjacent parking lot and a little bit of parking lot hopping later, we pulled up to Kevin’s truck at 12:01. We found out that we were the second ones to find his fox, and that earlier, due to a technical issue, he transmitted off-cycle.
After chatting for a few minutes, we headed home, walked downtown, and got tasty burgers and beer.
So, to recap: we found both foxes, we found them in 2 hours and 1 minute, got to enjoy the Arlington Town Day, and last (but definitely not least) I think we wiped the floor with the KM1NDY team. ;)
Edit: Mindy wrote her own blog post about the fox hunt.
]]>Unfortunately, I didn’t get to participate in the BCRA June fox hunt because it conflicted with the ARRL June VHF contest. As a result, I was rather excited to participate. Just like last time, Holly joined me.
Our goals were:
We were going to keep the last goal to ourselves, but during the fox hunt check-in at 9:45am, Mindy threw some shade in our direction…so, I guess that’s the kind of game we’re playing. ;) (For the record, Marc and Mindy were accompanied by Jeremy. So, they had three hams on their team.)
This time, the two foxes were within a 5-mile radius of Church St in Swansea. I like this. A 5-mile radius is still a lot of ground to cover but avoids having to drive for a long time.
For the most part, this hunt was like the last one. I used the same Alinco handheld with the same home-built yagi. I jotted down the measured vectors on a map on my iPad. The major change since last time is the addition of a second radio—a GT-5R Baofeng handheld with a small loop antenna I threw together a few nights ago. I’m not sure how much it helped, since the Baofeng is both poorly shielded (and therefore picks up strong signals) and kind of deaf (and therefore doesn’t pick up weaker signals).
Inspecting the map while enjoying breakfast in a Dunks parking lot a couple of miles north of Fall River, we concluded that we should start the hunt near I-195 in Fall River. That way, we could quickly get to the other side of the river if it turned out that both foxes were on the other side.
(The higher resolution map resulted in my annotations being kind of small when zoomed all the way out. The ~2MB full-sized image shows them better.)
The first vectors were rather disappointing. The first fox (which we dubbed the red fox), seemed not too far away but not very close. The second fox (blue), was very weak and apparently on the other side of the river. Well, that’s what we got from the Alinco+yagi. The Baofeng+loop got nothing.
Driving to stop number two, Holly picked up a little bit of the red fox’s second transmission. This was encouraging—the loop wasn’t completely useless and hopefully we were getting closer to the fox. Unfortunately, the first and second red fox vectors disagreed a little too much. So, we drove a bit further to see which direction it would confirm.
At stop number three, we concluded that either the red fox was down near the water or somewhere on the other side of the river (but not too far past it). Recalling the back-and-forth driving we did during last year’s hunt, we decided that our next stop would be near the bridge, which should tell us which bank the fox is on.
The signal got a whole lot stronger at the fourth stop. So much so that we thought that the fox must be in or near the nearby cemetery or park. This is why you can see stops 5–8 so close together on the map. After getting a very strong signal (even with 16dB of attenuation) at stop number 8 (and not having too many convenient places to pull over) I started to circle the various blocks looking for parking lots where someone could park for the 4+ hours of the hunt to act as a fox. While I was circling, Holly was trying to use the loop antenna and looking at the map.
Soon enough, we happened onto a parking lot for a strip mall. We drove around the lot, not seeing the Jeep we were expecting. So, I pulled into a spot to regroup and get another yagi vector when I noticed that a car on the other side of parking lot had two antennas on the roof. Sure enough, it was Skip’s Jeep.
We were the third ones to find it. (I didn’t actually note down the time, but it was something like 11:15-11:25, so somewhere between an hour and hour and a half since the start.)
You can see that I stopped jotting down blue fox’s vectors after the 4th stop. That is because we concluded that it was on the other side of the river and because it was weak, it was probably far enough that we’d just continue getting essentially parallel vectors.
Next stop (#10) was Home Depot. Well, their parking lot. It is large and it is easy to get out of the car and swing the yagi around. The signal was stronger, but that’s all the new information we got. So, looking at the map, we picked a spot about halfway between the Home Depot and the edge of the 5-mile circle.
There was not a whole lot in the vicinity of stop #11, so we just pulled over on a side street. Unfortunately, due to a timing error on our behalf, we missed one transmission. So we had to wait for the next one delaying us 5 minutes. The vector we got was confusing. It pointed north, but was weaker than the Home Depot one. On a gut feeling, we chose to ignore it and continue west. Just as we were going to get into our car, we were approached by a woman who lived in the house near which we stopped. After I explained that we were doing a ham radio fox hunt, she wished us luck and headed back inside the house.
Our penultimate stop was the parking lot of a middle school in Warren. There, we got confused because we heard the blue fox transmit 2.5 minutes early, and then right on time. After briefly considering that someone was transmitting a fake fox signal, we decided to trust the vector and follow the RI-136 north, hoping to stop around the middle for another vector.
While driving up RI-136, I started looking for a good place to stop…when suddenly I noticed a blue pickup with a “BCRA” sign in the window. A quick turn into the adjacent parking lot and a little bit of parking lot hopping later, we pulled up to Kevin’s truck at 12:01. We found out that we were the second ones to find his fox, and that earlier, due to a technical issue, he transmitted off-cycle.
After chatting for a few minutes, we headed home, walked downtown, and got tasty burgers and beer.
So, to recap: we found both foxes, we found them in 2 hours and 1 minute, got to enjoy the Arlington Town Day, and last (but definitely not least) I think we wiped the floor with the KM1NDY team. ;)
Edit: Mindy wrote her own blog post about the fox hunt.
]]>For a long while, I was contemplating building a end-fed half-wave antenna. The draw with this type of antenna is that it has a minimal ground footprint, but it is still a full-sized antenna, so it should perform well.
Before I go any further, I should say that there is a difference between end-fed half-wave and random-wire antennas. End-fed half-waves, as the name suggests, are exactly half a wavelength long. In theory, the feed point has an infinite impedance, but in practice it is between 3 and 4kΩ. As a result, they are often fed with a 49:1 or 64:1 unun which transforms the 50Ω coax feedline impedance to about 2.5–3.2kΩ. Because the impedance is so close, it is possible to use these antennas without a tuner. Random wire antennas are also end-fed, but their length is specifically chosen to be not resonant. They are often fed with a 9:1 unun and require a tuner.
Before I ordered the parts to build my antenna (or to be more accurate, the 49:1 unun), I looked for information about this type of antenna.
I found K1RF’s slides from 2018 titled The End-Fed Half-Wave Antenna. They seem to cover pretty much everything I wanted to know about the design—namely the ferrite toroid sizing, capacitor specs, and so on.
As far as what to expect from the mechanical build, I drew inspiration from KM1NDY’s DIY 49:1 Unun Impedance Transformer For End-Fed Half Wave (EFWH) Antenna (Step-by-Step Instructions) blog post.
I ordered the items I was missing from Mouser. I could have probably saved a few dollars by hunting around on eBay, but I like the idea of receiving what I wanted instead of mis-advertised garbage…and I was going to place an order with them anyway for one of my other hobbies.
Using K1RF’s summary table (see slide 25), I targeted something between “QRP” and “QRP Plus” to make it somewhat portable. I tend to run 50-66W SSB and 15-25W digital, which is certainly on the upper end of the approximate power rating from that slide.
Namely, I went with two T140-43 toroids, 21:3 turns of #20 magnet wire, and 100pF 3kV capacitor. I used #20 magnet wire simply because I already had a spool.
Here’s the list of items for my build including prices (some of which I estimated):
Item | Qty | Price | |
Ferrite T140-43 | $2.94 | 2x | $5.88 |
Capacitor 100pF 3kV | $0.22 | 1x | $0.22 |
Type-N connector | $8.02 | 1x | $8.02 |
Magnet wire #20 | ~9’ | ~$1 | |
Assorted screws, nuts, and washers | ~$2 | ||
“Project box” | free | ||
Total | ~$17 |
For comparison, a similarly sized commercially produced 49:1 unun will easily cost between $30 and $60.
I used my favorite source for project boxes—a nearby restaurant. Many restaurants use various plastic boxes for take out orders. I love using these for various projects. Since they don’t cost me anything, I don’t care if I break it during construction or scrape it up during subsequent use.
(And yes, I’m aware, type-N connectors aren’t necessary for HF. I standardized on them to allow me to use the same coaxes for whatever band I wish without having to worry about adapters or losses.)
After the build was done, I soldered a 2.2kΩ and a 1kΩ resistor in series to use as a 1/4W dummy load for the NanoVNA. I didn’t bother doing anything fancy with the “dummy load”. I simply let it rest between the antenna terminal and the ground on the connector:
Anyway, here’s the VNA sweep from 1 MHz to 30 MHz:
Here is the complex impedance in rectangular coordinates:
Finally, the SWR is at its lowest (1.085:1) at 7.55 MHz. (Note the different x-axis range.)
Not perfect, but certainly quite usable. And for those that prefer, here’s a table with various amateur radio HF bands:
Band | Freq (MHz) | SWR | Z (Ω) | Usable? | |
160m | 1.9 | 1.321:1 | 60.4+j11.3 | yes | |
80m | 3.6 | 1.159:1 | 58-j0.03 | yes | |
60m | 5.3 | 1.111:1 | 54-j3.77 | yes | |
40m | 7.1 | 1.086:1 | 49.5-j4.08 | yes | |
30m | 10.1 | 1.166:1 | 43.3+j2.41 | yes | |
20m | 14.1 | 1.428:1 | 49.2+j17.7 | yes | |
17m | 18.1 | 2.345:1 | 82.6+j46.1 | yes | |
15m | 21.1 | 3.895:1 | 187+j35.6 | maybe | |
12m | 24.9 | 8.341:1 | 80.5-j158 | no | |
10m | 28.1 | 16.110:1 | 15.7-j99.7 | no |
Of course, this is with the 3.2kΩ dummy load. The impedances may be completely different with an actual antenna connected.
I mentioned that I went with smaller toroids to make it more portable. The whole unun weighs 161 g (that’s 5.7 funny units, or 0.36 bigger funny units).
Not super light, but it would have been much worse with 2.4" T240-43 toroids which weigh more than three times as much (106g vs. 33g per toroid).
No matter how nice the results of a bench test are, they are irrelevant. What actually matters is on-air performance. So, I packed up my FT-991A, the new unun, and the 40m 1/4 wave antenna’s radiating element (1/4 wave for 40m is the same as 1/2 for 20m) and headed to a nearby park.
I did this two days in a row.
On Saturday (August 13th), I went exclusively with FT4 running 20W. I spent about 1 hour and 12 minutes on-air and got 50 contacts all over Europe, some in North America, and a handful in South America and Africa. A very good activation! (Average: 0.7 contacts/minute)
On Sunday (August 14th), I started with SSB at 66W and later moved to FT4 at 20W. After about an hour and a half and 96 contacts, the SSB pileup kind of dried up, so I switched to FT4 for another hour and a half and another 44 contacts. On SSB, I got only US stations. On FT4, I had a mix of North America and Europe. (Average: 1.04 contacts/minute SSB, 0.5 contacts/min FT4)
Both days, I had the antenna set up as a sloper with the feedpoint (and therefore the unun) about 2 m above ground fed through 100’ of off-brand LMR-240-UF. I know that the repurposed radiating element is too long, but I’ve been too lazy to try to trim it better since the FT-991A’s tuner handles it just fine. The 100’ of coax is completely silly and 20’ would do, but I didn’t have a shorter one handy. The datasheet says that there is 1.60dB loss per 100’ at 30MHz.
With that said, here’s what the NanoVNA showed for the 20m band:
The bottom of the band has SWR of 1.34:1 and the top of the band 1.50:1. The minimum of 1.03:1 is at 13.470 MHz.
For completeness, here’s the 1–30 MHz sweep:
Even though I’ve only used the unun for little over 4 hours, I already started collecting todo items for what to check or build next. For example:
For about $17, I’m very happy with it so far.
]]>For a long while, I was contemplating building a end-fed half-wave antenna. The draw with this type of antenna is that it has a minimal ground footprint, but it is still a full-sized antenna, so it should perform well.
Before I go any further, I should say that there is a difference between end-fed half-wave and random-wire antennas. End-fed half-waves, as the name suggests, are exactly half a wavelength long. In theory, the feed point has an infinite impedance, but in practice it is between 3 and 4kΩ. As a result, they are often fed with a 49:1 or 64:1 unun which transforms the 50Ω coax feedline impedance to about 2.5–3.2kΩ. Because the impedance is so close, it is possible to use these antennas without a tuner. Random wire antennas are also end-fed, but their length is specifically chosen to be not resonant. They are often fed with a 9:1 unun and require a tuner.
Before I ordered the parts to build my antenna (or to be more accurate, the 49:1 unun), I looked for information about this type of antenna.
I found K1RF’s slides from 2018 titled The End-Fed Half-Wave Antenna. They seem to cover pretty much everything I wanted to know about the design—namely the ferrite toroid sizing, capacitor specs, and so on.
As far as what to expect from the mechanical build, I drew inspiration from KM1NDY’s DIY 49:1 Unun Impedance Transformer For End-Fed Half Wave (EFWH) Antenna (Step-by-Step Instructions) blog post.
I ordered the items I was missing from Mouser. I could have probably saved a few dollars by hunting around on eBay, but I like the idea of receiving what I wanted instead of mis-advertised garbage…and I was going to place an order with them anyway for one of my other hobbies.
Using K1RF’s summary table (see slide 25), I targeted something between “QRP” and “QRP Plus” to make it somewhat portable. I tend to run 50-66W SSB and 15-25W digital, which is certainly on the upper end of the approximate power rating from that slide.
Namely, I went with two T140-43 toroids, 21:3 turns of #20 magnet wire, and 100pF 3kV capacitor. I used #20 magnet wire simply because I already had a spool.
Here’s the list of items for my build including prices (some of which I estimated):
Item | Qty | Price | |
Ferrite T140-43 | $2.94 | 2x | $5.88 |
Capacitor 100pF 3kV | $0.22 | 1x | $0.22 |
Type-N connector | $8.02 | 1x | $8.02 |
Magnet wire #20 | ~9’ | ~$1 | |
Assorted screws, nuts, and washers | ~$2 | ||
“Project box” | free | ||
Total | ~$17 |
For comparison, a similarly sized commercially produced 49:1 unun will easily cost between $30 and $60.
I used my favorite source for project boxes—a nearby restaurant. Many restaurants use various plastic boxes for take out orders. I love using these for various projects. Since they don’t cost me anything, I don’t care if I break it during construction or scrape it up during subsequent use.
(And yes, I’m aware, type-N connectors aren’t necessary for HF. I standardized on them to allow me to use the same coaxes for whatever band I wish without having to worry about adapters or losses.)
After the build was done, I soldered a 2.2kΩ and a 1kΩ resistor in series to use as a 1/4W dummy load for the NanoVNA. I didn’t bother doing anything fancy with the “dummy load”. I simply let it rest between the antenna terminal and the ground on the connector:
Anyway, here’s the VNA sweep from 1 MHz to 30 MHz:
Here is the complex impedance in rectangular coordinates:
Finally, the SWR is at its lowest (1.085:1) at 7.55 MHz. (Note the different x-axis range.)
Not perfect, but certainly quite usable. And for those that prefer, here’s a table with various amateur radio HF bands:
Band | Freq (MHz) | SWR | Z (Ω) | Usable? | |
160m | 1.9 | 1.321:1 | 60.4+j11.3 | yes | |
80m | 3.6 | 1.159:1 | 58-j0.03 | yes | |
60m | 5.3 | 1.111:1 | 54-j3.77 | yes | |
40m | 7.1 | 1.086:1 | 49.5-j4.08 | yes | |
30m | 10.1 | 1.166:1 | 43.3+j2.41 | yes | |
20m | 14.1 | 1.428:1 | 49.2+j17.7 | yes | |
17m | 18.1 | 2.345:1 | 82.6+j46.1 | yes | |
15m | 21.1 | 3.895:1 | 187+j35.6 | maybe | |
12m | 24.9 | 8.341:1 | 80.5-j158 | no | |
10m | 28.1 | 16.110:1 | 15.7-j99.7 | no |
Of course, this is with the 3.2kΩ dummy load. The impedances may be completely different with an actual antenna connected.
I mentioned that I went with smaller toroids to make it more portable. The whole unun weighs 161 g (that’s 5.7 funny units, or 0.36 bigger funny units).
Not super light, but it would have been much worse with 2.4" T240-43 toroids which weigh more than three times as much (106g vs. 33g per toroid).
No matter how nice the results of a bench test are, they are irrelevant. What actually matters is on-air performance. So, I packed up my FT-991A, the new unun, and the 40m 1/4 wave antenna’s radiating element (1/4 wave for 40m is the same as 1/2 for 20m) and headed to a nearby park.
I did this two days in a row.
On Saturday (August 13th), I went exclusively with FT4 running 20W. I spent about 1 hour and 12 minutes on-air and got 50 contacts all over Europe, some in North America, and a handful in South America and Africa. A very good activation! (Average: 0.7 contacts/minute)
On Sunday (August 14th), I started with SSB at 66W and later moved to FT4 at 20W. After about an hour and a half and 96 contacts, the SSB pileup kind of dried up, so I switched to FT4 for another hour and a half and another 44 contacts. On SSB, I got only US stations. On FT4, I had a mix of North America and Europe. (Average: 1.04 contacts/minute SSB, 0.5 contacts/min FT4)
Both days, I had the antenna set up as a sloper with the feedpoint (and therefore the unun) about 2 m above ground fed through 100’ of off-brand LMR-240-UF. I know that the repurposed radiating element is too long, but I’ve been too lazy to try to trim it better since the FT-991A’s tuner handles it just fine. The 100’ of coax is completely silly and 20’ would do, but I didn’t have a shorter one handy. The datasheet says that there is 1.60dB loss per 100’ at 30MHz.
With that said, here’s what the NanoVNA showed for the 20m band:
The bottom of the band has SWR of 1.34:1 and the top of the band 1.50:1. The minimum of 1.03:1 is at 13.470 MHz.
For completeness, here’s the 1–30 MHz sweep:
Even though I’ve only used the unun for little over 4 hours, I already started collecting todo items for what to check or build next. For example:
For about $17, I’m very happy with it so far.
]]>I went through my collection of random components and found one 555 timer chip—specifically a TS555CN. I played with it on a breadboard and very quickly concluded that I should have more than just one. Disappointingly, sometime over the past 25 years, STM stopped making TS555 in DIP packages, so I ordered NA555PE4s thinking that they should be similar enough.
When they arrived, I tried to make use of them but I quickly noticed that their output seemed…weird. I tweeted about it and then tweeted some more. I concluded that precision 555s just weren’t fundamental enough to most circuits using DIP packages, and that I would have to make do with the NA555 parts.
Fast forward a few months, and I noticed ICM7555IPAZ on Mouser. The datasheet made it look a lot like the TS555…so I bought one to benchmark.
I went with a very simple astable multivibrator configuration—the same one that every 555 datasheet includes:
R1, R2 | 1kΩ |
C1 | 220nF |
C2 | 0.01μF |
C3 | 10μF |
The TS555 datasheet suggested 0.01μF for C2, and it didn’t seem to harm the other two chips so I went with it.
The NA555 datasheet suggested 0.01μF for C3. That cleaned up the rising edge slightly for TS555 and ICM7555. NA555’s rising edge actually became an edge instead of a huge mess, however it still seemed to be limited so I went with a bigger decoupling capacitor—namely 10μF. That didn’t seem to harm the other two chips.
Finally, note that the output is completely unloaded. I figure that this is reasonable since there are plenty of high input impedance loads that the 555 output could feed into. (A quick sanity check with a 1kΩ resitor to ground shows that the output voltage drops by about a volt, but the general shape of the wave doesn’t change.)
I assembled it on a breadboard with plenty of space for my fingers to swap out the chip:
The orange and red wires go to +5V and the black one goes to ground. All 3 are plugged in just right of the decoupling capacitor (off image).
Looking at the three datasheets, they all provide the same (or slightly rearranged) formulas for the frequency and duty cycle. Since I used 1kΩ for the two resistors and 220nF for the capacitor, I should be seeing:
and duty cycle:
or 66.67%
Because I used a breadboard, there is some amount of stray capacitance which likely shifts the frequency a bit. Based on previous experience, that shouldn’t be too much of an issue.
I supplied the circuit with a power supply set to 5V and 0.2A. (It operated in constant-voltage mode the entire time.)
Unlike some of my previous experiments, I actually tried to get a nice clean measurement this time. I used the probe grounding spring to get a short ground and measured between pin 1 and 3 (ground and output, respectively).
Let’s look at the amplitude, frequency, duty cycle, and rise time of the three chips. I took screenshots of the scope as I was performing the various measurements. To make it easier to compare them, I made combined/overlayed images and tweaked the colors. This makes the UI elements in the screenshot look terrible, but it is trivial to see how the chips compare at a glance. In the combined images TS555 is always yellow, NA555 is cyan, and ICM7555 is magenta.
(Individual screenshots: NA555, TS555, ICM7555)
It is easy to see that the output of both TS555 and ICM7555 goes to (and stays at) 5V. The NA555 spikes to 5V during the transition, but then decays to 4.5V. More on this later.
Similarly, it is easy to see that the TS555 and NA555 have a very similar positive cycle time but different enough negative cycle time that their frequencies and duty cycle will be different.
TS555 got close with the frequency (2.20 kHz) while NA555 got close with the duty cycle (65.75%). ICM7555 was the worst of the bunch with 2.28 kHz and 63.23% duty cycle.
(Individual screenshots: NA555, TS555, ICM7555)
The NA555 has a comparatively awful rise time of 74.88 ns. The TS555 appears to be a speed demon clocking in at 18.69 ns. Finally, the ICM7555 appears to split the difference with 41.91 ns.
I still think that it is amazing that a relatively inexpensive scope (like the Siglent SDS 1104X-E used for these measurements) can visualize signal changes on nanosecond scales.
In a way, looking at the amplitude is what got me into this evaluation—specifically, the strange output voltage on the NA555 chip. Let’s take a look at the first microsecond following a positive edge.
(Individual screenshots: NA555, TS555, ICM7555)
After the somewhat leisurely rise time of ~75 ns, the output stays near 5V for about 200 ns, before dipping down to about 3.75V for almost 200 ns and then recovering to about 4.5V over the next 400 ns. The output stays at 4.5V until the negative edge.
This is weird and I don’t have any answers for why this happens. I tried a handful of the NA555s (all likely from the same batch), and they all exhibit this behavior.
As I mentioned in the introduction, I didn’t follow the NA555’s decoupling capacitor suggestion. I wasn’t planning on writing this section, but I think that it is interesting to see just how much the output changes as the decoupling capacitor is varied.
As before, I made combined/overlayed images for easier comparison. This time, yellow is no decoupling capacitor, magenta is 0.01μF (suggested by the NA555 datasheet), cyan is 0.1μF, and green is 10μF (used in chip comparison circuit).
(Individual screenshots: no cap, 0.01μF, 0.1μF, 10μF)
As you can see, not having a decoupling capacitor makes the output voltage go to nearly 7V in a circuit with a 5V supply. Adding the suggested 0.01μ certainly makes things better (the peak is at about 5.8V) but it looks like the chip is still struggling to deal with the transient. Using 0.1μF or more results in approximately the same waveform with a peak just around 5V.
The suggested 0.01μF has another problem in my circuit. It makes the NA555’s output ring:
(Individual screenshots: no cap, 0.01μF, 0.1μF, 10μF)
Neither the TS555 nor the ICM7555 have this issue. They are both quite happy with a 0.01μF capacitor. Without any capacitor, they have a little bit of a ring around 5V (1.2Vpp for TS555, 200mVpp for ICM7555) but it subsides promptly. The ICM7555’s ringing is so minor, that it probably isn’t worth it to even use a decoupling capacitor.
I’ve collected the various measurements from the screenshots and put them into the following table:
Calculated | TS555CN | NA555PE4 | ICM7555IPAZ | |
f (kHz) | 2.182 | 2.20 (+0.8%) | 2.24 (+2.7%) | 2.28 (+4.4%) |
D (%) | 66.67 | 64.68 (-3.0%) | 65.75 (-1.4%) | 63.23 (-5.2%) |
Rise (ns) | — | 18.69 | 74.88 | 41.91 |
Logic high peak (V) | 5 | 5.08 | 5.12 | 5.08 |
Logic high steady state (V) | 5 | 5.08 | ~4.5 | 5.08 |
So, what does this all mean? Ultimately, not a whole lot. The 555 is a versatile chip, but not a magical one. Despite what the NA555 datasheet says, the 555 is not a precision device by modern standards, but it is still an easy way to get a square(-ish) wave around the desired frequency.
With that said, not all 555s are created equal.
The NA555 with all its flaws still works well enough and has a low price. So, for any sort of “crude” timing, it should work well. If, however, the circuit making use of the timer output requires a cleaner signal, then I’d reach for something better.
The ICM7555 is very good. It produces a nice clean output with reasonably fast edges, but not as fast as the TS555. Unfortunately, the performance costs extra—an ICM7555 is about twice the cost of a NA555.
All things being equal, the TS555 and ICM7555 are on par. One has a faster edge, the other has less ringing (and is still actively manufactured). I’ll save the TS555 for future benchmarks. Depending on the application, I’ll either use a NA555 or ICM7555.
]]>I went through my collection of random components and found one 555 timer chip—specifically a TS555CN. I played with it on a breadboard and very quickly concluded that I should have more than just one. Disappointingly, sometime over the past 25 years, STM stopped making TS555 in DIP packages, so I ordered NA555PE4s thinking that they should be similar enough.
When they arrived, I tried to make use of them but I quickly noticed that their output seemed…weird. I tweeted about it and then tweeted some more. I concluded that precision 555s just weren’t fundamental enough to most circuits using DIP packages, and that I would have to make do with the NA555 parts.
Fast forward a few months, and I noticed ICM7555IPAZ on Mouser. The datasheet made it look a lot like the TS555…so I bought one to benchmark.
I went with a very simple astable multivibrator configuration—the same one that every 555 datasheet includes:
R1, R2 | 1kΩ |
C1 | 220nF |
C2 | 0.01μF |
C3 | 10μF |
The TS555 datasheet suggested 0.01μF for C2, and it didn’t seem to harm the other two chips so I went with it.
The NA555 datasheet suggested 0.01μF for C3. That cleaned up the rising edge slightly for TS555 and ICM7555. NA555’s rising edge actually became an edge instead of a huge mess, however it still seemed to be limited so I went with a bigger decoupling capacitor—namely 10μF. That didn’t seem to harm the other two chips.
Finally, note that the output is completely unloaded. I figure that this is reasonable since there are plenty of high input impedance loads that the 555 output could feed into. (A quick sanity check with a 1kΩ resitor to ground shows that the output voltage drops by about a volt, but the general shape of the wave doesn’t change.)
I assembled it on a breadboard with plenty of space for my fingers to swap out the chip:
The orange and red wires go to +5V and the black one goes to ground. All 3 are plugged in just right of the decoupling capacitor (off image).
Looking at the three datasheets, they all provide the same (or slightly rearranged) formulas for the frequency and duty cycle. Since I used 1kΩ for the two resistors and 220nF for the capacitor, I should be seeing:
and duty cycle:
or 66.67%
Because I used a breadboard, there is some amount of stray capacitance which likely shifts the frequency a bit. Based on previous experience, that shouldn’t be too much of an issue.
I supplied the circuit with a power supply set to 5V and 0.2A. (It operated in constant-voltage mode the entire time.)
Unlike some of my previous experiments, I actually tried to get a nice clean measurement this time. I used the probe grounding spring to get a short ground and measured between pin 1 and 3 (ground and output, respectively).
Let’s look at the amplitude, frequency, duty cycle, and rise time of the three chips. I took screenshots of the scope as I was performing the various measurements. To make it easier to compare them, I made combined/overlayed images and tweaked the colors. This makes the UI elements in the screenshot look terrible, but it is trivial to see how the chips compare at a glance. In the combined images TS555 is always yellow, NA555 is cyan, and ICM7555 is magenta.
(Individual screenshots: NA555, TS555, ICM7555)
It is easy to see that the output of both TS555 and ICM7555 goes to (and stays at) 5V. The NA555 spikes to 5V during the transition, but then decays to 4.5V. More on this later.
Similarly, it is easy to see that the TS555 and NA555 have a very similar positive cycle time but different enough negative cycle time that their frequencies and duty cycle will be different.
TS555 got close with the frequency (2.20 kHz) while NA555 got close with the duty cycle (65.75%). ICM7555 was the worst of the bunch with 2.28 kHz and 63.23% duty cycle.
(Individual screenshots: NA555, TS555, ICM7555)
The NA555 has a comparatively awful rise time of 74.88 ns. The TS555 appears to be a speed demon clocking in at 18.69 ns. Finally, the ICM7555 appears to split the difference with 41.91 ns.
I still think that it is amazing that a relatively inexpensive scope (like the Siglent SDS 1104X-E used for these measurements) can visualize signal changes on nanosecond scales.
In a way, looking at the amplitude is what got me into this evaluation—specifically, the strange output voltage on the NA555 chip. Let’s take a look at the first microsecond following a positive edge.
(Individual screenshots: NA555, TS555, ICM7555)
After the somewhat leisurely rise time of ~75 ns, the output stays near 5V for about 200 ns, before dipping down to about 3.75V for almost 200 ns and then recovering to about 4.5V over the next 400 ns. The output stays at 4.5V until the negative edge.
This is weird and I don’t have any answers for why this happens. I tried a handful of the NA555s (all likely from the same batch), and they all exhibit this behavior.
As I mentioned in the introduction, I didn’t follow the NA555’s decoupling capacitor suggestion. I wasn’t planning on writing this section, but I think that it is interesting to see just how much the output changes as the decoupling capacitor is varied.
As before, I made combined/overlayed images for easier comparison. This time, yellow is no decoupling capacitor, magenta is 0.01μF (suggested by the NA555 datasheet), cyan is 0.1μF, and green is 10μF (used in chip comparison circuit).
(Individual screenshots: no cap, 0.01μF, 0.1μF, 10μF)
As you can see, not having a decoupling capacitor makes the output voltage go to nearly 7V in a circuit with a 5V supply. Adding the suggested 0.01μ certainly makes things better (the peak is at about 5.8V) but it looks like the chip is still struggling to deal with the transient. Using 0.1μF or more results in approximately the same waveform with a peak just around 5V.
The suggested 0.01μF has another problem in my circuit. It makes the NA555’s output ring:
(Individual screenshots: no cap, 0.01μF, 0.1μF, 10μF)
Neither the TS555 nor the ICM7555 have this issue. They are both quite happy with a 0.01μF capacitor. Without any capacitor, they have a little bit of a ring around 5V (1.2Vpp for TS555, 200mVpp for ICM7555) but it subsides promptly. The ICM7555’s ringing is so minor, that it probably isn’t worth it to even use a decoupling capacitor.
I’ve collected the various measurements from the screenshots and put them into the following table:
Calculated | TS555CN | NA555PE4 | ICM7555IPAZ | |
f (kHz) | 2.182 | 2.20 (+0.8%) | 2.24 (+2.7%) | 2.28 (+4.4%) |
D (%) | 66.67 | 64.68 (-3.0%) | 65.75 (-1.4%) | 63.23 (-5.2%) |
Rise (ns) | — | 18.69 | 74.88 | 41.91 |
Logic high peak (V) | 5 | 5.08 | 5.12 | 5.08 |
Logic high steady state (V) | 5 | 5.08 | ~4.5 | 5.08 |
So, what does this all mean? Ultimately, not a whole lot. The 555 is a versatile chip, but not a magical one. Despite what the NA555 datasheet says, the 555 is not a precision device by modern standards, but it is still an easy way to get a square(-ish) wave around the desired frequency.
With that said, not all 555s are created equal.
The NA555 with all its flaws still works well enough and has a low price. So, for any sort of “crude” timing, it should work well. If, however, the circuit making use of the timer output requires a cleaner signal, then I’d reach for something better.
The ICM7555 is very good. It produces a nice clean output with reasonably fast edges, but not as fast as the TS555. Unfortunately, the performance costs extra—an ICM7555 is about twice the cost of a NA555.
All things being equal, the TS555 and ICM7555 are on par. One has a faster edge, the other has less ringing (and is still actively manufactured). I’ll save the TS555 for future benchmarks. Depending on the application, I’ll either use a NA555 or ICM7555.
]]>This was my first fox hunt of any kind. To improve the chances of success I teamed up with KM1NDY and AA1F. They participated in at least one BCRA fox hunt before, so they knew what to expect. (You can read KM1NDY’s thoughts about the hunt on her blog.)
The “parameters” of the hunt were simple: find the transmitter transmitting every 5 minutes from somewhere within 5 miles of exit 13 on MA 24.
Everyone likes to talk about gear, but at least in my opinion it is much more important to have a good strategy than to invest in specialized gear. That idea, combined with not knowing whether I’d like fox hunting or not, meant that I was going to use what I already owned. That meant WA5VJB’s cheap yagi and an Alinco DJ-G7 handheld. As far as non-radio gear is concerned, I brought my iPad to use for an annotated map.
I already talked about the antenna in my ARRL June VHF contest writeup, so I won’t repeat myself here. I got the Alinco handheld because I wanted a handheld with a third band. That narrowed my options down a lot. Since I heard good things about the Alinco and having a 1.2 GHz capability seemed cool, I went with it, even though the Boston area doesn’t have any sort of 1.2 GHz activity.
We decided to meet up at Massasoit State Park. That made it easy for me to do a POTA/WWFF activation after the hunt.
My co-conspirators were running a bit late, so I got to make the first “measurement” from the park parking lot alone. You can see it on the map labeled as #1:
As you can see, I went relatively low-tech on the map annotation. I just took a screenshot of a reasonably zoomed map and hand-drew the 5 mile circle. Then, during the hunt itself, I just eyeballed the direction of each measurement and noted it down.
When KM1NDY and AA1F arrived at the park, I shared with them my measurement. After a brief discussion about where to go next, I hopped into their car and we headed west to get back to the highway.
I won’t bore you with turn by turn retelling of the whole trip. I will, however, mention a few observations. In no particular order:
Between this and the previous BCRA fox hunt, I got a chance to do some on-foot fox hunting thanks to K1MJC who hid a fox several times in nearby Waltham. This time, I decided to try the hunt by myself (well, with Holly) and left KM1NDY and AA1F to fend for themselves—or “once our partner and now our competitor” as KM1NDY put it in her writeup.
This was a bigger hunt. The radius was 10 miles centered on the Veterans Memorial Bridge in Fall River and there were two transmitters!
Given the size, I decided to make a better blank map. I stitched together a couple of screenshots and then drew 5 mile and 10 mile circles. This turned out to be mostly useless since both foxes were within the 5 mile circle and we hadn’t even picked them up before entering the inner circle. Just look at the annotated map:
I didn’t even bother to try to capture all the information on this map because of how close everything was. When I got home, I ended up redrawing the map to show all the detail based on the above map, notes I made on the side, and what I remembered.
As you can see, we started off getting measurements for both foxes, but soon afterwards thought that we were relatively close to the blue fox. After driving between the two banks of the river far too many times, we gave up on the blue fox and tried our luck with the red fox.
Hunting the red fox was pretty straightforward, and before long we found Skip (KB1CNB) in his car playing the role of the fox. Skip told us that the other fox (blue on our map) was on the other side of the river. This sort of helped. So, we headed across the river.
Looking at the map now, it is clear which measurements were real and which were erroneous, but it is much harder to sort it all out when you are driving around not knowing where the fox is. :) We got really close at stop #20 where we got two equally promising directions. Sadly, we followed what turned out to be the reflection instead of the real one because we assumed that the blue fox was, much like Skip’s, a car in a parking lot. It wasn’t. The fox was on a step ladder in someone’s yard. We were clued in to this when someone mentioned it on the BCRA repeater.
I should know better, but I’ll promise anyway to write about my fox hunting strategy at some point in the future.
]]>This was my first fox hunt of any kind. To improve the chances of success I teamed up with KM1NDY and AA1F. They participated in at least one BCRA fox hunt before, so they knew what to expect. (You can read KM1NDY’s thoughts about the hunt on her blog.)
The “parameters” of the hunt were simple: find the transmitter transmitting every 5 minutes from somewhere within 5 miles of exit 13 on MA 24.
Everyone likes to talk about gear, but at least in my opinion it is much more important to have a good strategy than to invest in specialized gear. That idea, combined with not knowing whether I’d like fox hunting or not, meant that I was going to use what I already owned. That meant WA5VJB’s cheap yagi and an Alinco DJ-G7 handheld. As far as non-radio gear is concerned, I brought my iPad to use for an annotated map.
I already talked about the antenna in my ARRL June VHF contest writeup, so I won’t repeat myself here. I got the Alinco handheld because I wanted a handheld with a third band. That narrowed my options down a lot. Since I heard good things about the Alinco and having a 1.2 GHz capability seemed cool, I went with it, even though the Boston area doesn’t have any sort of 1.2 GHz activity.
We decided to meet up at Massasoit State Park. That made it easy for me to do a POTA/WWFF activation after the hunt.
My co-conspirators were running a bit late, so I got to make the first “measurement” from the park parking lot alone. You can see it on the map labeled as #1:
As you can see, I went relatively low-tech on the map annotation. I just took a screenshot of a reasonably zoomed map and hand-drew the 5 mile circle. Then, during the hunt itself, I just eyeballed the direction of each measurement and noted it down.
When KM1NDY and AA1F arrived at the park, I shared with them my measurement. After a brief discussion about where to go next, I hopped into their car and we headed west to get back to the highway.
I won’t bore you with turn by turn retelling of the whole trip. I will, however, mention a few observations. In no particular order:
Between this and the previous BCRA fox hunt, I got a chance to do some on-foot fox hunting thanks to K1MJC who hid a fox several times in nearby Waltham. This time, I decided to try the hunt by myself (well, with Holly) and left KM1NDY and AA1F to fend for themselves—or “once our partner and now our competitor” as KM1NDY put it in her writeup.
This was a bigger hunt. The radius was 10 miles centered on the Veterans Memorial Bridge in Fall River and there were two transmitters!
Given the size, I decided to make a better blank map. I stitched together a couple of screenshots and then drew 5 mile and 10 mile circles. This turned out to be mostly useless since both foxes were within the 5 mile circle and we hadn’t even picked them up before entering the inner circle. Just look at the annotated map:
I didn’t even bother to try to capture all the information on this map because of how close everything was. When I got home, I ended up redrawing the map to show all the detail based on the above map, notes I made on the side, and what I remembered.
As you can see, we started off getting measurements for both foxes, but soon afterwards thought that we were relatively close to the blue fox. After driving between the two banks of the river far too many times, we gave up on the blue fox and tried our luck with the red fox.
Hunting the red fox was pretty straightforward, and before long we found Skip (KB1CNB) in his car playing the role of the fox. Skip told us that the other fox (blue on our map) was on the other side of the river. This sort of helped. So, we headed across the river.
Looking at the map now, it is clear which measurements were real and which were erroneous, but it is much harder to sort it all out when you are driving around not knowing where the fox is. :) We got really close at stop #20 where we got two equally promising directions. Sadly, we followed what turned out to be the reflection instead of the real one because we assumed that the blue fox was, much like Skip’s, a car in a parking lot. It wasn’t. The fox was on a step ladder in someone’s yard. We were clued in to this when someone mentioned it on the BCRA repeater.
I should know better, but I’ll promise anyway to write about my fox hunting strategy at some point in the future.
]]>Software type content — Assorted (mostly DSP) software by Jonti.
Dad Jokes — US government’s dad joke API.
Second IC :) — Sam Zeloof’s second home-made IC.
USB Cheat Sheet — Fabien Sanglard’s very nicely done summary of the USB standard naming mess.
]]>Software type content — Assorted (mostly DSP) software by Jonti.
Dad Jokes — US government’s dad joke API.
Second IC :) — Sam Zeloof’s second home-made IC.
USB Cheat Sheet — Fabien Sanglard’s very nicely done summary of the USB standard naming mess.
]]>HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation
you want to set RealTimeIsUniversal to a dword 1.
That’s it. After this, Windows will no longer adjust the hardware clock during DST changes.
I’ve used this a number of times on Windows 7.
This concludes today’s edition of Note To Self.
]]>HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\TimeZoneInformation
you want to set RealTimeIsUniversal to a dword 1.
That’s it. After this, Windows will no longer adjust the hardware clock during DST changes.
I’ve used this a number of times on Windows 7.
This concludes today’s edition of Note To Self.
]]>I’ve been meaning to try roving for the past 7 months, but every time there was a good opportunity (in other words a VHF contest), life got in the way and I couldn’t participate.
Since I first got the idea, I’ve emailed with a number of people about a variety of radio-related topics. Speaking specifically of VHF contest roving, WB8LYJ and WW7D provided me with plenty of information. As a matter of fact, they gave me so much roving info I didn’t even use it all—yet. Thank you!
Every rove starts with planning of the route. In order to be a rover, one must make contacts from at least two grid squares during the contest. Given that this was going to be my first rove, I decided to do the bare minimum and visit only two grids to get some experience for the next time.
I live in FN42, so I went with a location I knew would work—the Middlesex Fells Reservation. I’ve been there a couple of times, so I knew exactly which hill I wanted to use. This requires a 200 m hike with about 15 m of elevation gain to get to from the parking lot.
Living pretty much in the center of FN42, I have three equally annoying options for the second grid—FN32 to the west, FN43 to the north, and FN41 to the south.
I looked for parks just outside FN42 to operate from and eventually settled on Wells State Park in Sturbridge, MA in FN32.
At VHF and UHF frequencies, the elevation of the antennas matters quite a bit, so I was happy to see that Wells State Park has a decent hill—Carpenter’s Rocks. The peak is at about 260 m while the parking lot at the bottom of the park is at 190 m—or about 70 m of elevation gain over 1.1 km of distance. Hiking up the hill with the necessary radio equipment didn’t seem like too crazy of an idea while sitting at my computer.
Finally, both Wells and Middlesex Fells are in the Parks on the Air and World Wide Flora & Fauna databases. Wells is K-2462 and KFF-2462, while Middlesex Fells is K-8414 and KFF-5690, respectively. So, not only do any contacts made there count toward the contest, I can also use them to get credit for activating the parks. (Well, I didn’t realize that Wells was a WWFF park until after the contest.)
To keep the timing simple, I was going to spend Saturday at Wells and Sunday at Middlesex Fells.
The plan for a few months was to build yagis for 2 m and 70 cm bands and some (weakly) directional antenna for the 6 m band. Somehow, I ran out of time and only managed to build the 2 m yagi the day of the contest.
I went with WA5VJB’s cheap yagi design. I used a 2 inch by 1 inch wooden furring strip for the boom and 1/8 inch aluminum tubes for the elements.
Here’s the antenna after the contest. The elements are beaten up and slightly misaligned.
I bought an 8 foot long furring strip and cut it in half, which gives plenty of space as the 4-element “cheap yagi” design requires 40.5 inches between the reflector and the second director. I placed the reflector about 5 inches from the end of the boom which leaves enough room to act as a hand grip. This left about 2 inches extra on the other end.
Because I didn’t have time to figure out how to attach it to a mast, I drilled 3/8 inch holes about 1 inch from both ends of the boom to let me suspend it on a rope from a tree branch.
The aluminum tubes I found come in 3 foot sections. Unfortunately, three of the four elements in the design are longer than 3 feet, so I had to splice them together to make the longer lengths.
At the hardware store, I noticed that the 3/32 inch aluminum tube fit nicely (but loosely) inside the 1/8 inch tubes. So, the plan was to use bits of the smaller diameter tube as a stub to hold the sections together.
At first, I tried to solder the sections together, but the solder just wasn’t sticking to the aluminum. After nearly giving up on the build, I realized that I can crimp the pieces together. The 0.100 hex die I have for coax crimping works perfectly for this.
So, whenever I needed to do a splice, I’d insert a 1 inch section of the 3/32 inch aluminum tube between the two section of 1/8 inch tube to be joined and I’d crimp each side. This provides decent mechanical and electrical connections.
Completed splice on the driven element:
Unfortunately, the aluminum tubes themselves are rather fragile. While carrying the fully built yagi up and down a hill, it was far too easy to bump one of the elements and bend it immediately next to the boom. It didn’t take many bumps for metal fatigue to result in a break. Thankfully, the one and only break happened on the way home. I still had to fix it in order to use the antenna on the second day of the contest.
I would not recommend 1/8 inch aluminum tubes for 2 m yagis. The elements stick out a bit too much. Combine that with the softness of aluminum, and you have an antenna that’ll break far too easily. A yagi for 70 cm might be narrow enough that these aluminum tubes would work well, but I haven’t tried. I plan to repurpose the tubes from this build for a 10-element 1296 MHz yagi. With the widest element being only 4.3 inches, it should be relatively robust. And if one of the elements breaks, it is simple enough to just cut a new one instead of having to splice things back together.
For the 6 m band, I reused my 1/4 wave vertical that I’ve been using for Parks On The Air activations over the past two months. (I plan on making a separate post about my 1/4 wave verticals.)
I don’t have a dedicated 70 cm antenna. However, I have an Ed Fong DBJ-1, which is a 2 m/70 cm wire J-pole antenna. It only really works on the 440-450 MHz part of the band, but it is better than nothing.
Unsurprisingly, not everything went according to plan.
Suspending the yagi from a branch worked, but it was a bit fiddly. Specifically, it was far too easy to tilt it up or down instead of keeping it level. It was also a bit difficult to aim the antenna in a specific direction since the coax hanging down constantly tried to turn it back to where it started.
The contest started at 18:00Z. I planned to leave early enough that I could drive over to Wells State Park, grab all the gear, hike up the hill, set up, test everything, and then have a few minutes to relax before the start.
Well, I ended up leaving late because of last minute antenna building. I planned to leave about two hours before the start of the contest, but managed to leave only 5 minutes before the start.
I arrived at the park, and it became obvious that I wasn’t quite sure how to get to the top of the hill. Instead of roaming aimlessly around the forest with all the gear, I did a quick hike to the top to find a reasonable way. This extra hiking added another 30 minute delay to my start.
When I got back to the car, I grabbed everything and headed up again. The second ascent was much harder because of the ~16 kg (~35 lbs) of radios, coax, battery, water, etc. Having my hands literally full also made it harder to defend myself from mosquitoes on the way up. Thankfully, the top of the hill didn’t have any.
Once back at the top, I took a few minutes to reduce my heart rate and then I started setting up. That’s when I discovered that even though I brought three antennas with me, I hauled only two coaxes up the hill. I left the third (and spare fourth) in the car. There was no way I was going to go back to the car, so I resorted to moving one of the coaxes between the Ed Fong and the 6 m 1/4 wave. During the first coax swap, I realized that I also forgot a coax switch.
Anyway, at least the view was nice. (You can see the Ed Fong antenna hanging in the tree on the left.)
At 00:00Z, about 20 minutes before sunset, I called it a day, packed up, and descended through the mosquito territory once more to get to the car. During the descent, I managed to break off one of the elements on the yagi.
The first thing I did Sunday morning was fix the yagi. This took extra effort because the break happened at a crimped joint. So, the first step was to remove the broken inner aluminum tube. Once removed, re-crimping took very little time.
After that, eating breakfast, repacking everything, and so on, I headed out to Middlesex Fells. I hiked up the hill, set up the three antennas, and started working stations around noon (16:00Z).
I’m not sure what happened, but I think the repair I did on the yagi or something else messed up its pattern. It seemed as if the pattern rotated 20-30 degrees.
I planned to stay about 8 hours—from noon to 8pm (16:00Z–00:00Z), but about half way through the breeze died down enough that the mosquitoes started biting. It was nowhere near as bad as during the hikes at Wells, but enough that by 5pm (17:00Z) I decided to call it quits. I packed up and headed home. On the way home, I realized that I could use my handheld radio to catch a few more FM contacts by going to Robbins Farm Park. It is near home, has good elevation, and overlooks Boston, Cambridge, etc. — in other words, places with people and therefore hams.
I made it up to Robbins Farm Park about an hour later. I called for good 25 minutes before I got a response. The person that got back to me happens to be a new-ish ham. We chatted for about half an hour about antenna building, portable operations, ham radio in general, software (we’re both software developers), and programming languages. After that contact, I decided that I wanted dinner and went home.
So, how did I do? I ended up with a score of 832 points. Not great, but not bad either.
In more detail, I…
I definitely learned quite a bit about about VHF contesting and roving. None of it is ground breaking, and I’ve heard some variant of each of my conclusions before, but I can confirm that they are valid ideas. :)
The next relevant contest is the CQ World Wide VHF Contest in July. Which means that I have a month to rebuild the 2 m yagi, construct something directional for 6 m that is still easy enough to transport, and figure out a mast. I should also start scoping out locations. Finally, I need to subscribe to some mailing lists so I have a place to announce my intentions.
This section has been added in November 2021. The results for the contests are out.
With 864 points, I placed 3rd in the New England division. This sounds impressive, but there were only 4 limited rovers in New England. More impressively, I placed 36th out of 62 limited rovers in all of US.
]]>
I’ve been meaning to try roving for the past 7 months, but every time there was a good opportunity (in other words a VHF contest), life got in the way and I couldn’t participate.
Since I first got the idea, I’ve emailed with a number of people about a variety of radio-related topics. Speaking specifically of VHF contest roving, WB8LYJ and WW7D provided me with plenty of information. As a matter of fact, they gave me so much roving info I didn’t even use it all—yet. Thank you!
Every rove starts with planning of the route. In order to be a rover, one must make contacts from at least two grid squares during the contest. Given that this was going to be my first rove, I decided to do the bare minimum and visit only two grids to get some experience for the next time.
I live in FN42, so I went with a location I knew would work—the Middlesex Fells Reservation. I’ve been there a couple of times, so I knew exactly which hill I wanted to use. This requires a 200 m hike with about 15 m of elevation gain to get to from the parking lot.
Living pretty much in the center of FN42, I have three equally annoying options for the second grid—FN32 to the west, FN43 to the north, and FN41 to the south.
I looked for parks just outside FN42 to operate from and eventually settled on Wells State Park in Sturbridge, MA in FN32.
At VHF and UHF frequencies, the elevation of the antennas matters quite a bit, so I was happy to see that Wells State Park has a decent hill—Carpenter’s Rocks. The peak is at about 260 m while the parking lot at the bottom of the park is at 190 m—or about 70 m of elevation gain over 1.1 km of distance. Hiking up the hill with the necessary radio equipment didn’t seem like too crazy of an idea while sitting at my computer.
Finally, both Wells and Middlesex Fells are in the Parks on the Air and World Wide Flora & Fauna databases. Wells is K-2462 and KFF-2462, while Middlesex Fells is K-8414 and KFF-5690, respectively. So, not only do any contacts made there count toward the contest, I can also use them to get credit for activating the parks. (Well, I didn’t realize that Wells was a WWFF park until after the contest.)
To keep the timing simple, I was going to spend Saturday at Wells and Sunday at Middlesex Fells.
The plan for a few months was to build yagis for 2 m and 70 cm bands and some (weakly) directional antenna for the 6 m band. Somehow, I ran out of time and only managed to build the 2 m yagi the day of the contest.
I went with WA5VJB’s cheap yagi design. I used a 2 inch by 1 inch wooden furring strip for the boom and 1/8 inch aluminum tubes for the elements.
Here’s the antenna after the contest. The elements are beaten up and slightly misaligned.
I bought an 8 foot long furring strip and cut it in half, which gives plenty of space as the 4-element “cheap yagi” design requires 40.5 inches between the reflector and the second director. I placed the reflector about 5 inches from the end of the boom which leaves enough room to act as a hand grip. This left about 2 inches extra on the other end.
Because I didn’t have time to figure out how to attach it to a mast, I drilled 3/8 inch holes about 1 inch from both ends of the boom to let me suspend it on a rope from a tree branch.
The aluminum tubes I found come in 3 foot sections. Unfortunately, three of the four elements in the design are longer than 3 feet, so I had to splice them together to make the longer lengths.
At the hardware store, I noticed that the 3/32 inch aluminum tube fit nicely (but loosely) inside the 1/8 inch tubes. So, the plan was to use bits of the smaller diameter tube as a stub to hold the sections together.
At first, I tried to solder the sections together, but the solder just wasn’t sticking to the aluminum. After nearly giving up on the build, I realized that I can crimp the pieces together. The 0.100 hex die I have for coax crimping works perfectly for this.
So, whenever I needed to do a splice, I’d insert a 1 inch section of the 3/32 inch aluminum tube between the two section of 1/8 inch tube to be joined and I’d crimp each side. This provides decent mechanical and electrical connections.
Completed splice on the driven element:
Unfortunately, the aluminum tubes themselves are rather fragile. While carrying the fully built yagi up and down a hill, it was far too easy to bump one of the elements and bend it immediately next to the boom. It didn’t take many bumps for metal fatigue to result in a break. Thankfully, the one and only break happened on the way home. I still had to fix it in order to use the antenna on the second day of the contest.
I would not recommend 1/8 inch aluminum tubes for 2 m yagis. The elements stick out a bit too much. Combine that with the softness of aluminum, and you have an antenna that’ll break far too easily. A yagi for 70 cm might be narrow enough that these aluminum tubes would work well, but I haven’t tried. I plan to repurpose the tubes from this build for a 10-element 1296 MHz yagi. With the widest element being only 4.3 inches, it should be relatively robust. And if one of the elements breaks, it is simple enough to just cut a new one instead of having to splice things back together.
For the 6 m band, I reused my 1/4 wave vertical that I’ve been using for Parks On The Air activations over the past two months. (I plan on making a separate post about my 1/4 wave verticals.)
I don’t have a dedicated 70 cm antenna. However, I have an Ed Fong DBJ-1, which is a 2 m/70 cm wire J-pole antenna. It only really works on the 440-450 MHz part of the band, but it is better than nothing.
Unsurprisingly, not everything went according to plan.
Suspending the yagi from a branch worked, but it was a bit fiddly. Specifically, it was far too easy to tilt it up or down instead of keeping it level. It was also a bit difficult to aim the antenna in a specific direction since the coax hanging down constantly tried to turn it back to where it started.
The contest started at 18:00Z. I planned to leave early enough that I could drive over to Wells State Park, grab all the gear, hike up the hill, set up, test everything, and then have a few minutes to relax before the start.
Well, I ended up leaving late because of last minute antenna building. I planned to leave about two hours before the start of the contest, but managed to leave only 5 minutes before the start.
I arrived at the park, and it became obvious that I wasn’t quite sure how to get to the top of the hill. Instead of roaming aimlessly around the forest with all the gear, I did a quick hike to the top to find a reasonable way. This extra hiking added another 30 minute delay to my start.
When I got back to the car, I grabbed everything and headed up again. The second ascent was much harder because of the ~16 kg (~35 lbs) of radios, coax, battery, water, etc. Having my hands literally full also made it harder to defend myself from mosquitoes on the way up. Thankfully, the top of the hill didn’t have any.
Once back at the top, I took a few minutes to reduce my heart rate and then I started setting up. That’s when I discovered that even though I brought three antennas with me, I hauled only two coaxes up the hill. I left the third (and spare fourth) in the car. There was no way I was going to go back to the car, so I resorted to moving one of the coaxes between the Ed Fong and the 6 m 1/4 wave. During the first coax swap, I realized that I also forgot a coax switch.
Anyway, at least the view was nice. (You can see the Ed Fong antenna hanging in the tree on the left.)
At 00:00Z, about 20 minutes before sunset, I called it a day, packed up, and descended through the mosquito territory once more to get to the car. During the descent, I managed to break off one of the elements on the yagi.
The first thing I did Sunday morning was fix the yagi. This took extra effort because the break happened at a crimped joint. So, the first step was to remove the broken inner aluminum tube. Once removed, re-crimping took very little time.
After that, eating breakfast, repacking everything, and so on, I headed out to Middlesex Fells. I hiked up the hill, set up the three antennas, and started working stations around noon (16:00Z).
I’m not sure what happened, but I think the repair I did on the yagi or something else messed up its pattern. It seemed as if the pattern rotated 20-30 degrees.
I planned to stay about 8 hours—from noon to 8pm (16:00Z–00:00Z), but about half way through the breeze died down enough that the mosquitoes started biting. It was nowhere near as bad as during the hikes at Wells, but enough that by 5pm (17:00Z) I decided to call it quits. I packed up and headed home. On the way home, I realized that I could use my handheld radio to catch a few more FM contacts by going to Robbins Farm Park. It is near home, has good elevation, and overlooks Boston, Cambridge, etc. — in other words, places with people and therefore hams.
I made it up to Robbins Farm Park about an hour later. I called for good 25 minutes before I got a response. The person that got back to me happens to be a new-ish ham. We chatted for about half an hour about antenna building, portable operations, ham radio in general, software (we’re both software developers), and programming languages. After that contact, I decided that I wanted dinner and went home.
So, how did I do? I ended up with a score of 832 points. Not great, but not bad either.
In more detail, I…
I definitely learned quite a bit about about VHF contesting and roving. None of it is ground breaking, and I’ve heard some variant of each of my conclusions before, but I can confirm that they are valid ideas. :)
The next relevant contest is the CQ World Wide VHF Contest in July. Which means that I have a month to rebuild the 2 m yagi, construct something directional for 6 m that is still easy enough to transport, and figure out a mast. I should also start scoping out locations. Finally, I need to subscribe to some mailing lists so I have a place to announce my intentions.
This section has been added in November 2021. The results for the contests are out.
With 864 points, I placed 3rd in the New England division. This sounds impressive, but there were only 4 limited rovers in New England. More impressively, I placed 36th out of 62 limited rovers in all of US.
]]>
You may have heard me say that I don’t like “magical behavior”. Instead, I want everything system software does to be explicit. The rest of this post is going to be about words and my mantra when designing sysadmin friendly interfaces.
First of all, explicit does not mean manual. Explicit behavior is simply something the sysadmin has to ask for. A manual behavior is something the sysadmin has to do by hand.
The opposite of explicit is magical. That is, something which has a varying behavior depending subtle differences in “some state” of something related.
The opposite of manual is automatic. That is, repetitive actions are performed by the computer instead of the human operator.
For the tl;dr crowd:
explicit & automatic = good
magical & manual = bad
To “prove” this by example, let me analyze the good ol’ Unix rm command.
By default, it will refuse to remove a directory. You have to explicitly tell it that it is ok to do by using the -d flag (either directly or implicitly via the -r flag).
The command does not try to guess what you likely intended to do—that’d be magical behavior.
At the same time, rm can delete many files without manually listing every single one. In other words, rm has automation built in, and therefore it isn’t manual.
Makes sense? Good.
What does this mean for more complicated software than rm? Well, I came up with these “rules” to guide your design:
Let me go through each of these rules and explain what I mean. I jump between examples of APIs and user (sysadmin) interfaces. In many ways, the same ideas apply to both and so I reach for whichever is easier to talk about at the time.
Avoid magical behavior by not guessing what the user may have intended.
Just like installing a second web browser shouldn’t change all your settings, installing a new RDBMS shouldn’t just randomly find some disk space and reformat it for its use. Similarly, when a new host in a cluster starts up, the software has no way of knowing what the intent is. Is it supposed to go into production immediately? What if it is Friday at 5pm? Would it make sense to wait till Monday morning? Is it supposed to be a spare?
The software should give the sysadmin the tools to perform whatever actions may be needed but leave it up to the sysadmin to decide when to do them. This is very similar to the idea of separation of mechanism and policy.
So, won’t this create a lot of work for the sysadmin? Glad you asked! Keep reading to find out why it doesn’t ;)
Err on the side of caution and error out if the user’s intent isn’t clear.
Error out if you aren’t sure what exactly the user intended. This is really a form of the first rule—avoid magical behavior.
It is better to be (slightly) annoying to use, than to misinterpret the user’s intentions and lose data. “Annoying to use” can be addressed in the future with new commands and APIs. Lost data cannot be “unlost” by code changes.
Provide interfaces and tools to encapsulate implementation details.
If the installation instructions for an operating system included disk byte offsets and values to store there, you’d either think that it is insane or that you are living in the 1970’s and you just got a super fancy 8-bit computer with a (floppy) disk drive.
Any modern OS installer will encapsulate all these disk writes by several layers of abstractions. Disk driver, file system, some sort of mkfs utility, and so on. Depending on the intended users’ skill level, the highest abstraction visible may be a fully functional shell or just a single “Install now” button.
Similarly, a program that requires a database should provide some (explicit) “initialize the database” command instead of requiring the user to run manual queries. (Yes, there is software requiring setup steps like that!) Or in the “new host in a cluster” scenario, the new host should have a “add self to cluster” command for the sysadmin.
With these interfaces and commands, it is possible to automate tasks if the need arises. For example, since the cluster admin already has some form of provisioning or configuration management tool, it is rather easy to add the “add self to cluster” command invocation to the existing tooling. Whether or not to automate this (as well as when exactly to run the command) is a matter of policy and therefore shouldn’t be dictated by the developer.
Err on the side of caution and create (reasonably) low-level primitives.
Different tasks benefit from different levels of abstraction. The higher the abstraction level, the less flexible it is, but the easier it is to use—but only if that’s exactly what you want to do. If what you want to do is not quite what the level of abstraction provides, it can be very difficult (or outright impossible) to accomplish what you are after.
Therefore, it is better to have a solid lower-level abstraction that can be built on rather than a higher-level abstraction that you have to fight with.
Note that these two aren’t mutually exclusive, it is possible to have a low-level abstraction with a few higher level primitives that help with common tasks.
Consider a simple file access API. We could implement functions to delete a single file, delete a set of files, delete recursively, and so on. This would take a lot of effort and would create a lot of code that needs to be maintained. If you are uncertain what the users will need, do the simplest thing you expect them to need. For example, give them a way to delete one file and to list files. Users are clever, and before long they’ll script ways to delete multiple files or to delete recursively.
Then, when you have some user feedback (“I always end up writing the same complicated command over and over”), you can revisit the set of provided primitives, and add or modify as needed.
It doesn’t matter if you are providing a file API, a cluster management API, or something else, providing some form of create, read, update, delete, and list API for each “thing” you expect the users to operate on is sufficient to get going. Of course the type of object will dictate the exact set of operations. For example, better command names may be add/remove (cluster node) instead of a create/delete.
Err on the side of caution and do not commit to support APIs and other interfaces.
It is essentially impossible to predict what APIs or other interfaces will actually end up being useful. It can become a huge maintenance burden (in time and cost) to maintain seldom used interfaces that have only a handful of users. Unfortunately, users like being able to rely on functionality not going away. Therefore, for your own sanity, make it clear:
The first two items are self-explanatory, but the last one requires a few extra words.
It is tempting to say that “function foo is supported”, but that is the wrong way to do it. Rather, you want to say “function foo, which does only bar, is supported”.
For example, suppose that we have a function which returns an array of names (strings). Let’s also assume that it is convenient to keep track of those names internally using a balanced binary search tree. When we implement this get-names function, we are likely to simply iterate the tree appending all the names to the output array. This results in the output being sorted because of the tree-based implementation.
Now, consider these two possible statements of what is supported. First, a bad one:
Function get-names is supported. The function returns all names.
And now a better one:
Function get-names is supported. The function returns all names in an unspecified order.
Using the first (bad) description, it is completely reasonable for someone to start relying on the fact that the returned names are sorted. This ties our hands in multiple ways.
The second (better) description makes it clear that the order of the names can be anything and therefore the users shouldn’t rely on a particular order. It better communicates our intention of what is and what isn’t supported.
Now, say that we’d like to replace the tree with a hash table. (Maybe the tree insertion cost is too high for what we are trying to do.) This is a pretty simple change, but now our get-names output is unsorted. If we used the first description and some major consumer relied on the sorted behavior, we have to add a O(n log n) sort to the end of get-names making everyone pay the penalty instead of just the consumers that want sorted output. On the other hand, the second description lets us do this hash table change.
So, be very explicit about what is and what isn’t supported.
I used a function in the above example, but the same applies to utilities and other tools. For example, it is perfectly reasonable to make the default output of a command implementation dependant, but provide arguments that force certain columns, values, or units for the consumers that care.
A project I worked on a number of years ago had very simple rules for what was supported. Everything was unsupported, unless otherwise stated.
In short, we supported any API function and utility command that had a manpage that didn’t explicitly say that it was a developer-only interface or that the specific behavior should not be relied upon.
Yes, there have been a few instances where our users assumed something was supported when it wasn’t, and inevitably they filed bugs. However, we were able to tell them that there was a better (and supported) way to accomplishing their task. Once they fixed their assumptions, their system became more robust and significantly less likely to break in the future.
Finally, make your interfaces consistent.
Not only internally consistent (e.g., always use the same option name for the same behavior) but also consistent with the rest of the system (e.g., use the same option names that commonly used software uses). This is a rephrasing of the principle of least astonishment.
There are other ways of approaching interface design, but the only one I’ve seen that doesn’t turn into a mess (or doesn’t cause a user revolt) is what I tried to outline here. Specifically, start with a small, simple, consistent, and explicit interface that you barely support and evolve over time.
This was a long post with a lot of information, but it still barely scratches the surface of what could be said. Really, most of the rules could easily turn into lengthy posts of their own. Maybe if there is interest (and I find the time), I’ll elaborate on some of these.
]]>You may have heard me say that I don’t like “magical behavior”. Instead, I want everything system software does to be explicit. The rest of this post is going to be about words and my mantra when designing sysadmin friendly interfaces.
First of all, explicit does not mean manual. Explicit behavior is simply something the sysadmin has to ask for. A manual behavior is something the sysadmin has to do by hand.
The opposite of explicit is magical. That is, something which has a varying behavior depending subtle differences in “some state” of something related.
The opposite of manual is automatic. That is, repetitive actions are performed by the computer instead of the human operator.
For the tl;dr crowd:
explicit & automatic = good
magical & manual = bad
To “prove” this by example, let me analyze the good ol’ Unix rm command.
By default, it will refuse to remove a directory. You have to explicitly tell it that it is ok to do by using the -d flag (either directly or implicitly via the -r flag).
The command does not try to guess what you likely intended to do—that’d be magical behavior.
At the same time, rm can delete many files without manually listing every single one. In other words, rm has automation built in, and therefore it isn’t manual.
Makes sense? Good.
What does this mean for more complicated software than rm? Well, I came up with these “rules” to guide your design:
Let me go through each of these rules and explain what I mean. I jump between examples of APIs and user (sysadmin) interfaces. In many ways, the same ideas apply to both and so I reach for whichever is easier to talk about at the time.
Avoid magical behavior by not guessing what the user may have intended.
Just like installing a second web browser shouldn’t change all your settings, installing a new RDBMS shouldn’t just randomly find some disk space and reformat it for its use. Similarly, when a new host in a cluster starts up, the software has no way of knowing what the intent is. Is it supposed to go into production immediately? What if it is Friday at 5pm? Would it make sense to wait till Monday morning? Is it supposed to be a spare?
The software should give the sysadmin the tools to perform whatever actions may be needed but leave it up to the sysadmin to decide when to do them. This is very similar to the idea of separation of mechanism and policy.
So, won’t this create a lot of work for the sysadmin? Glad you asked! Keep reading to find out why it doesn’t ;)
Err on the side of caution and error out if the user’s intent isn’t clear.
Error out if you aren’t sure what exactly the user intended. This is really a form of the first rule—avoid magical behavior.
It is better to be (slightly) annoying to use, than to misinterpret the user’s intentions and lose data. “Annoying to use” can be addressed in the future with new commands and APIs. Lost data cannot be “unlost” by code changes.
Provide interfaces and tools to encapsulate implementation details.
If the installation instructions for an operating system included disk byte offsets and values to store there, you’d either think that it is insane or that you are living in the 1970’s and you just got a super fancy 8-bit computer with a (floppy) disk drive.
Any modern OS installer will encapsulate all these disk writes by several layers of abstractions. Disk driver, file system, some sort of mkfs utility, and so on. Depending on the intended users’ skill level, the highest abstraction visible may be a fully functional shell or just a single “Install now” button.
Similarly, a program that requires a database should provide some (explicit) “initialize the database” command instead of requiring the user to run manual queries. (Yes, there is software requiring setup steps like that!) Or in the “new host in a cluster” scenario, the new host should have a “add self to cluster” command for the sysadmin.
With these interfaces and commands, it is possible to automate tasks if the need arises. For example, since the cluster admin already has some form of provisioning or configuration management tool, it is rather easy to add the “add self to cluster” command invocation to the existing tooling. Whether or not to automate this (as well as when exactly to run the command) is a matter of policy and therefore shouldn’t be dictated by the developer.
Err on the side of caution and create (reasonably) low-level primitives.
Different tasks benefit from different levels of abstraction. The higher the abstraction level, the less flexible it is, but the easier it is to use—but only if that’s exactly what you want to do. If what you want to do is not quite what the level of abstraction provides, it can be very difficult (or outright impossible) to accomplish what you are after.
Therefore, it is better to have a solid lower-level abstraction that can be built on rather than a higher-level abstraction that you have to fight with.
Note that these two aren’t mutually exclusive, it is possible to have a low-level abstraction with a few higher level primitives that help with common tasks.
Consider a simple file access API. We could implement functions to delete a single file, delete a set of files, delete recursively, and so on. This would take a lot of effort and would create a lot of code that needs to be maintained. If you are uncertain what the users will need, do the simplest thing you expect them to need. For example, give them a way to delete one file and to list files. Users are clever, and before long they’ll script ways to delete multiple files or to delete recursively.
Then, when you have some user feedback (“I always end up writing the same complicated command over and over”), you can revisit the set of provided primitives, and add or modify as needed.
It doesn’t matter if you are providing a file API, a cluster management API, or something else, providing some form of create, read, update, delete, and list API for each “thing” you expect the users to operate on is sufficient to get going. Of course the type of object will dictate the exact set of operations. For example, better command names may be add/remove (cluster node) instead of a create/delete.
Err on the side of caution and do not commit to support APIs and other interfaces.
It is essentially impossible to predict what APIs or other interfaces will actually end up being useful. It can become a huge maintenance burden (in time and cost) to maintain seldom used interfaces that have only a handful of users. Unfortunately, users like being able to rely on functionality not going away. Therefore, for your own sanity, make it clear:
The first two items are self-explanatory, but the last one requires a few extra words.
It is tempting to say that “function foo is supported”, but that is the wrong way to do it. Rather, you want to say “function foo, which does only bar, is supported”.
For example, suppose that we have a function which returns an array of names (strings). Let’s also assume that it is convenient to keep track of those names internally using a balanced binary search tree. When we implement this get-names function, we are likely to simply iterate the tree appending all the names to the output array. This results in the output being sorted because of the tree-based implementation.
Now, consider these two possible statements of what is supported. First, a bad one:
Function get-names is supported. The function returns all names.
And now a better one:
Function get-names is supported. The function returns all names in an unspecified order.
Using the first (bad) description, it is completely reasonable for someone to start relying on the fact that the returned names are sorted. This ties our hands in multiple ways.
The second (better) description makes it clear that the order of the names can be anything and therefore the users shouldn’t rely on a particular order. It better communicates our intention of what is and what isn’t supported.
Now, say that we’d like to replace the tree with a hash table. (Maybe the tree insertion cost is too high for what we are trying to do.) This is a pretty simple change, but now our get-names output is unsorted. If we used the first description and some major consumer relied on the sorted behavior, we have to add a O(n log n) sort to the end of get-names making everyone pay the penalty instead of just the consumers that want sorted output. On the other hand, the second description lets us do this hash table change.
So, be very explicit about what is and what isn’t supported.
I used a function in the above example, but the same applies to utilities and other tools. For example, it is perfectly reasonable to make the default output of a command implementation dependant, but provide arguments that force certain columns, values, or units for the consumers that care.
A project I worked on a number of years ago had very simple rules for what was supported. Everything was unsupported, unless otherwise stated.
In short, we supported any API function and utility command that had a manpage that didn’t explicitly say that it was a developer-only interface or that the specific behavior should not be relied upon.
Yes, there have been a few instances where our users assumed something was supported when it wasn’t, and inevitably they filed bugs. However, we were able to tell them that there was a better (and supported) way to accomplishing their task. Once they fixed their assumptions, their system became more robust and significantly less likely to break in the future.
Finally, make your interfaces consistent.
Not only internally consistent (e.g., always use the same option name for the same behavior) but also consistent with the rest of the system (e.g., use the same option names that commonly used software uses). This is a rephrasing of the principle of least astonishment.
There are other ways of approaching interface design, but the only one I’ve seen that doesn’t turn into a mess (or doesn’t cause a user revolt) is what I tried to outline here. Specifically, start with a small, simple, consistent, and explicit interface that you barely support and evolve over time.
This was a long post with a lot of information, but it still barely scratches the surface of what could be said. Really, most of the rules could easily turn into lengthy posts of their own. Maybe if there is interest (and I find the time), I’ll elaborate on some of these.
]]>VHF/UHF Line of Sight Calculator
Hey What’s That — Line of sight calculator
Radio Mobile Online — RF coverage estimator
Telnet Access to DX Clusters and Reverse Beacon Network
FCC M3 Map of Effective Ground Conductivity in the US for AM Broadcast Stations
]]>VHF/UHF Line of Sight Calculator
Hey What’s That — Line of sight calculator
Radio Mobile Online — RF coverage estimator
Telnet Access to DX Clusters and Reverse Beacon Network
FCC M3 Map of Effective Ground Conductivity in the US for AM Broadcast Stations
]]>In short, I’m officially stopping work on guilt.
Practically speaking, I haven’t touched it (as a developer) in over two years and as a user in about as long. So really, nothing will change.
I started writing Guilt in fall 2006 because I was working on unionfs and needed to maintain patches on top of the Linux kernel git repository—much like what the mq extension did with Mercurial repositories.
It all started with:
commit 664e5a7d7f8d2c2726f03a239de11fa00127cf84 Author: Josef Sipek <jsipek@thor.fsl.cs.sunysb.edu> Date: Mon Nov 6 13:08:30 2006 -0500 Initial commit
That’s right, 14 years to the day.
Technically, the first few versions were called “gq” (which stood for “git quilt”) until someone pointed out that “GQ” was a well established GTK-based LDAP client.
If anyone wishes to resurrect this project, then by all means go for it. If not, the old content will remain online for as long as I have a web server. :)
Specifically, you can find everything up to and including the last release (v0.37-rc1) at the following locations:
I know that Guilt has served a number of people quite well over the years. It’s been quite stable and mostly feature complete since at least 2008, so I haven’t really been hearing from people short of the occasional patch or an occasional “oh yeah, I use that”.
To those users: I hope the last release works well enough for you until someone starts to maintain Guilt again or you find a different tool that suits your needs.
]]>In short, I’m officially stopping work on guilt.
Practically speaking, I haven’t touched it (as a developer) in over two years and as a user in about as long. So really, nothing will change.
I started writing Guilt in fall 2006 because I was working on unionfs and needed to maintain patches on top of the Linux kernel git repository—much like what the mq extension did with Mercurial repositories.
It all started with:
commit 664e5a7d7f8d2c2726f03a239de11fa00127cf84 Author: Josef Sipek <jsipek@thor.fsl.cs.sunysb.edu> Date: Mon Nov 6 13:08:30 2006 -0500 Initial commit
That’s right, 14 years to the day.
Technically, the first few versions were called “gq” (which stood for “git quilt”) until someone pointed out that “GQ” was a well established GTK-based LDAP client.
If anyone wishes to resurrect this project, then by all means go for it. If not, the old content will remain online for as long as I have a web server. :)
Specifically, you can find everything up to and including the last release (v0.37-rc1) at the following locations:
I know that Guilt has served a number of people quite well over the years. It’s been quite stable and mostly feature complete since at least 2008, so I haven’t really been hearing from people short of the occasional patch or an occasional “oh yeah, I use that”.
To those users: I hope the last release works well enough for you until someone starts to maintain Guilt again or you find a different tool that suits your needs.
]]>Ultimately, working on a project requires communication—and lots of it. Communication with peers, with managers, with other departments within the company, and even with customers. It is tempting to grab the Tool du Jour and add it to your ever-growing arsenal of tools believing it will make communication easier. Often, it does not.
For example, let’s consider these tools: Jira, Confluence, Slack, Zoom, GitHub/GitLab, phone, and email.
Does your company use these tools or their equivalents? Isn’t it a bit overkill to have 7 different channels of communication? Sure, often one tool is better at a particular mode of communication than the others but there is a significant overlap.
Do you want a video chat? Do you use Slack or Zoom?
Voice chat? Slack, Zoom, or phone?
Do you want to ask a question related to a bug? Do you use Jira, Slack, or just set up a call? Voice or video? Or would email be best?
Do you keep track of your project via high-level Jira issues? Or do you use a set of Confluence pages where you include various semi-autogenerated plots?
Decision fatigue is real. Do you want your (rather expensive) employees to waste their cognitive capacity deciding which tool to use? Or do you want them to make the product better?
It is painful how many times over the past ten years I’ve witnessed conversations that went much like this:
A: Can you answer the question I left in Jira?
B: <B reads Jira question> Oh, that is answered on the ABC123 Confluence page.
A: Ah. Can you make a note of that in Jira? Thanks.
This example involves three communication channels—Jira, Confluence, and some chat system.
This sort of communication fragmentation is really bad. Not only does it waste a lot of time with exchanges like this example, it also makes searching for information essentially impossible. Who in their right mind would search half a dozen tools (with various degrees of search capability) for something? It is simply easier to just ask your coworkers. After all, their time is less valuable to you than your own time and sanity.
So, what can be done to improve things?
Well, if at all possible do not use tools that have duplicate functionality. If you have to, hopefully you can disable the duplicate functionality. If there is no way to disable it, then you must make it painfully clear where such communication should go. Hopefully this can be done via automated hooks that somehow notify the user. For example, automatically closing issues opened in the wrong bug tracker (e.g., opened in GitHub instead of Jira), or automatically responding to wiki commenters directing them to the proper medium for wiki discussion. Finally, if all else fails, have someone (ideally manager or team lead so the notification has some weight to it) manually make sure that anyone that uses the functionality is told not to.
This reduction in the number of tools should also help with responsiveness. It is no secret that the average human can hold only about 7 things in working memory at the same time. How many of those do you want to dedicate to tooling? If I have to remember to check 7 different tools periodically, one of two things happens: either I manage to check them all but accomplish nothing else, or I get things done but only remember about 2 or 3 tools.
That should help with quite a bit of the fragmentation. Now “all” that’s left to do is decide which communication channel is used for what.
I have concluded that there are four major levels of communication:
I’m using the terms “synchronous” to mean that you want the back-and-forth latency to be low, and “important” to mean that that you must have an answer. Note that “unimportant” does not mean off-topic, but rather lower priority.
Why make the synchronous/asynchronous distinction? For multiple reasons. First of all, being interrupted in the middle of something is costly. It takes a significant amount of time to get back “into the zone” but only a fraction of a minute to get out of it. Would you rather pay your employees to try to work or to actually work? And second, asynchrony makes communication across time zones easier. Not easy, but easier.
So, let me go through the four major levels of communication one by one and share my opinion about what works and why.
These four levels are, of course, not set in stone. It is possible (and I’d even encourage it) to upgrade or downgrade your communication as needed. For example, it is perfectly reasonable to ask in chat if there are objections or obvious issues with a particular approach, function, or workload. Then, if the responses don’t make it obviously a terrible idea but a more definitive discussion is desired, a similar (but more detailed) version can be sent via email. In essence, upgrading it from “unimportant synchronous” to “important asynchronous”. (Caution: don’t overdo these upgrades/downgrades.)
As you can see, I think that email is a good choice for any asynchronous communication. That’s for good reasons. Everyone has an email address, everyone knows how to use it (at least a little), and the free-form format allows you to use the most appropriate content type to get your point across—be it ASCII art, images, or even Excel spreadsheets. In other words:
Email is ubiquitous.
Email works remarkably well.
Email is extremely flexible.
As a real world example, consider that pretty much every company-wide announcement (important or not) has been made either in a huge meeting or via email. Often the meeting-time announcements are followed up by an email anyway! It’s not a chat message. It’s not a Confluence page. It’s not a Jira issue. It’s an email.
Before I conclude, I’d like to address two slightly more specific cases.
First, what about issue tracking? How does that tie into my email-centric world? Well, you can keep your issue tracker, but in my opinion, the comments feature should not be used. If a ticket needs to be discussed, send an email, set up a conference call, whatever works for your—just don’t use the comments on the issue. If you look at any issue in your issue tracker, the comments will fall into one of two categories. Either there are none or there are many, and it is painfully clear that people don’t read them and ask the same questions over and over. Instead of burying progress reports or updates to the understanding of the issue in a comment that nobody will ever read, that information should be used to reword the issue description. The same largely applies to other tools’ comments sections as well.
Second is a concern that people will not read all those emails. I think this is only a problem if there are too many tools and email isn’t viewed as an important one. If (unrealistically) all communication happens through email, then right after communicating with someone, the person is already in the right tool to handle the next communication. If code reviews, support requests, and everything else were to go to the same place, there is nearly zero context switching cost. Even if the person goes to use a different tool (e.g., a text editor or an IDE), when that work is done, they’ll return to their email client. In other words, if you make the email communication channel important, your emails will get read. If you don’t make it important, then you (individually) are better off using a channel the recipient considers important. In an environment with too many tools, each recipient may have a different preference.
Just to make it painfully clear, I am not advocating killing off everything except email. Instead, I’m advocating killing off tools that duplicate functionality, and shifting all asynchronous communication to a single medium. In my experience, the most efficient (and least disruptive) asynchronous communication medium is email. And therefore it should not only be one of the tools that survives the culling, but it also should be the one that is embraced afterwards.
That’s it for today. In the next post, I’ll talk about what I consider the ideal code review workflow.
]]>Ultimately, working on a project requires communication—and lots of it. Communication with peers, with managers, with other departments within the company, and even with customers. It is tempting to grab the Tool du Jour and add it to your ever-growing arsenal of tools believing it will make communication easier. Often, it does not.
For example, let’s consider these tools: Jira, Confluence, Slack, Zoom, GitHub/GitLab, phone, and email.
Does your company use these tools or their equivalents? Isn’t it a bit overkill to have 7 different channels of communication? Sure, often one tool is better at a particular mode of communication than the others but there is a significant overlap.
Do you want a video chat? Do you use Slack or Zoom?
Voice chat? Slack, Zoom, or phone?
Do you want to ask a question related to a bug? Do you use Jira, Slack, or just set up a call? Voice or video? Or would email be best?
Do you keep track of your project via high-level Jira issues? Or do you use a set of Confluence pages where you include various semi-autogenerated plots?
Decision fatigue is real. Do you want your (rather expensive) employees to waste their cognitive capacity deciding which tool to use? Or do you want them to make the product better?
It is painful how many times over the past ten years I’ve witnessed conversations that went much like this:
A: Can you answer the question I left in Jira?
B: <B reads Jira question> Oh, that is answered on the ABC123 Confluence page.
A: Ah. Can you make a note of that in Jira? Thanks.
This example involves three communication channels—Jira, Confluence, and some chat system.
This sort of communication fragmentation is really bad. Not only does it waste a lot of time with exchanges like this example, it also makes searching for information essentially impossible. Who in their right mind would search half a dozen tools (with various degrees of search capability) for something? It is simply easier to just ask your coworkers. After all, their time is less valuable to you than your own time and sanity.
So, what can be done to improve things?
Well, if at all possible do not use tools that have duplicate functionality. If you have to, hopefully you can disable the duplicate functionality. If there is no way to disable it, then you must make it painfully clear where such communication should go. Hopefully this can be done via automated hooks that somehow notify the user. For example, automatically closing issues opened in the wrong bug tracker (e.g., opened in GitHub instead of Jira), or automatically responding to wiki commenters directing them to the proper medium for wiki discussion. Finally, if all else fails, have someone (ideally manager or team lead so the notification has some weight to it) manually make sure that anyone that uses the functionality is told not to.
This reduction in the number of tools should also help with responsiveness. It is no secret that the average human can hold only about 7 things in working memory at the same time. How many of those do you want to dedicate to tooling? If I have to remember to check 7 different tools periodically, one of two things happens: either I manage to check them all but accomplish nothing else, or I get things done but only remember about 2 or 3 tools.
That should help with quite a bit of the fragmentation. Now “all” that’s left to do is decide which communication channel is used for what.
I have concluded that there are four major levels of communication:
I’m using the terms “synchronous” to mean that you want the back-and-forth latency to be low, and “important” to mean that that you must have an answer. Note that “unimportant” does not mean off-topic, but rather lower priority.
Why make the synchronous/asynchronous distinction? For multiple reasons. First of all, being interrupted in the middle of something is costly. It takes a significant amount of time to get back “into the zone” but only a fraction of a minute to get out of it. Would you rather pay your employees to try to work or to actually work? And second, asynchrony makes communication across time zones easier. Not easy, but easier.
So, let me go through the four major levels of communication one by one and share my opinion about what works and why.
These four levels are, of course, not set in stone. It is possible (and I’d even encourage it) to upgrade or downgrade your communication as needed. For example, it is perfectly reasonable to ask in chat if there are objections or obvious issues with a particular approach, function, or workload. Then, if the responses don’t make it obviously a terrible idea but a more definitive discussion is desired, a similar (but more detailed) version can be sent via email. In essence, upgrading it from “unimportant synchronous” to “important asynchronous”. (Caution: don’t overdo these upgrades/downgrades.)
As you can see, I think that email is a good choice for any asynchronous communication. That’s for good reasons. Everyone has an email address, everyone knows how to use it (at least a little), and the free-form format allows you to use the most appropriate content type to get your point across—be it ASCII art, images, or even Excel spreadsheets. In other words:
Email is ubiquitous.
Email works remarkably well.
Email is extremely flexible.
As a real world example, consider that pretty much every company-wide announcement (important or not) has been made either in a huge meeting or via email. Often the meeting-time announcements are followed up by an email anyway! It’s not a chat message. It’s not a Confluence page. It’s not a Jira issue. It’s an email.
Before I conclude, I’d like to address two slightly more specific cases.
First, what about issue tracking? How does that tie into my email-centric world? Well, you can keep your issue tracker, but in my opinion, the comments feature should not be used. If a ticket needs to be discussed, send an email, set up a conference call, whatever works for your—just don’t use the comments on the issue. If you look at any issue in your issue tracker, the comments will fall into one of two categories. Either there are none or there are many, and it is painfully clear that people don’t read them and ask the same questions over and over. Instead of burying progress reports or updates to the understanding of the issue in a comment that nobody will ever read, that information should be used to reword the issue description. The same largely applies to other tools’ comments sections as well.
Second is a concern that people will not read all those emails. I think this is only a problem if there are too many tools and email isn’t viewed as an important one. If (unrealistically) all communication happens through email, then right after communicating with someone, the person is already in the right tool to handle the next communication. If code reviews, support requests, and everything else were to go to the same place, there is nearly zero context switching cost. Even if the person goes to use a different tool (e.g., a text editor or an IDE), when that work is done, they’ll return to their email client. In other words, if you make the email communication channel important, your emails will get read. If you don’t make it important, then you (individually) are better off using a channel the recipient considers important. In an environment with too many tools, each recipient may have a different preference.
Just to make it painfully clear, I am not advocating killing off everything except email. Instead, I’m advocating killing off tools that duplicate functionality, and shifting all asynchronous communication to a single medium. In my experience, the most efficient (and least disruptive) asynchronous communication medium is email. And therefore it should not only be one of the tools that survives the culling, but it also should be the one that is embraced afterwards.
That’s it for today. In the next post, I’ll talk about what I consider the ideal code review workflow.
]]>At first, I thought it was a Qt issue since only Qt applications appeared broken. But then, mere minutes before emailing a FreeBSD mailing list, I managed to find a hint that it was likely an ALSA on FreeBSD issue. Some searching later, I learned that in order for ALSA to see the device, it needed a mapping to the actual OSS device.
So, after adding the following to ~/.asoundrc, any ALSA application (and therefore any Qt application) that tries to list the sound devices will see a “ft991a” device:
pcm.ft991a { type oss device /dev/dsp3 }
To make it more explicit, without adding the above stanza to .asoundrc:
With the stanza, everything seems to work.
]]>At first, I thought it was a Qt issue since only Qt applications appeared broken. But then, mere minutes before emailing a FreeBSD mailing list, I managed to find a hint that it was likely an ALSA on FreeBSD issue. Some searching later, I learned that in order for ALSA to see the device, it needed a mapping to the actual OSS device.
So, after adding the following to ~/.asoundrc, any ALSA application (and therefore any Qt application) that tries to list the sound devices will see a “ft991a” device:
pcm.ft991a { type oss device /dev/dsp3 }
To make it more explicit, without adding the above stanza to .asoundrc:
With the stanza, everything seems to work.
]]>