<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
 xmlns:content="http://purl.org/rss/1.0/modules/content/"
 xmlns:wfw="http://wellformedweb.org/CommentAPI/"
 xmlns:dc="http://purl.org/dc/elements/1.1/"
 xmlns:atom="http://www.w3.org/2005/Atom"
 xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
 xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
 xmlns:georss="http://www.georss.org/georss"
 xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#"
 xmlns:media="http://search.yahoo.com/mrss/">
<channel>
<atom:link href="https://remcycles.net/blog/rss.xml" rel="self" type="application/rss+xml" />
<title>Remcycles Blog</title>
<link>https://remcycles.net/blog/index.html</link>
<description><![CDATA[Occasional thoughts on cycles]]></description>
<language>en</language>
<lastBuildDate>Sat, 04 Jul 2026 08:56:23 -0700</lastBuildDate>
<generator>Emacs 30.2 org-publish-rss.el 0.8</generator>
<item>
<title>RSS Feed</title>
<link>https://remcycles.net/blog/rss.html</link>
<pubDate>Sat, 04 Jul 2026 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/rss.html</guid>
<description>
<![CDATA[<p>
At long last, here's an RSS feed for my blog:
</p>

<p>
<a href="https://remcycles.net/blog/./rss.xml">rss.xml</a>
</p>

<p>
This has been on my todo list for years, but the recent work by <a href="https://taingram.org/">Thomas
Ingram</a> and <a href="https://thibaut.dev/blog/org-publish-rss.html">Thibaut Meyer</a> on <a href="https://git.sr.ht/~taingram/org-publish-rss/"><code>org-publish-rss</code></a> has made this very
straightforward.
</p>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>A POSIX ~cksum~ in Bash</title>
<link>https://remcycles.net/blog/bash_cksum.html</link>
<pubDate>Fri, 22 May 2026 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/bash_cksum.html</guid>
<description>
<![CDATA[<p>
For fun I ported the POSIX <code>cksum</code> command to Bash.  It was relatively
straightforward to port the C reference implementation using
<a href="https://www.gnu.org/software/bash/manual/html_node/Shell-Arithmetic.html">arithmetic expressions</a>.  The biggest gotcha was adding a 32-bit mask
to narrow the wide integers.
</p>

<p>
Here's the specification:
</p>

<p>
<a href="https://pubs.opengroup.org/onlinepubs/9799919799/utilities/cksum.html">https://pubs.opengroup.org/onlinepubs/9799919799/utilities/cksum.html</a>
</p>

<p>
It's very slow, as expected, but it works:
</p>
<pre class="example" id="orge1feff4">
$ time cksum &lt; cksum.sh
2237303807 4936

real	0m0.003s
user	0m0.000s
sys	0m0.003s

$ time ./cksum.sh &lt; cksum.sh
2237303807 4936

real	0m3.214s
user	0m2.357s
sys	0m1.106s

$ time cksum &lt; $(which cksum)
67740544 112880

real	0m0.007s
user	0m0.002s
sys	0m0.005s

$ time ./cksum.sh &lt; $(which cksum)
67740544 112880

real	0m39.091s
user	0m29.802s
sys	0m12.385s
</pre>

<p>
It also handles multiple files and missing files correctly:
</p>
<pre class="example" id="orgc5ac476">
$ cksum cksum.sh cksum.sh
2237303807 4936 cksum.sh
2237303807 4936 cksum.sh

$ ./cksum.sh cksum.sh cksum.sh
2237303807 4936 cksum.sh
2237303807 4936 cksum.sh

$ ./cksum.sh blah
./cksum.sh: line 100: blah: No such file or directory

$ cksum blah
cksum: blah: No such file or directory
</pre>

<div class="org-src-container">
<pre class="src src-bash"><span style="color: #add8e6;">#</span><span style="color: #add8e6;">!/bin/</span><span style="color: #fa8072;">bash</span>

<span style="color: #add8e6;"># </span><span style="color: #add8e6;">cksum.sh Performs a POSIX cksum in Bash.</span>
<span style="color: #add8e6;">#</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Copyright (C) 2026 Remington Furman</span>
<span style="color: #add8e6;">#</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">SPDX-License-Identifier: MIT</span>
<span style="color: #add8e6;">#</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Permission is hereby granted, free of charge, to any person</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">obtaining a copy of this software and associated documentation files</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">(the "Software"), to deal in the Software without restriction,</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">including without limitation the rights to use, copy, modify, merge,</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">publish, distribute, sublicense, and/or sell copies of the Software,</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">and to permit persons to whom the Software is furnished to do so,</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">subject to the following conditions:</span>
<span style="color: #add8e6;">#</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">The above copyright notice and this permission notice shall be</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">included in all copies or substantial portions of the Software.</span>
<span style="color: #add8e6;">#</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">SOFTWARE.</span>


<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Refer to the POSIX specification for details:</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">https://pubs.opengroup.org/onlinepubs/9799919799/utilities/cksum.html</span>

<span style="color: #7fffd4; font-weight: bold;">table</span>=(
    0x00000000 0x04c11db7 0x09823b6e 0x0d4326d9 0x130476dc 0x17c56b6b
    0x1a864db2 0x1e475005 0x2608edb8 0x22c9f00f 0x2f8ad6d6 0x2b4bcb61
    0x350c9b64 0x31cd86d3 0x3c8ea00a 0x384fbdbd 0x4c11db70 0x48d0c6c7
    0x4593e01e 0x4152fda9 0x5f15adac 0x5bd4b01b 0x569796c2 0x52568b75
    0x6a1936c8 0x6ed82b7f 0x639b0da6 0x675a1011 0x791d4014 0x7ddc5da3
    0x709f7b7a 0x745e66cd 0x9823b6e0 0x9ce2ab57 0x91a18d8e 0x95609039
    0x8b27c03c 0x8fe6dd8b 0x82a5fb52 0x8664e6e5 0xbe2b5b58 0xbaea46ef
    0xb7a96036 0xb3687d81 0xad2f2d84 0xa9ee3033 0xa4ad16ea 0xa06c0b5d
    0xd4326d90 0xd0f37027 0xddb056fe 0xd9714b49 0xc7361b4c 0xc3f706fb
    0xceb42022 0xca753d95 0xf23a8028 0xf6fb9d9f 0xfbb8bb46 0xff79a6f1
    0xe13ef6f4 0xe5ffeb43 0xe8bccd9a 0xec7dd02d 0x34867077 0x30476dc0
    0x3d044b19 0x39c556ae 0x278206ab 0x23431b1c 0x2e003dc5 0x2ac12072
    0x128e9dcf 0x164f8078 0x1b0ca6a1 0x1fcdbb16 0x018aeb13 0x054bf6a4
    0x0808d07d 0x0cc9cdca 0x7897ab07 0x7c56b6b0 0x71159069 0x75d48dde
    0x6b93dddb 0x6f52c06c 0x6211e6b5 0x66d0fb02 0x5e9f46bf 0x5a5e5b08
    0x571d7dd1 0x53dc6066 0x4d9b3063 0x495a2dd4 0x44190b0d 0x40d816ba
    0xaca5c697 0xa864db20 0xa527fdf9 0xa1e6e04e 0xbfa1b04b 0xbb60adfc
    0xb6238b25 0xb2e29692 0x8aad2b2f 0x8e6c3698 0x832f1041 0x87ee0df6
    0x99a95df3 0x9d684044 0x902b669d 0x94ea7b2a 0xe0b41de7 0xe4750050
    0xe9362689 0xedf73b3e 0xf3b06b3b 0xf771768c 0xfa325055 0xfef34de2
    0xc6bcf05f 0xc27dede8 0xcf3ecb31 0xcbffd686 0xd5b88683 0xd1799b34
    0xdc3abded 0xd8fba05a 0x690ce0ee 0x6dcdfd59 0x608edb80 0x644fc637
    0x7a089632 0x7ec98b85 0x738aad5c 0x774bb0eb 0x4f040d56 0x4bc510e1
    0x46863638 0x42472b8f 0x5c007b8a 0x58c1663d 0x558240e4 0x51435d53
    0x251d3b9e 0x21dc2629 0x2c9f00f0 0x285e1d47 0x36194d42 0x32d850f5
    0x3f9b762c 0x3b5a6b9b 0x0315d626 0x07d4cb91 0x0a97ed48 0x0e56f0ff
    0x1011a0fa 0x14d0bd4d 0x19939b94 0x1d528623 0xf12f560e 0xf5ee4bb9
    0xf8ad6d60 0xfc6c70d7 0xe22b20d2 0xe6ea3d65 0xeba91bbc 0xef68060b
    0xd727bbb6 0xd3e6a601 0xdea580d8 0xda649d6f 0xc423cd6a 0xc0e2d0dd
    0xcda1f604 0xc960ebb3 0xbd3e8d7e 0xb9ff90c9 0xb4bcb610 0xb07daba7
    0xae3afba2 0xaafbe615 0xa7b8c0cc 0xa379dd7b 0x9b3660c6 0x9ff77d71
    0x92b45ba8 0x9675461f 0x8832161a 0x8cf30bad 0x81b02d74 0x857130c3
    0x5d8a9099 0x594b8d2e 0x5408abf7 0x50c9b640 0x4e8ee645 0x4a4ffbf2
    0x470cdd2b 0x43cdc09c 0x7b827d21 0x7f436096 0x7200464f 0x76c15bf8
    0x68860bfd 0x6c47164a 0x61043093 0x65c52d24 0x119b4be9 0x155a565e
    0x18197087 0x1cd86d30 0x029f3d35 0x065e2082 0x0b1d065b 0x0fdc1bec
    0x3793a651 0x3352bbe6 0x3e119d3f 0x3ad08088 0x2497d08d 0x2056cd3a
    0x2d15ebe3 0x29d4f654 0xc5a92679 0xc1683bce 0xcc2b1d17 0xc8ea00a0
    0xd6ad50a5 0xd26c4d12 0xdf2f6bcb 0xdbee767c 0xe3a1cbc1 0xe760d676
    0xea23f0af 0xeee2ed18 0xf0a5bd1d 0xf464a0aa 0xf9278673 0xfde69bc4
    0x89b8fd09 0x8d79e0be 0x803ac667 0x84fbdbd0 0x9abc8bd5 0x9e7d9662
    0x933eb0bb 0x97ffad0c 0xafb010b1 0xab710d06 0xa6322bdf 0xa2f33668
    0xbcb4666d 0xb8757bda 0xb5365d03 0xb1f740b4
)

<span style="color: #7fffd4; font-weight: bold;">cksum</span>() {
    <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Calculate CRC for file contents.</span>
    <span style="color: #98fb98; font-weight: bold;">local</span> byte crc len <span style="color: #7fffd4; font-weight: bold;">LANG</span>=C <span style="color: #7fffd4; font-weight: bold;">IFS</span>=
    <span style="color: #fa8072;">while </span><span style="color: #98fb98; font-weight: bold;">read</span> -r -d <span style="color: #ffa07a;">''</span> -n 1 byte ; <span style="color: #fa8072;">do</span>
        <span style="color: #7fffd4; font-weight: bold;">byte</span>=$(<span style="color: #fa8072;">printf "%d" \'$byte</span>)
        ((len++))
        ((crc = 0xffffffff &amp; ((crc&lt;&lt;8) ^ table[(crc &gt;&gt; 24) ^ byte])))
    <span style="color: #fa8072;">done</span>

    <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Include file size in the CRC.</span>
    <span style="color: #7fffd4; font-weight: bold;">n</span>=len
    <span style="color: #fa8072;">while</span> ((n)) ; <span style="color: #fa8072;">do</span>
        ((byte = n &amp; 255))
        ((n &gt;&gt;= 8))
        ((crc = 0xffffffff &amp; ((crc &lt;&lt; 8) ^ table[(crc &gt;&gt; 24) ^ byte])))
    <span style="color: #fa8072;">done</span>
    ((crc = 0xffffffff &amp; ~crc))
    <span style="color: #98fb98; font-weight: bold;">printf</span> <span style="color: #ffa07a;">"%u %d"</span> $<span style="color: #7fffd4; font-weight: bold;">crc</span> $<span style="color: #7fffd4; font-weight: bold;">len</span>
}

<span style="color: #fa8072;">if</span> [ <span style="color: #ffa07a;">"$*"</span> ] ; <span style="color: #fa8072;">then</span>
    <span style="color: #fa8072;">for</span> file<span style="color: #fa8072;"> in</span> <span style="color: #ffa07a;">"$@"</span> ; <span style="color: #fa8072;">do</span>
        cksum &lt; <span style="color: #ffa07a;">"$file"</span> &amp;&amp; <span style="color: #98fb98; font-weight: bold;">echo</span> <span style="color: #ffa07a;">" $file"</span>
    <span style="color: #fa8072;">done</span>
<span style="color: #fa8072;">else</span>
    cksum
    <span style="color: #98fb98; font-weight: bold;">echo</span>
<span style="color: #fa8072;">fi</span>
</pre>
</div>

<p>
Credit to <a href="https://f-hauri.ch/">F. Hauri</a> on StackOverflow for showing <a href="https://stackoverflow.com/a/13890319/182734">how to read binary
bytes in Bash</a>.
</p>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Sonifying the Tides with J</title>
<link>https://remcycles.net/blog/tides_j.html</link>
<pubDate>Tue, 18 Nov 2025 21:30:00 -0800</pubDate>
<guid>https://remcycles.net/blog/tides_j.html</guid>
<description>
<![CDATA[<p>
Prior to my presentations at the <a href="https://dsponlineconference.com">DSP Online Conference</a> and the
inaugural <a href="https://www.signalprocessingsummit.com/index.php#speakers-title">Signal Processing Summit</a> I ported my C code for sonifying
the tides to the <a href="https://jsoftware.com">J</a> language.  I like how terse it is compared to the C
version.
</p>

<p>
<a href="https://remcycles.net/blog/../files/j/tides.ijs">tides.ijs</a>:
</p>
<div class="org-src-container">
<pre class="src src-j"><span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">tides.ijs, sonify the tides using harmonic constituent data fro</span><span style="color: #add8e6;">m</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">NOAA</span><span style="color: #add8e6;">.</span>
<span style="color: #add8e6;">NB.</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">Copyright &#169; 2025 Remington Furma</span><span style="color: #add8e6;">n</span>
<span style="color: #add8e6;">NB.</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">SPDX-License-Identifier: MI</span><span style="color: #add8e6;">T</span>
<span style="color: #add8e6;">NB.</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">Permission is hereby granted, free of charge, to any perso</span><span style="color: #add8e6;">n</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">obtaining a copy of the software demonstrated in code cells (th</span><span style="color: #add8e6;">e</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">"Software"), to deal in the Software without restriction, includin</span><span style="color: #add8e6;">g</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">without limitation the rights to use, copy, modify, merge, publish</span><span style="color: #add8e6;">,</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">distribute, sublicense, and/or sell copies of the Software, and t</span><span style="color: #add8e6;">o</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">permit persons to whom the Software is furnished to do so, subjec</span><span style="color: #add8e6;">t</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">to the following conditions</span><span style="color: #add8e6;">:</span>
<span style="color: #add8e6;">NB.</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">The above copyright notice and this permission notice shall b</span><span style="color: #add8e6;">e</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">included in all copies or substantial portions of the Software</span><span style="color: #add8e6;">.</span>
<span style="color: #add8e6;">NB.</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND</span><span style="color: #add8e6;">,</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES O</span><span style="color: #add8e6;">F</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AN</span><span style="color: #add8e6;">D</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDER</span><span style="color: #add8e6;">S</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN A</span><span style="color: #add8e6;">N</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR I</span><span style="color: #add8e6;">N</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN TH</span><span style="color: #add8e6;">E</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">SOFTWARE</span><span style="color: #add8e6;">.</span>

<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">Exit on error</span><span style="color: #add8e6;">:</span>
<span style="color: #ff0000; font-weight: bold;">9!:</span>29<span style="color: #ff4500;">]</span>1<span style="color: #ff4500;">[</span><span style="color: #ff0000; font-weight: bold;">9!:</span>27<span style="color: #ffa07a;">'2!:55]1'</span>

<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">Use ASCII boxes</span><span style="color: #add8e6;">:</span>
boxdraw_j_ 1

<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">wav.ijs customizes some code from the media/wav addon</span><span style="color: #add8e6;">.</span>
<span style="color: #98fb98; font-weight: bold;">load</span> <span style="color: #ffa07a;">'./wav.ijs'</span>

<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">Save as a .wav file</span><span style="color: #add8e6;">.</span>
<span style="color: #7fffd4; font-weight: bold;">save_wav</span><span style="color: #a9a9a9;">=:</span> <span style="color: #7fffd4;">dyad</span> <span style="color: #98fb98; font-weight: bold;">define</span>
  (SAMPLE_RATE wavmake x) <span style="color: #ff0000; font-weight: bold;">1!:</span>2 <span style="color: #ff4500;">&lt;</span>y
)

<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">Adapted from https://code.jsoftware.com/wiki/User:Devon_McCormick/Palette</span><span style="color: #add8e6;">s</span>
<span style="color: #7fffd4; font-weight: bold;">round_even</span><span style="color: #a9a9a9;">=:</span> <span style="color: #7fffd4;">monad</span> <span style="color: #98fb98; font-weight: bold;">define</span>
  <span style="color: #ff4500;">&lt;.</span>y<span style="color: #ff4500;">+</span>0.5<span style="color: #ff4500;">*</span>(0<span style="color: #ff4500;">~:</span>2<span style="color: #ff4500;">|&lt;.</span>y)<span style="color: #ff4500;">+.</span>0.5<span style="color: #ff4500;">~:</span>1<span style="color: #ff4500;">|</span>y
)

<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">Audio setu</span><span style="color: #add8e6;">p</span>
<span style="color: #7fffd4; font-weight: bold;">SAMPLE_RATE</span><span style="color: #a9a9a9;">=:</span> 44100 <span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">H</span><span style="color: #add8e6;">z</span>
<span style="color: #7fffd4; font-weight: bold;">SAMPLE_SIZE</span><span style="color: #a9a9a9;">=:</span> 16    <span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">bit</span><span style="color: #add8e6;">s</span>

<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">Scaling factor</span><span style="color: #add8e6;">s</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">TODO: Determine max amplitude encountered at any station</span><span style="color: #add8e6;">.</span>
<span style="color: #7fffd4; font-weight: bold;">GAIN</span><span style="color: #a9a9a9;">=:</span> 0.3  <span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">Allow for headroom</span><span style="color: #add8e6;">.</span>
<span style="color: #7fffd4; font-weight: bold;">MAX_PCM_AMP</span><span style="color: #a9a9a9;">=:</span> (2<span style="color: #ff4500;">^</span>(SAMPLE_SIZE<span style="color: #ff4500;">-</span>1))<span style="color: #ff4500;">*</span>GAIN
<span style="color: #7fffd4; font-weight: bold;">FT_TO_AMP</span><span style="color: #a9a9a9;">=:</span> MAX_PCM_AMP <span style="color: #ff4500;">%</span> 13.0
<span style="color: #7fffd4; font-weight: bold;">DPH_TO_RPS</span><span style="color: #a9a9a9;">=:</span> 2p1<span style="color: #ff4500;">%</span>(60<span style="color: #ff4500;">*</span>60<span style="color: #ff4500;">*</span>360.0)  <span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">(degrees/hour) to (rad/second</span><span style="color: #add8e6;">)</span>
<span style="color: #7fffd4; font-weight: bold;">FREQ_SCALE</span><span style="color: #a9a9a9;">=:</span> 60<span style="color: #ff4500;">*</span>60<span style="color: #ff4500;">*</span>10000.0      <span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">times realtim</span><span style="color: #add8e6;">e</span>

<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">Synthesize a single harmonic constituent</span><span style="color: #add8e6;">.</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">x: number of output sample</span><span style="color: #add8e6;">s</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">y: harmonic constituents (amplitude, phase, speed</span><span style="color: #add8e6;">)</span>
<span style="color: #7fffd4; font-weight: bold;">synth_harcon</span><span style="color: #a9a9a9;">=:</span> <span style="color: #7fffd4;">dyad</span> <span style="color: #98fb98; font-weight: bold;">define</span> <span style="color: #00bfff;">"</span>0 1
  <span style="color: #7fffd4; font-weight: bold;">amp</span><span style="color: #a9a9a9;">=.</span> 0<span style="color: #ff4500;">{</span>y
  <span style="color: #7fffd4; font-weight: bold;">phase</span><span style="color: #a9a9a9;">=.</span> 360 <span style="color: #ff4500;">%</span><span style="color: #7cfc00;">~</span> 2p1 <span style="color: #ff4500;">*</span> 1<span style="color: #ff4500;">{</span>y
  <span style="color: #7fffd4; font-weight: bold;">ang_vel</span><span style="color: #a9a9a9;">=.</span> FREQ_SCALE <span style="color: #ff4500;">*</span> DPH_TO_RPS<span style="color: #ff4500;">*</span>(2<span style="color: #ff4500;">{</span>y) <span style="color: #ff4500;">%</span> SAMPLE_RATE
  <span style="color: #7fffd4; font-weight: bold;">phases</span><span style="color: #a9a9a9;">=.</span> phase <span style="color: #ff4500;">+</span> 2p1<span style="color: #ff4500;">|</span>ang_vel<span style="color: #ff4500;">*</span>(<span style="color: #ff4500;">i.</span> x)
  <span style="color: #ff4500;">]</span><span style="color: #7fffd4; font-weight: bold;">samps</span><span style="color: #a9a9a9;">=.</span> amp <span style="color: #ff4500;">*</span> 1 <span style="color: #ff4500;">o.</span> phases
)

<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">Synthesize all the harmonic constituents at a tide station an</span><span style="color: #add8e6;">d</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">save the waveform as a .wav audio file</span><span style="color: #add8e6;">.</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">x: number of output sample</span><span style="color: #add8e6;">s</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">y: boxed station inf</span><span style="color: #add8e6;">o</span>
<span style="color: #7fffd4; font-weight: bold;">synth_station</span><span style="color: #a9a9a9;">=:</span> <span style="color: #7fffd4;">dyad</span> <span style="color: #98fb98; font-weight: bold;">define</span>
  <span style="color: #7fffd4; font-weight: bold;">id</span><span style="color: #a9a9a9;">=.</span><span style="color: #ff4500;">".&gt;{.{.{.</span> y
  <span style="color: #7fffd4; font-weight: bold;">harcons</span><span style="color: #a9a9a9;">=.</span><span style="color: #ff4500;">".&gt;</span>(3 4 5) <span style="color: #ff4500;">{</span><span style="color: #00bfff;">"</span>1 y <span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">Just the facts, please</span><span style="color: #add8e6;">.</span>
  <span style="color: #7fffd4; font-weight: bold;">feet</span><span style="color: #a9a9a9;">=.</span><span style="color: #ff4500;">+</span><span style="color: #7cfc00;">/</span> x synth_harcon harcons
  <span style="color: #7fffd4; font-weight: bold;">samps</span><span style="color: #a9a9a9;">=.</span> round_even FT_TO_AMP<span style="color: #ff4500;">*</span>feet
  echo (<span style="color: #ff4500;">":</span>id)

  samps save_wav <span style="color: #ffa07a;">'./output/'</span><span style="color: #ff4500;">,</span> (<span style="color: #ff4500;">":</span>id)<span style="color: #ff4500;">,</span> <span style="color: #ffa07a;">'.wav'</span>
  0  <span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">We only care about side-effects, so return a dummy value</span><span style="color: #add8e6;">.</span>
)

<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">Read harmonic constituents</span><span style="color: #add8e6;">:</span>
<span style="color: #98fb98; font-weight: bold;">load</span> <span style="color: #ffa07a;">'tables/csv'</span>
<span style="color: #7fffd4; font-weight: bold;">dat</span><span style="color: #a9a9a9;">=:</span> readcsv <span style="color: #98fb98; font-weight: bold;">jpath</span> <span style="color: #ffa07a;">'harcon_amp.csv'</span>

<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">Group and box each station</span><span style="color: #add8e6;">:</span>
<span style="color: #7fffd4; font-weight: bold;">stations</span><span style="color: #a9a9a9;">=:</span> (<span style="color: #ff4500;">{.</span><span style="color: #00bfff;">"</span>1 dat) <span style="color: #ff4500;">&lt;</span><span style="color: #7cfc00;">/.</span> dat

<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">Uncomment to use a short dataset for testing</span><span style="color: #add8e6;">:</span>
<span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">stations=: 100{.station</span><span style="color: #add8e6;">s</span>

<span style="color: #7fffd4; font-weight: bold;">main</span><span style="color: #a9a9a9;">=:</span> <span style="color: #7fffd4;">monad</span> <span style="color: #98fb98; font-weight: bold;">define</span>
  <span style="color: #7fffd4; font-weight: bold;">DUR_SEC</span><span style="color: #a9a9a9;">=.</span> 10.0
  <span style="color: #7fffd4; font-weight: bold;">DUR_SAMP</span><span style="color: #a9a9a9;">=.</span> round_even SAMPLE_RATE<span style="color: #ff4500;">*</span>DUR_SEC

  <span style="color: #fa8072;">if.</span> 0 <span style="color: #fa8072;">do.</span>
    <span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">Single threade</span><span style="color: #add8e6;">d</span>
    DUR_SAMP (synth_station <span style="color: #ff4500;">&gt;</span>)<span style="color: #00bfff;">"</span>0 stations
  <span style="color: #fa8072;">else.</span>
    <span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">Multi-threaded</span><span style="color: #add8e6;">.</span>
    <span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">Initialize threadpool 0 with N-1 threads</span><span style="color: #add8e6;">.</span>
    <span style="color: #fa8072;">{{</span>0 <span style="color: #ff4500;">T.</span>0<span style="color: #fa8072;">}}</span><span style="color: #00bfff;">^:</span><span style="color: #ff4500;">]</span> <span style="color: #ff4500;">&lt;:</span> <span style="color: #ff4500;">{.</span> 8 <span style="color: #ff4500;">T.</span> <span style="color: #ffa07a;">''</span>
    <span style="color: #ff4500;">]</span><span style="color: #00bfff;">&amp;.</span><span style="color: #ff4500;">&gt;</span> DUR_SAMP (synth_station <span style="color: #ff4500;">&gt;</span>)<span style="color: #00bfff;">t.</span><span style="color: #ffa07a;">''</span><span style="color: #00bfff;">"</span>0 stations
    <span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">The ]&amp;.&gt; verb waits for every pyx to be populated, but i</span><span style="color: #add8e6;">s</span>
    <span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">otherwise a no-op</span><span style="color: #add8e6;">.</span>
    <span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">J9.6 will crash if exit is called and tasks are still running</span><span style="color: #add8e6;">.</span>
    <span style="color: #add8e6;">NB. </span><span style="color: #add8e6;">J9.7 won't crash, but also doesn't wait for unfinished threads</span><span style="color: #add8e6;">.</span>
  <span style="color: #fa8072;">end.</span>
)

main<span style="color: #ffa07a;">''</span>
<span style="color: #98fb98; font-weight: bold;">exit</span><span style="color: #ffa07a;">''</span>
</pre>
</div>

<p>
The code uses this CSV data file which has all non-zero amplitude
harmonic constituents for all 1274 NOAA tide prediction stations (as
of 2018):
</p>

<p>
<a href="https://remcycles.net/blog/../files/tides/harcon_amp.csv.gz">harcon<sub>amp.csv.gz</sub></a>
</p>


<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Sonifying the Tides with C</title>
<link>https://remcycles.net/blog/tides_c.html</link>
<pubDate>Tue, 18 Nov 2025 08:00:00 -0800</pubDate>
<guid>https://remcycles.net/blog/tides_c.html</guid>
<description>
<![CDATA[<p>
Here is the C code and associated scripts that I used for <a href="https://remcycles.net/blog/./tides.html">sonifying
the tides</a>, updated for my recent presentations at the <a href="https://dsponlineconference.com">DSP Online
Conference</a> and the inaugural <a href="https://www.signalprocessingsummit.com/index.php#speakers-title">Signal Processing Summit</a>.
</p>

<p>
It's licensed under the GPLv3, and only tested in Linux.  If you make
something cool with it or have questions or comments, please <a href="mailto:blog@remcycles.net">let me
know</a>!
</p>

<p>
<a href="https://remcycles.net/blog/../files/tides/tides_c.tar.gz">tides<sub>c.tar.gz</sub></a>
</p>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Digital Oscillator Deep Dive</title>
<link>https://remcycles.net/blog/viete_cheb.html</link>
<pubDate>Wed, 05 Nov 2025 00:00:00 -0800</pubDate>
<guid>https://remcycles.net/blog/viete_cheb.html</guid>
<description>
<![CDATA[<p>
It doesn't get more "cycles" than sinusoids.  This post is about
efficiently generating sine waves with the fewest CPU cycles,
something I investigated while preparing my presentation for the
Signal Processing Summit and DSP Online Conference.
</p>

<p>
My original desktop program to sonify the tides simply used the C
standard library cosine function, <code>cos()</code>. When I ported that to
the <a href="https://www.pjrc.com/store/teensy32.html">Teensy 3.2</a> with an <a href="https://www.pjrc.com/store/teensy3_audio.html">audio adapter</a> in 2016 that didn't perform well
enough and I had to resort to a Taylor series approximation run it in
real-time on that device.
</p>

<p>
I've learned some new tricks since then.
</p>

<p>
First, the Levine-Vicanek quadrature oscillator can output a new
sine-cosine pair with just three multiplies and three additions using
only the last output pair.  It reduced the total run-time of my tide
sonification program by 87% on my laptop.
</p>

<p>
Rick Lyons <a href="https://www.dsprelated.com/showarticle/1467.php">wrote about it on DSPRelated.com in 2023</a> and provided a new
proof of it's stability.  Vicanek sketched a different stability proof
in <a href="https://www.vicanek.de/articles.htm">his 2015 paper</a>, but it took me a while to understand it.
</p>

<p>
Second, just two days before I presented at the <a href="https://signalprocessingsummit.com">Signal Processing
Summit</a> I stumbled across the <a href="https://en.wikipedia.org/wiki/List_of_trigonometric_identities#Chebyshev_method">a recurrence relation for cosine</a> in <a href="https://store.doverpublications.com/products/9780486152936">Real
Computing Made Real, by Forman S. Acton</a>, p. 173:
</p>

<p>
\[\cos((n+1)\theta) = 2\cos(\theta)\cos(n\theta)-\cos((n-1)\theta)\]
</p>

<p>
This outputs a new cosine value with just one multiply and one
addition using the two previous outputs. I raced to implement it
and included the performance results as a bonus slide: a 90% reduction
in total run-time.  Two of them running in parallel offset by 90
degrees would give a sine-cosine pair in just two multiples and two
additions.
</p>

<p>
I would not have understood the utility of this equation before I
implemented the Levine-Vicanek quadrature oscillator to optimize my
tide sonification program.
</p>


<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Tides at the Inaugural Signal Processing Summit</title>
<link>https://remcycles.net/blog/sps2025.html</link>
<pubDate>Sun, 19 Oct 2025 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/sps2025.html</guid>
<description>
<![CDATA[<p>
Last week I attended and presented at the inaugural <a href="https://signalprocessingsummit.com/">Signal Processing
Summit</a> near San Jose, California and it was a great success.  Many,
many thanks to Stephane Boucher for organizing such a lovely
conference and bringing a great group of talented people together.  It
was nice to meet a diverse group of signal processing experts from
different domains, including audio, communications, and radar.  I
learned a lot from the other speakers' presentations and from
conversations between sessions and over meals.
</p>

<p>
This was also my second time meeting <a href="https://www.dsp-coach.com/about-us">Dan Boschen</a> after last month's
<a href="https://events.gnuradio.org/event/26/">GNU Radio Conference</a> in Everett, WA.  It was Dan that first suggested
I present at this conference.
</p>

<p>
I presented about "Sonifying the Tides", with more focus on
mechanical tide computers, tidal physics, and some neat signal
processing aspects of predicting the tides.  In particular, the
<a href="https://muzemazer.com/SymplecticOscillator.pdf">Levine</a>-<a href="https://www.vicanek.de/articles/QuadOsc.pdf">Vicanek</a> oscillator <a href="https://www.dsprelated.com/showarticle/1467.php">described by Rick Lyons in 2023</a> on
<a href="https://www.dsprelated.com">DSPRelated.com</a> provided a very substantial performance boost to my
tide prediction program (an 87% decrease in total run-time) compared
to calling the C standard library <code>cos()</code> function for generating
sinusoid waves and 3.5 hours of tide audio.  An even better
improvement was obtained by using <a href="https://en.wikipedia.org/wiki/List_of_trigonometric_identities#Chebyshev_method">Chebychev's recurrence relation for
cosine</a>.  I will write more on both methods and their stability in a
future post&#x2026;
</p>

<p>
Overall, I think my presentation was well received and I was asked
great questions both during and after my talk.
</p>

<p>
<a href="https://remcycles.net/blog/../files/tides/tides_presentation_sps2025.pdf">Here are the slides I presented</a>.
</p>

<p>
I will also be recording a version of this talk for the <a href="https://www.dsponlineconference.com/">2025 Online
DSP Conference</a>.  That conference will include versions of all the
in-person presentations and a few more speakers, including <a href="http://www.digitalsignallabs.com/home.htm">Randy
Yates</a>.  Randy was the second person to suggest I present, and I'm very
glad I did.
</p>

<p>
This all started after I fell in love with the mechanical tide
computer at the <a href="https://pacificsciencecenter.org/">Pacific Science Center</a> in 2016 when I worked there as
an Exhibit Technician.  Unfortunately, that exhibit was recently
removed from their floor.
</p>

<p>
Thankfully, <a href="https://www.ocean.washington.edu/home/Bill_Nitsche">Bill Nitsche</a> at the University of Washington School of
Oceanography was very generous with his time and willing to show me
the mechanical tide computer and Puget Sound model they still have
there.  That meant I was able to include a video of the machine in
action during my talk, and that was very helpful for explaining its
operation.
</p>


<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>A Simple DIY Laptop Stand</title>
<link>https://remcycles.net/blog/laptop_stand.html</link>
<pubDate>Fri, 19 Sep 2025 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/laptop_stand.html</guid>
<description>
<![CDATA[<p>
Here's a simple laptop stand that I really enjoy and is easy to make.
</p>

<p>
Simply rip a 2x4 on a table saw at a ten degree angle enough times to
make a snug fit on the bottom edge of your laptop.
</p>

<p>
This setup saves space and brings the laptop screen up to the same
level as a second monitor.
</p>


<div id="org36494a5" class="figure">
<p><a href="https://remcycles.net/blog/../images/laptop_stand_detail.jpg" width="500px"><img src="https://remcycles.net/blog/../images/laptop_stand_detail.jpg" alt="laptop_stand_detail.jpg" width="500px" /></a>
</p>
</div>


<div id="org0f26815" class="figure">
<p><a href="https://remcycles.net/blog/../images/laptop_stand_rick.jpg" width="500px"><img src="https://remcycles.net/blog/../images/laptop_stand_rick.jpg" alt="laptop_stand_rick.jpg" width="500px" /></a>
</p>
</div>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Tiger: A Stylish Cat</title>
<link>https://remcycles.net/blog/tiger.html</link>
<pubDate>Sat, 02 Apr 2022 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/tiger.html</guid>
<description>
<![CDATA[<p>
Okay, this is one of the stupidest programs I've written, but once I
had the idea I couldn't not do it.
</p>

<p>
Here's what it does:
</p>
<pre class="example" id="org8c2c876">
$ xxd tiger | ./tiger -i | head -n96
0000   0: 7f45 4  6 0201 010   000 000    00 0000  .ELF.....    ...
0000   0: 0300 3  0 0100 000   007 000     0 0000  ..&gt;.......   ...
0000   0: 4000 00 0 0000 0000   24 000     0 0000  @ .......$.  ...
000   30: 0000 0000 4000 3800   00 400     0 1c00  .  .@.8...@   ..
000   40: 0600 0000 0400 0000   00 000       0000  .  .....@...  ..
000   50: 4000 0000 0000 0000   00 000       0000  @.  ....@...   .
00   060: f801 0000 0000 0000 f  1 0000      0000  ..   ........  .
00   070: 0800 00 0 0000 0000 0  0 0000       000  ...   .......   
00   080: 3802 00 0 0000 0000 3  2 0000 0     000  8...  ..8....   
00  0090: 3802 00   0000 0000 1  0 0000 0     000  8...  .......   
00  00a0: 1c00 00   0000 0000    0 0000 0    0000  ....   .......  
00  00b0: 0100 0    0500 0000    0 0000      0000  ....  ........  
00  00c0: 0000 0    0000 000    00 0000    0 0000  ....  ......... 
00 000d0: 480d      0000 00     0d 000    00 0000  H...  ..H...... 
000000e0: 000     0 0000 00    100 000    00 0000  .. .   .........
000000f0: 800     0 0000 0     00d 20     00 0000  ...   .... .....
00000100: 80     00 0000      a00b 00    000  000  .. .  ..........
00000110: b0     00 0000      0000 2     000   00  ...  ..... .....
00000120: 0      00 060     0 900d 0    0000   00  ..  ............
00000130: 9     000 00      0 900d      0000   00  ..   ..... .....
00 00140:       000 00     00 f001    0 0000   00  ..  ............
00 00150:      0000 0      00 0400    0 0400   00  .   ............
00 00160:      0000 0     000 540    00 0000   00  T    ...T.  ....
00 00170:      0000 0     000 440    00 000    00  T    ...D.  ....
00 00180:    0 0000 0     000 040    00 000    00  D    .....  ....
00  0190     5 7464 0    0000 dc    000 000   000  P   ......   ...
0   01a0    0b 0000 0    0000 dc    000 000   000  .   ......   ...
0   01b0    00 0000 0    0000 44    000 00    000  D   ....D.   ...
0   01c0    00 0000 0    0000 5     464 06    000  .   ....Q.   ...
0   01d0    00 0000      0000 0    0000 00   0000  .   ......   ...
0   01e0    00 0000    0 0000 0    0000 0    0000  .  .......   ...
    01f0    00 000     0 0000    0 0000 0  0 0000  .  ........   ..
    0200:   e5 746    00 0000   0d 0000    0 0000  R  d.......   ..
    0210:   0d 200    00 000    0d 2000    0 0000      ...... ..   
    0220:   02 00    000 00    002 0000    0 0000     ........    .
0   0230:    0 00   0000      2f6c 6962   34 2f6c     ...../lib   l
0   0240:    d 6c   6e75    d 783   62d   34 2e7      inux-x86-   s
0   0250:    e 32 0 040     0 100   000   00 000      .........    
00  0260:   4e 5  0 00     00 03   0000   00 000      .........    
00  0270:   00 0  0 04    000 14   0000 0 00 00       ........     
00  0280    4e 5 00 7    d9e0 d    9e7f 4  2 be       .p......     
000 0290   8e8   5f 2  e 6a70    0 0000 0  0 00       _%.jp..      
000 0 a0   100   00   00 000    00 2000 80 0 00      ........      
00000 b0   000   00  e00 00    755 6110 0000 00      ......gU      
0000  c0   000   00  000 00   0000 0000 0000 00      .........     
0000  d0: 000    00 0000 0    1500 0000 1200 00      .........     
0000  e0: 000    00 0000 0  0 0000 0000 0000 0       .........    .
0000  f0: 860   000 2000 0  0 0000 0000 0000 0       .. .......    
0000  00: 000   000 0000 0  0 1000 0000 1200 0       .........    .
0000  10: 000   000 0000 0    0000 0000 0000 0       .........   ..
0000  20: 230   000 1200 00    000 0000 0000 0       ........    ..
0000   0: 000    00 0000 000     0 0000 1200 0       ......^.   ...
0000   0: 000    00 0000 0000       000 0000 0       .......   ....
00000  0: a20    00 2000 0000 0      00 0000 0       .. .....   ...
00000  0: 0000   00 00 0 0000 55      0 1200 00      ......    ....
000003  : 0000    0 00    000 000     0 0000 00      ......   .....
000003    3100    0 120     0 0000      0000 00       ....    .....
0000039   0000 0  0 0000      0b00 0     200 000      ....    .....
00 003a0  0000 0  0 0000 0     000 00     00 000      ....    .....
00  03b0   100 0  0 2000 00    000 000    00 000        ...    ....
000   c0: 0000 0  0 0000 000   600 0000    0 0000       ...   ."...
000    0: 0000 0  0 0000 0000   00 0000    0 0000       ...   .....
0000   0: 2a00 0  0 1200 0000   00 0000      0000  *     ..   .....
00000   : 0000 0    0000 0000   00 0000 1     000  .     ..8  .... 
000004  : 0000 00   0000 0000 0  0 0000 00     00  ..    ...  .... 
0000041   1d00 00   1100 1800 2  9 2000 000    00  ..    .. .   ...
0000042   0800 00    000 0000 0  c 6962 632     f  ..    ...l bc.s 
000 0430   e36 006    69 7400 70 5 7473 0070       .6.   t.pu s.pu 
000  440    68 617    73 7464 69 e 0070 7269 6      ha   tdin prin 
0000 450:    0 7374    3 7472 00 7 6574 6f70 7      .s    r.getopt 
0000  60: 5    6374 7    655f 62 f 6c6f 6300 5f     _ct   _b_loc._ 
00000  0: 63    15f 66    e61 6c69 7a65 005f 494    xa_    lize._I 
00000   : 5f6   574 63    f5f 6c69 6263 5f73 746    get    libc_st 
00000   : 7274   6d 616    00 474c 4942 435f 322     _ma   GLIBC_2.
000004    3300    c 4942    f 322e 3    3500 5f49    GLI   2.2.5._I
000004    544d 5  4 6572    7 6973 74    254 4d43    _de   isterTMC
000004    6c6f 6e   5461 6    6500 5f5    6d 6f6e     eT   e.__gmon
000004    5f73 746   274 5f    05f 4954    f 7265  _  ar   ._ITM_re
000004    6769 7374  572 54    36c 6f6e 6    6162  g  te   CloneTab
000004    6c65 0000 0000 020    00 0200 02    200  l  ..   ........
000005    0000 0200 0200 020     0 0200 020    00  .. ..   ........
000005  : 0200 00 0 0000 0000      0200 010     0  .. ..  . .......
000005  : 1000 00   0000 0000 1     90d 0000    0  .....  .  i.....
000005  : 7000 00   1000 0000 7      09 0000 0     p....  .  i.....
00000   : 7a00 00   0000 0000 80      0 0000 0     z..... .   .....
00000   : 0800 00    000 0000 a00     0 0000 0     ........   .....
00000   : 880d 20   0000 0000 080       0000 00     . ......   ....
00000   : 6008 00   0000 0000 0810      0000 00     ........   ....
00000   : 0800 0    0000 0000 0810      0000 000     .......   ....
00000   : d80f 2    0000 0000 0600 0    0200 000      .......  ....
00000   : 0000 0    0000 0000 e00f 2    0000 0000     ......   ....
00000   : 0600      0500 000  0000 00    000 0000  .  ......  .....
00000   : e80f      0000 000  0600 00    600 0000  ..   .....  ....
00000   : 0000 0  0 0000 000  f00f 20    000 0000  ... .....    ...
00000   : 0600 0  0 0a00 000   000 00     00 0000  .........   ....
0000    : f80f 2  0 0000 000   600 00     00 0000  .. .......   ...
</pre>

<p>
Here's the source (<a href="https://remcycles.net/blog/../files/tiger/tiger.c">tiger.c</a>):
</p>
<div class="org-src-container">
<pre class="src src-c"><span style="color: #add8e6;">/* </span><span style="color: #add8e6;">tiger -- Tiger print standard input to standard output.</span>
<span style="color: #add8e6;">   Copyright (C) 2022 Remington Furman</span>
<span style="color: #add8e6;">   This program is free software: you can redistribute it and/or modify</span>
<span style="color: #add8e6;">   it under the terms of the GNU General Public License as published by</span>
<span style="color: #add8e6;">   the Free Software Foundation, either version 3 of the License, or</span>
<span style="color: #add8e6;">   (at your option) any later version.</span>
<span style="color: #add8e6;">   This program is distributed in the hope that it will be useful,</span>
<span style="color: #add8e6;">   but WITHOUT ANY WARRANTY; without even the implied warranty of</span>
<span style="color: #add8e6;">   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span>
<span style="color: #add8e6;">   GNU General Public License for more details.</span>
<span style="color: #add8e6;">   You should have received a copy of the GNU General Public License</span>
<span style="color: #add8e6;">   along with this program.  If not, see <a href="https://www.gnu.org/licenses/&gt;.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h">&lt;https://www.gnu.org/licenses/&gt;.</a></span><a href="https://www.gnu.org/licenses/&gt;.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h">
</a><span style="color: #add8e6;"><a href="https://www.gnu.org/licenses/&gt;.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h">*/</a></span><a href="https://www.gnu.org/licenses/&gt;.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h">

</a><span style="color: #fa8072;"><a href="https://www.gnu.org/licenses/&gt;.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h">#include</a></span><a href="https://www.gnu.org/licenses/&gt;.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h"> </a><span style="color: #ffa07a;"><a href="https://www.gnu.org/licenses/&gt;.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h">&lt;stdio.h&gt;</a></span><a href="https://www.gnu.org/licenses/&gt;.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h">
</a><span style="color: #fa8072;"><a href="https://www.gnu.org/licenses/&gt;.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h">#include</a></span><a href="https://www.gnu.org/licenses/&gt;.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h"> </a><span style="color: #ffa07a;"><a href="https://www.gnu.org/licenses/&gt;.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h">&lt;stdlib.h&gt;</a></span><a href="https://www.gnu.org/licenses/&gt;.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h">
</a><span style="color: #fa8072;"><a href="https://www.gnu.org/licenses/&gt;.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h">#include</a></span><a href="https://www.gnu.org/licenses/&gt;.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h"> </a><span style="color: #ffa07a;"><a href="https://www.gnu.org/licenses/&gt;.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h">&lt;ctype.h&gt;</a></span><a href="https://www.gnu.org/licenses/&gt;.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h">
</a><span style="color: #fa8072;"><a href="https://www.gnu.org/licenses/&gt;.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h">#include</a></span><a href="https://www.gnu.org/licenses/&gt;.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h"> </a><span style="color: #ffa07a;"><a href="https://www.gnu.org/licenses/&gt;.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h">&lt;string.h&gt;</a></span><a href="https://www.gnu.org/licenses/&gt;.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h">
</a><span style="color: #fa8072;"><a href="https://www.gnu.org/licenses/&gt;.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h">#include</a></span><a href="https://www.gnu.org/licenses/&gt;.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h"> </a><span style="color: #ffa07a;"><a href="https://www.gnu.org/licenses/&gt;.
*/

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;ctype.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h">&lt;getopt.h&gt;</a></span>
<span style="color: #fa8072;">#include</span> <span style="color: #ffa07a;">"tiger.h"</span>
<span style="color: #fa8072;">#include</span> <span style="color: #ffa07a;">"leopard.h"</span>

<span style="color: #9acd32; font-weight: bold;">void</span> <span style="color: #7fffd4; font-weight: bold;">usage</span>(<span style="color: #9acd32; font-weight: bold;">char</span> *<span style="color: #7fffd4; font-weight: bold;">name</span>) {
    printf(<span style="color: #ffa07a;">"usage: cat file | %s [-i] [-h] \n"</span>, name);
    printf(<span style="color: #ffa07a;">"  -i    invert pattern\n"</span>);
    printf(<span style="color: #ffa07a;">"  -h    print this help\n"</span>);
}

<span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">main</span>(<span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">argc</span>, <span style="color: #9acd32; font-weight: bold;">char</span> **<span style="color: #7fffd4; font-weight: bold;">argv</span>) {
    <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">width</span>  = tiger_width;
    <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">height</span> = tiger_height;
    <span style="color: #9acd32; font-weight: bold;">unsigned</span> <span style="color: #9acd32; font-weight: bold;">char</span> *<span style="color: #7fffd4; font-weight: bold;">image</span> = tiger_bits;

    <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">opt_invert</span> = 0;

    <span style="color: #fa8072;">if</span> (strstr(argv[0], <span style="color: #ffa07a;">"tiger"</span>) != <span style="color: #7fffd4;">NULL</span>) {
        width  = tiger_width;
        height = tiger_height;
        image  = tiger_bits;
    }
    <span style="color: #fa8072;">else</span> <span style="color: #fa8072;">if</span> (strstr(argv[0], <span style="color: #ffa07a;">"leopard"</span>) != <span style="color: #7fffd4;">NULL</span>) {
        width  = leopard_width;
        height = leopard_height;
        image  = leopard_bits;
    }

    <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">opt</span>;
    <span style="color: #fa8072;">while</span> ((opt = getopt(argc, argv, <span style="color: #ffa07a;">"ih"</span>)) != -1) {
        <span style="color: #fa8072;">switch</span> (opt) {
            <span style="color: #fa8072;">case</span> <span style="color: #ffa07a;">'i'</span>:
                opt_invert = 0x1;
                <span style="color: #fa8072;">break</span>;
            <span style="color: #fa8072;">case</span> <span style="color: #ffa07a;">'h'</span>:
                usage(argv[0]);
                exit(EXIT_SUCCESS);
                <span style="color: #fa8072;">break</span>;
            <span style="color: #fa8072;">default</span>:
                usage(argv[0]);
                exit(EXIT_FAILURE);
        }
    }

    <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">x</span> = 0;
    <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">y</span> = 0;
    <span style="color: #9acd32; font-weight: bold;">char</span> <span style="color: #7fffd4; font-weight: bold;">c</span>;
    <span style="color: #fa8072;">while</span> ((c = getc(stdin)) != EOF) {
        <span style="color: #fa8072;">if</span> (c == <span style="color: #ffa07a;">'\n'</span>) {
            x = 0;
            y = (y+1) % height;
        }
        <span style="color: #fa8072;">else</span> <span style="color: #fa8072;">if</span> (c == <span style="color: #ffa07a;">'\t'</span>) {
            x = (x+8) % width;
        }
        <span style="color: #fa8072;">else</span> <span style="color: #fa8072;">if</span> (isgraph(c)) {
            x = (x+1) % width;
            <span style="color: #9acd32; font-weight: bold;">unsigned</span> <span style="color: #9acd32; font-weight: bold;">char</span> <span style="color: #7fffd4; font-weight: bold;">byte</span>  = image[y*width + x&gt;&gt;3];
            <span style="color: #9acd32; font-weight: bold;">unsigned</span> <span style="color: #9acd32; font-weight: bold;">char</span> <span style="color: #7fffd4; font-weight: bold;">pixel</span> = (byte &gt;&gt; (x&amp;7)) &amp; 1;
            pixel ^= opt_invert;
            c = pixel ? c : <span style="color: #ffa07a;">' '</span>;
        }
        putchar(c);
    }
}
</pre>
</div>

<p>
All the code (including a Makefile and even a manpage) can be found
here:
</p>

<p>
<a href="https://remcycles.net/blog/../files/tiger/tiger.tar.gz">tiger.tar.gz</a>
</p>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Sonifying All the Tides</title>
<link>https://remcycles.net/blog/tides.html</link>
<pubDate>Sat, 04 May 2024 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/tides.html</guid>
<description>
<![CDATA[<p>
This post is an extension of my previous post and <a href="https://remcycles.net/blog/./sonifying_the_tides.html">presentation on sonifying the tides</a>.
</p>

<p>
I downloaded all the available harmonic constituent data from NOAA,
converted it to CSV, sonified it, and rendered part of each waveform
as an image.
</p>

<p>
The sound files simulate the tides at 36 million times faster than
real-time which makes the resulting waveforms audible.
</p>

<p>
Here is a <a href="https://tidesandcurrents.noaa.gov/map/?type=harcon">map of all NOAA stations with harmonic constituents data</a>.
You can find station ID numbers there and find them in the list below.
</p>

<p>
Many thanks to NOAA for providing all the data.
</p>

<p>
Enjoy!
</p>

<p xmlns:cc="http://creativecommons.org/ns#" >This work is marked with
<a href="https://creativecommons.org/publicdomain/zero/1.0/" target="_blank" rel="license noopener noreferrer" style="display:inline-block;">CC0 1.0<img style="height:1em!important;margin-left:3px;vertical-align:text-bottom;" src="../images/cc/cc.svg" alt=""><img style="height:1em!important;margin-left:3px;vertical-align:text-bottom;" src="../images/cc/zero.svg" alt="">
</a></p>


<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>A Short Introduction to Tcl</title>
<link>https://remcycles.net/blog/tcl_presentation.html</link>
<pubDate>Fri, 03 Jan 2025 00:00:00 -0800</pubDate>
<guid>https://remcycles.net/blog/tcl_presentation.html</guid>
<description>
<![CDATA[<p>
<a href="https://remcycles.net/blog/../files/tcl_intro.pdf">A Short Introduction to Tcl</a>
</p>

<p>
I gave this presentation at a <a href="https://bellingham.codes">Bellingham.Codes</a> meeting on January
2nd, 2025.
</p>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Generating Squares and Cubes with Only Addition</title>
<link>https://remcycles.net/blog/squares.html</link>
<pubDate>Fri, 04 Mar 2022 00:00:00 -0800</pubDate>
<guid>https://remcycles.net/blog/squares.html</guid>
<description>
<![CDATA[<p>
I thought of this trick while falling asleep one night a few years
ago.  I'm sure I'm not the first, but I thought it would be fun to
share anyway.
</p>

<div class="org-src-container">
<pre class="src src-c"><span style="color: #fa8072;">#include</span> <span style="color: #ffa07a;">&lt;stdio.h&gt;</span>

<span style="color: #add8e6;">/*</span>
<span style="color: #add8e6;">  Silly math trick:</span>
<span style="color: #add8e6;">  Generating square numbers with only addition.</span>
<span style="color: #add8e6;">  At each step, add n, then n+1.</span>

<span style="color: #add8e6;">  Example: from 4*4 to 5*5</span>
<span style="color: #add8e6;">  ssss n</span>
<span style="color: #add8e6;">  ssss n</span>
<span style="color: #add8e6;">  ssss n</span>
<span style="color: #add8e6;">  ssss n</span>
<span style="color: #add8e6;">  nnnn 1</span>

<span style="color: #add8e6;">Read more...</span>
<span style="color: #add8e6;">*/</span>

<span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">main</span>(<span style="color: #9acd32; font-weight: bold;">void</span>) {
  <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">n</span> = 1;
  <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">square</span> = 1;

  <span style="color: #fa8072;">while</span> (square &lt;= 256) {
    printf(<span style="color: #ffa07a;">"%d * %d = %d\n"</span>, n, n, square);
    square += n++;
    square += n;
  }
}
</pre>
</div>
]]>
</description></item>
<item>
<title>Taming Stack Overflow</title>
<link>https://remcycles.net/blog/taming_stack_overflow.html</link>
<pubDate>Sun, 18 Sep 2022 20:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/taming_stack_overflow.html</guid>
<description>
<![CDATA[<p>
No, this post isn't about taming Stack Overflow's culture, just it's
web design. I find stackoverflow.com and the related Stack Exchange
sites to be a bit cluttered and distracting.  The worst culprit for me
is the "Hot Network Questions" panel, which is explictly designed to
distract you.
</p>

<p>
Luckily, <a href="https://ublockorigin.com/">uBlock Origin</a> provides a nice solution: blocking elements of
the page at will.  I won't use a browser without it anymore.
</p>

<p>
These are the settings I use to remove the sidebar and footer content
I don't care about.  You might find them helpful too, at least as a
starting point for the customizations you want.
</p>
<div class="org-src-container">
<pre class="src src-nil">stackoverflow.com##.ps-relative.js-pinned-left-sidebar.left-sidebar
stackoverflow.com##.mb16.s-anchors__grayscale.s-anchors.s-sidebarwidget__yellow.s-sidebarwidget
stackoverflow.com##.mb16.js-join-leave-container.s-sidebarwidget
stackoverflow.com##.tex2jax_ignore.module
stackoverflow.com##.js-feed-link
stackoverflow.com##.js-footer.site-footer

stackexchange.com##.ps-relative.js-pinned-left-sidebar.left-sidebar
stackexchange.com##.mb16.s-anchors__grayscale.s-anchors.s-sidebarwidget__yellow.s-sidebarwidget
stackexchange.com##.mb16.js-join-leave-container.s-sidebarwidget
stackexchange.com##.tex2jax_ignore.module
stackexchange.com##.js-feed-link
stackexchange.com##.js-footer.site-footer

askubuntu.com##.ps-relative.js-pinned-left-sidebar.left-sidebar
askubuntu.com##.mb16.s-anchors__grayscale.s-anchors.s-sidebarwidget__yellow.s-sidebarwidget
askubuntu.com##.mb16.js-join-leave-container.s-sidebarwidget
askubuntu.com##.tex2jax_ignore.module
askubuntu.com##.js-feed-link
askubuntu.com##.js-footer.site-footer

serverfault.com##.ps-relative.js-pinned-left-sidebar.left-sidebar
serverfault.com##.mb16.s-anchors__grayscale.s-anchors.s-sidebarwidget__yellow.s-sidebarwidget
serverfault.com##.mb16.js-join-leave-container.s-sidebarwidget
serverfault.com##.tex2jax_ignore.module
serverfault.com##.js-feed-link
serverfault.com##.js-footer.site-footer

superuser.com##.ps-relative.js-pinned-left-sidebar.left-sidebar
superuser.com##.mb16.s-anchors__grayscale.s-anchors.s-sidebarwidget__yellow.s-sidebarwidget
superuser.com##.mb16.js-join-leave-container.s-sidebarwidget
superuser.com##.tex2jax_ignore.module
superuser.com##.js-feed-link
superuser.com##.js-footer.site-footer
</pre>
</div>

<p>
Before:
</p>

<div id="org9d117d1" class="figure">
<p><a href="https://remcycles.net/blog/../images/so_before.png" width="600"><img src="https://remcycles.net/blog/../images/so_before.png" alt="so_before.png" width="600" /></a>
</p>
</div>

<p>
After:
</p>

<div id="org0fc0d8d" class="figure">
<p><a href="https://remcycles.net/blog/../images/so_after.png" width="600"><img src="https://remcycles.net/blog/../images/so_after.png" alt="so_after.png" width="600" /></a>
</p>
</div>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Sankey Diagram of the Speaker of the House Votes</title>
<link>https://remcycles.net/blog/speaker_votes.html</link>
<pubDate>Fri, 06 Jan 2023 00:00:00 -0800</pubDate>
<guid>https://remcycles.net/blog/speaker_votes.html</guid>
<description>
<![CDATA[<p>
This week the House was struggling to elect a Speaker.  I wanted to
see how the votes changed between rounds, so I made this Sankey
diagram to visualize the process.
</p>


<div id="org94ca509" class="figure">
<p><a href="https://remcycles.net/blog/../images/speaker_sankey.svg" alt="Speaker of the House Votes" width="100%"><img src="https://remcycles.net/blog/../images/speaker_sankey.svg" alt="Speaker of the House Votes" class="org-svg" width="100%" /></a>
</p>
<p><span class="figure-number">Figure 1: </span>Speaker of the House votes by round</p>
</div>

<p>
Here's the source code (written in AWK) to process the Clerk's data
and output as Sankeymatic.com input.
</p>

<p>
<a href="https://remcycles.net/blog/../files/speaker_sankey.awk">speaker<sub>sankey.awk</sub></a>:
</p>
<div class="org-src-container">
<pre class="src src-awk"><span style="color: #add8e6;">#</span><span style="color: #add8e6;">!/usr/bin/awk -f</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Copyright Remington Furman, January 2023.</span>

<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Generate a Sankey diagram to track the Speaker of the House votes</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">from House Clerk XML data.</span>
<span style="color: #add8e6;">#</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Generate diagram here:</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">https://sankeymatic.com/build/?layout_style=auto&amp;default_node_colorset=a&amp;default_flow_inherit=outside_in&amp;label_first_pos=before&amp;font_face=sans-serif</span>

<span style="color: #fa8072;">BEGIN</span> {
    r_color  = <span style="color: #ffa07a;">"#900"</span>
    d_color  = <span style="color: #ffa07a;">"#009"</span>
    p_color  = <span style="color: #ffa07a;">"#909"</span>
    nv_color = <span style="color: #ffa07a;">"#999"</span>

    candidate_colors[<span style="color: #ffa07a;">"Jeffries_"</span>]       = d_color
    candidate_colors[<span style="color: #ffa07a;">"McCarthy_"</span>]       = r_color
    candidate_colors[<span style="color: #ffa07a;">"Banks_"</span>]          = r_color
    candidate_colors[<span style="color: #ffa07a;">"Biggs_"</span>]          = r_color
    candidate_colors[<span style="color: #ffa07a;">"Donalds_"</span>]        = r_color
    candidate_colors[<span style="color: #ffa07a;">"Jordan_"</span>]         = r_color
    candidate_colors[<span style="color: #ffa07a;">"Zeldin_"</span>]         = r_color
    candidate_colors[<span style="color: #ffa07a;">"Hern_"</span>]           = r_color
    candidate_colors[<span style="color: #ffa07a;">"Donald_J_Trump_"</span>] = r_color
    candidate_colors[<span style="color: #ffa07a;">"Present_"</span>]        = p_color
    candidate_colors[<span style="color: #ffa07a;">"Not_Voting_"</span>]     = nv_color
}

<span style="color: #7fffd4; font-weight: bold;">FNR</span>==1 {
  FNUM++
}

<span style="color: #ffa07a;">/&lt;recorded-vote&gt;/</span> {
    <span style="color: #fa8072;">match</span>($0,<span style="color: #ffa07a;">/&gt;([^&lt;]+)&lt;\/legislator&gt;.*&gt;([^&lt;]+)&lt;\/vote&gt;/</span>,m)
    voter = m[1]
    candidate = m[2]<span style="color: #ffa07a;">"_"</span>
    <span style="color: #fa8072;">gsub</span>(<span style="color: #ffa07a;">/ /</span>, <span style="color: #ffa07a;">"_"</span>, voter) <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Replace spaces.</span>
    <span style="color: #fa8072;">gsub</span>(<span style="color: #ffa07a;">/ /</span>, <span style="color: #ffa07a;">"_"</span>, candidate)
    <span style="color: #fa8072;">gsub</span>(<span style="color: #ffa07a;">/[\(\)\.,]/</span>, <span style="color: #ffa07a;">""</span>, voter) <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Remove punctuation.</span>
    <span style="color: #fa8072;">gsub</span>(<span style="color: #ffa07a;">/[\(\)\.,]/</span>, <span style="color: #ffa07a;">""</span>, candidate)

    votes[FNUM][voter]=candidate
    candidate_totals[FNUM][candidate]++
}

<span style="color: #fa8072;">END</span> {
    <span style="color: #fa8072;">for</span> (round <span style="color: #fa8072;">in</span> votes) {
        <span style="color: #fa8072;">split</span>(<span style="color: #ffa07a;">""</span>, defections) <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Clear array.</span>
        <span style="color: #7fffd4; font-weight: bold;">PROCINFO</span>[<span style="color: #ffa07a;">"sorted_in"</span>] = <span style="color: #ffa07a;">"@val_str_asc"</span>
        <span style="color: #fa8072;">for</span> (voter <span style="color: #fa8072;">in</span> votes[round]) {
            candidate = votes[round][voter]
            node_colors[candidate round]=candidate_colors[candidate]
            <span style="color: #fa8072;">if</span> (round == 1) {
                <span style="color: #fa8072;">printf</span>(<span style="color: #ffa07a;">"%s%d [1] %s%d\n"</span>,
                       voter, round,
                       candidate, round)
            }
            <span style="color: #fa8072;">else</span> {
                previous_candidate = votes[round-1][voter]
                <span style="color: #fa8072;">if</span> (candidate != previous_candidate) {
                    defections[candidate]++
                    <span style="color: #fa8072;">printf</span>(<span style="color: #ffa07a;">"%s%d [1] %s%d\n"</span>,
                           previous_candidate, round-1,
                           voter, round)
                    <span style="color: #fa8072;">printf</span>(<span style="color: #ffa07a;">"%s%d [1] %s%d\n"</span>,
                           voter, round,
                           candidate, round)
                }
            }
        }
        <span style="color: #fa8072;">if</span> (round != 1) {
            <span style="color: #fa8072;">for</span>(candidate <span style="color: #fa8072;">in</span> candidate_totals[round]) {
                same_votes = candidate_totals[round][candidate] - defections[candidate]
                <span style="color: #fa8072;">if</span> (same_votes != 0) {
                    node_colors[candidate <span style="color: #ffa07a;">"voters"</span> round]=candidate_colors[candidate]
                    <span style="color: #fa8072;">printf</span>(<span style="color: #ffa07a;">"%s%d [%d] %svoters%d\n"</span>,
                           candidate, round-1,
                           same_votes,
                           candidate, round)
                    <span style="color: #fa8072;">printf</span>(<span style="color: #ffa07a;">"%svoters%d [%d] %s%d\n"</span>,
                           candidate, round,
                           same_votes,
                           candidate, round)
                }
            }
        }
    }
    <span style="color: #fa8072;">for</span> (node <span style="color: #fa8072;">in</span> node_colors) {
        <span style="color: #fa8072;">printf</span>(<span style="color: #ffa07a;">":%s %s\n"</span>, node, node_colors[node])
        <span style="color: #fa8072;">printf</span>(<span style="color: #ffa07a;">":%s %s &lt;&lt; &gt;&gt;\n"</span>, node, node_colors[node])
    }
}
</pre>
</div>

<p>
The XML data can be downloaded from the House Clerk's website:
</p>

<p>
<a href="https://clerk.house.gov/Votes?Question=Election%20of%20the%20Speaker">https://clerk.house.gov/Votes?Question=Election%20of%20the%20Speaker</a>
</p>

<p>
For example:
</p>

<p>
<a href="http://clerk.house.gov/evs/2023/roll016.xml">http://clerk.house.gov/evs/2023/roll016.xml</a>
</p>

<p>
Once all the data is downloaded it can be processed like so:
</p>
<div class="org-src-container">
<pre class="src src-bash"><span style="color: #add8e6;">#</span><span style="color: #add8e6;">!/bin/</span><span style="color: #fa8072;">bash</span>

<span style="color: #7fffd4; font-weight: bold;">FILES</span>=$(<span style="color: #fa8072;">ls roll*.xml | sort -n</span>)

./speaker_sankey.awk $<span style="color: #7fffd4; font-weight: bold;">FILES</span> &gt; speaker.sankey
</pre>
</div>

<p>
The output (<a href="https://remcycles.net/blog/../files/speaker.sankey">speaker.sankey</a>) can be fed to <a href="https://sankeymatic.com">https://sankeymatic.com</a>.
</p>

<p>
All the files (including data) can be downloaded here:
</p>

<p>
<a href="https://remcycles.net/blog/../files/speaker_votes.tar.gz">speaker<sub>votes.tar.gz</sub></a>
</p>


<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>The Geometry of the Smith Chart</title>
<link>https://remcycles.net/blog/smith_chart_geometry.html</link>
<pubDate>Thu, 05 Dec 2019 00:00:00 -0800</pubDate>
<guid>https://remcycles.net/blog/smith_chart_geometry.html</guid>
<description>
<![CDATA[<p>
I'm an embedded systems engineer and amateur radio operator and when
I'm lucky I get paid to do electrical engineering work.  One of the
most interesting graph formats I've used is the Smith Chart.  It has
many uses for electrical engineering, including understanding antenna
impedance measurements from a Vector Network Analyzer (VNA) and
designing matching networks for mismatched antennas.
</p>


<div id="org17b1399" class="figure">
<p><img src="https://remcycles.net/blog/../images/smith_circle_50.png" alt="smith_circle_50.png" />
</p>
</div>

<p>
There are many resources on learning how to apply a Smith chart to RF
engineering, and I won't attempt to write my own here.  However, I
found that most resources don't do a great job of explaining why the
Smith chart is circular.
</p>

<p>
Most sources cite the familiar equation that relates the reflection
coefficient \(\Gamma\) to a complex impedance \(z\):
</p>

<p>
\[\Gamma = \frac{z-1}{z+1}\]
</p>

<p>
But looking at that equation on it's own doesn't impart much intuition
for why that leads to a circular chart.
</p>

<p>
Breaking the equation down, \(z-1\) shifts a complex point one unit to
the left, and \(z+1\) shifts that point one unit to the right.  Division
of complex numbers is best done in polar coordinates, dividing the
magnitudes and subtracting the phase angles (\(\frac{z_1}{z_2} =
\frac{abs(z_1)}{abs(z_2)}e^{i(arg(z_1)-arg(z_2))}\)).  But this still
doesn't give much intuition as to what would happen to an entire
half-plane of points when mapped with this equation.
</p>

<p>
The first document I found that make this click for me was this slide
deck by Stephen D. Stearns, K6OIK:
</p>

<p>
<a href="https://www.fars.k6ya.org/docs/smith_chart.pdf">Mysteries of the Smith Chart: Transmission Lines, Impedance Matching,
and Little Known Facts</a>
</p>

<p>
In particular, slides 29 and 30 make it graphically clear that the
equation for \(\Gamma\) (and therefore, the Smith chart) maps the right
hand side of the complex plane (that is, all points with non-negative
real parts) to a unit circle.  As it does this, it also shifts the
point at (0,0) to (-1,0), so that the center of the circle is at
(0,0).  Points outside of this circle correspond to the left half of
the complex plane, which aren't of interest for passive RF circuits,
so they aren't shown on a Smith chart.
</p>

<p>
But the neat thing that really clicked for me was understanding that
the vertical imaginary axis of the complex plane gets wrapped around
the circumference of the Smith chart circle, with (0,0) moving the
left hand side, (0,1) moving to the top of the circle, (0,-1) to the
bottom, and the two points at infinity on the ends of the imaginary
axis meeting at the right side of the circle.
</p>

<p>
From that epiphany, what I wanted to see next was an animation of this
mapping taking place.  I couldn't find one online, and I set that
particular problem aside for a while.  But recently I figured out a
way to slowly apply the mapping so that I can watch the transformation
take place and I wrote the code to do so.
</p>

<p>
This is the result:
</p>


<div id="orgb35ad66" class="figure">
<p><img src="https://remcycles.net/blog/../images/smith_circle_50.gif" alt="smith_circle_50.gif" />
</p>
</div>

<p>
The mapping is known as a Mobius transformation, and the general case
of a Mobius transformation is:
</p>

<p>
\[\frac{a z + b}{c z + d}\]
</p>

<p>
And the general case of the Smith chart the equation is:
</p>

<p>
\[\Gamma = \frac{z-Z_0}{z+Z_0}\]
</p>

<p>
Thus, we have a Mobius transformation with \(a=c=1\) and \(d=-b=Z_0\).
</p>

<p>
Usually, \(z\) is normalized by dividing by the characteristic impedance
of a transmission line (\(Z_0\)) before applying the transformation, and
so the equation from the beginning of the article is the most
frequently published.
</p>

<p>
But I noticed that if \(Z_0\) is very large, then for smaller values of
\(z\) the transformation does not move the point very much (except for
the leftward shift by 1).  Drawing a connected Cartesian grid and
mapping the grid points with smaller and smaller values of \(Z_0\)
results in an animation like this:
</p>


<div id="org2d02a04" class="figure">
<p><img src="https://remcycles.net/blog/../images/smith_grid_10.gif" alt="smith_grid_10.gif" />
</p>
</div>

<p>
Here, the grid is drawn with a line every ten units from \(0 \leqslant
x \leqslant 1000\) and \(-1000 \leqslant y \leqslant 1000\), and the
resulting circle is always scaled to fit in the frame of image.
Because of the scaling, the grid appears to change size which is
unfortunate, but it clearly shows how the points along the vertical
imaginary axis begin to envelop the circle as the transform gets
closer and closer to the target \(Z_0\).  With large values of \(Z_0\),
the grid is more or less rectangular (occupying only a small arc of
the circle).
</p>

<p>
This grid chart is a little unsatisfying, since the grid points start
to look angular as they get more separated.  Plus, the constant
diameter of the plot hides the fact that the points at infinity come
closer and closer to the mapped (0,0) origin of the plot.
</p>

<p>
In order to keep the circular nature of the mapped grid lines I needed
to work out the geometry (centers, radii, and angles) of the arcs
after the mapping.  This was a fun math problem, especially the arc
lengths for proper clipping.
</p>

<p>
The vertical lines of the Cartesian grid map to circles with centers on
the real axis to the right of (0,0), and they all pass through (1,0).
The left most point of the circle passes through \(\Gamma =
\frac{(x+0i)-1}{(x+0i)+1}\).  From there, it's easy to calculate the radius
and center of the circle.
</p>

<p>
The horizontal lines are a bit more complicated.  The centers are all
above (1,0), and they all pass through (1,0) as well.  The other point
they pass through is \(\Gamma = \frac{(0+y i)-1}{(0+y i)+1}\).  A little
of bit of algebra (Pythagorean Theorem) shows that the radius of the
circle is \(r = \frac{(\Re(\Gamma)-1)^2 + \Im(\Gamma)^2}{2
\Im(\Gamma)}\).  Finding the arc angle for clipping just involves the
arctangent, since we know the two points that the arc must connect.
</p>


<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Sonifying the Tides</title>
<link>https://remcycles.net/blog/sonifying_the_tides.html</link>
<pubDate>Thu, 26 Apr 2018 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/sonifying_the_tides.html</guid>
<description>
<![CDATA[<p>
<a href="https://remcycles.net/blog/../files/tides_presentation.pdf">The Puget Sound, As Sound: Sonifying the tides with the Teensy Audio Adapter</a>
</p>

<p>
I gave this presentation at a <a href="https://bellingham.code">Bellingham.Codes</a> meeting on April 26th,
2018, and again at the Bellingham Space Meetup on May 30th, 2018.
</p>

<p>
<a href="https://remcycles.net/blog/../files/tides.wav">Click here</a> for a sound sample of the tides sped up to audio frequencies.
</p>

<p>
This image shows the simulated tides which are interpreted as an audio
waveform in the above audio clip.
</p>

<div id="orgf3d731d" class="figure">
<p><img src="https://remcycles.net/blog/../images/oscillograph.png" alt="oscillograph.png" width="500px" />
</p>
</div>

<p>
Thanks to windytan for the great waveform visualization code!
<a href="https://www.windytan.com/2013/03/rendering-pcm-with-simulated-phosphor.html">https://www.windytan.com/2013/03/rendering-pcm-with-simulated-phosphor.html</a>
</p>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Seldom Seen Smith's Nightmare: $e^x$</title>
<link>https://remcycles.net/blog/seldom_seens_nightmare.html</link>
<pubDate>Sun, 02 Jan 2022 00:00:00 -0800</pubDate>
<guid>https://remcycles.net/blog/seldom_seens_nightmare.html</guid>
<description>
<![CDATA[<p>
I recently read "The Monkey Wrench Gang" by Edward Abbey (a 1975 novel
about environmental activism and industrial sabotage), and there's a
scene where a character known as Seldom Seen Smith has a nightmare.
While trying to break into a dam's control room a robot captures him,
describes the assembly programming interface for a simple computer,
and threatens to electrocute him unless he can implement \(e^x\) as an
infinite series within 0.000015ms.
</p>

<p>
It took me more than 0.000015ms to simulate that machine in Python and
write the program, but it was a fun diversion.
</p>

<p>
<a href="https://remcycles.net/blog/../files/mwg-exp.py">mwg-exp.py</a>:
</p>
<div class="org-src-container">
<pre class="src src-python"><span style="color: #add8e6;">#</span><span style="color: #add8e6;">!/bin/env python3</span>

<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Evaluate exp(x) with an infinite series, as requested by the</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Operator in Seldom Seen Smith's nightmare in The Monkey Wrench Gang</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">by Edward Abbey.  The Operator describes the assembly language for a</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">simple computer which is simulated here.  It took me more than</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">0.000015 milliseconds to write this.</span>

<span style="color: #fa8072;">import</span> math

<span style="color: #7fffd4; font-weight: bold;">x</span> = 1.0                         <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Input argument</span>
<span style="color: #7fffd4; font-weight: bold;">expected_result</span> = math.exp(x)

<span style="color: #98fb98; font-weight: bold;">print</span>(f<span style="color: #ffa07a;">"Input: </span>{x}<span style="color: #ffa07a;">"</span>)
<span style="color: #98fb98; font-weight: bold;">print</span>(f<span style="color: #ffa07a;">"Expecting: </span>{expected_result}<span style="color: #ffa07a;">"</span>)

<span style="color: #7fffd4; font-weight: bold;">w</span> = x                           <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Working register</span>
<span style="color: #7fffd4; font-weight: bold;">s</span> = [0.0] * 6                   <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Storage locations</span>

<span style="color: #7fffd4; font-weight: bold;">s</span>[0] = 2.0                      <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Iteration counter</span>
<span style="color: #7fffd4; font-weight: bold;">s</span>[1] = 1.0                      <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Factorial</span>
<span style="color: #7fffd4; font-weight: bold;">s</span>[2] = 1.0                      <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Partial sum</span>
<span style="color: #7fffd4; font-weight: bold;">s</span>[3] = x                        <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Powers of x</span>
<span style="color: #7fffd4; font-weight: bold;">s</span>[4] = 1.0                      <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Unity (constant)</span>
<span style="color: #7fffd4; font-weight: bold;">s</span>[5] = x                        <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Input argument (constant)</span>

<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Functions to simulate the machine's op-codes.</span>
<span style="color: #fa8072;">def</span> <span style="color: #7fffd4; font-weight: bold;">T</span>(n):                       <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Store working register.</span>
    <span style="color: #fa8072;">global</span> w, s
    <span style="color: #7fffd4; font-weight: bold;">s</span>[n] = w

<span style="color: #fa8072;">def</span> <span style="color: #7fffd4; font-weight: bold;">B</span>(n):                       <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Load working register.</span>
    <span style="color: #fa8072;">global</span> w, s
    <span style="color: #7fffd4; font-weight: bold;">w</span> = s[n]

<span style="color: #fa8072;">def</span> <span style="color: #7fffd4; font-weight: bold;">add</span>(n):
    <span style="color: #fa8072;">global</span> w, s
    <span style="color: #7fffd4; font-weight: bold;">w</span> = w + s[n]

<span style="color: #fa8072;">def</span> <span style="color: #7fffd4; font-weight: bold;">sub</span>(n):
    <span style="color: #fa8072;">global</span> w, s
    <span style="color: #7fffd4; font-weight: bold;">w</span> = w - s[n]

<span style="color: #fa8072;">def</span> <span style="color: #7fffd4; font-weight: bold;">mul</span>(n):
    <span style="color: #fa8072;">global</span> w, s
    <span style="color: #7fffd4; font-weight: bold;">w</span> = w * s[n]

<span style="color: #fa8072;">def</span> <span style="color: #7fffd4; font-weight: bold;">div</span>(n):
    <span style="color: #fa8072;">global</span> w, s
    <span style="color: #7fffd4; font-weight: bold;">w</span> = w / s[n]

<span style="color: #fa8072;">def</span> <span style="color: #7fffd4; font-weight: bold;">Z</span>():
    <span style="color: #7fffd4;">exit</span>(0)                     <span style="color: #add8e6;"># </span><span style="color: #add8e6;">End program.</span>

<span style="color: #98fb98; font-weight: bold;">print</span>(w, s)

add(4)                          <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Add 1 to x.</span>
T(2)                            <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Save the result.</span>
B(1)                            <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Load factorial.</span>
mul(0)                          <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Multiply by iteration count.</span>
T(1)                            <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Save result.</span>
B(3)                            <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Load power of x.</span>
mul(5)                          <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Multiply by x.</span>
T(3)                            <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Save result.</span>
div(1)                          <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Divide by factorial.</span>
add(2)                          <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Add to partial sum.</span>
T(2)                            <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Save result.</span>

<span style="color: #98fb98; font-weight: bold;">print</span>(w, s)

<span style="color: #fa8072;">for</span> i <span style="color: #fa8072;">in</span> <span style="color: #98fb98; font-weight: bold;">range</span>(0,15):
    B(0)                        <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Increment iteration counter.</span>
    add(4)
    T(0)
    B(1)                        <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Update factorial.</span>
    mul(0)
    T(1)
    B(3)                        <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Update power of x (x^n).</span>
    mul(5)
    T(3)
    div(1)                      <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Divide by factorial.</span>
    add(2)                      <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Add to partial sum.</span>
    T(2)                        <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Save result.</span>

    <span style="color: #98fb98; font-weight: bold;">print</span>(w, expected_result, w - expected_result, s)

Z()
</pre>
</div>

<p>
This is a pretty straightforward implementation of this expression for
\(e^x\) (<a href="https://en.wikipedia.org/wiki/Characterizations_of_the_exponential_function#Characterizations">copied from Wikipedia</a>):
</p>

<p>
\[e^x = \sum_{n=0}^\infty {x^n \over n!} = 1 + x + \frac{x^2}{2!} +
\frac{x^3}{3!} + \frac{x^4}{4!} + \cdots\]
</p>

<p>
Jack Crenshaw's book <a href="https://www.routledge.com/Math-Toolkit-for-Real-Time-Programming/Crenshaw/p/book/9781929629091">Math Toolkit for Real-Time Programming</a> has a lot
to say about improved methods for calculating exponents and other
functions.  I recommend it.
</p>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>static const float complex</title>
<link>https://remcycles.net/blog/scfc.html</link>
<pubDate>Wed, 31 Jan 2024 00:00:00 -0800</pubDate>
<guid>https://remcycles.net/blog/scfc.html</guid>
<description>
<![CDATA[<p>
One of the following permutations of <code>static const float complex</code>
showed up in a code review at work today.  It made me wonder which
permutations would compile.  The answer: they all do.  Have fun.
</p>
<div class="org-src-container">
<pre class="src src-c"><span style="color: #fa8072;">#include</span> <span style="color: #ffa07a;">&lt;stdio.h&gt;</span>
<span style="color: #fa8072;">#include</span> <span style="color: #ffa07a;">&lt;complex.h&gt;</span>

<span style="color: #add8e6;">/*</span>
<span style="color: #add8e6;">#!/bin/usr/env python3</span>
<span style="color: #add8e6;">import itertools</span>
<span style="color: #add8e6;">for perm in itertools.permutations(["static", "const", "float", "complex"]):</span>
<span style="color: #add8e6;">    print(" ".join(perm))</span>
<span style="color: #add8e6;">*/</span>

<span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">main</span> (<span style="color: #9acd32; font-weight: bold;">void</span>) {
    <span style="color: #fa8072;">static</span> <span style="color: #fa8072;">const</span> <span style="color: #9acd32; font-weight: bold;">float</span> <span style="color: #7fffd4; font-weight: bold;">complex</span> static_const_float_complex = 0 + 1 * I;
    <span style="color: #fa8072;">static</span> <span style="color: #fa8072;">const</span> complex <span style="color: #9acd32; font-weight: bold;">float</span> static_const_complex_float = 0 + 1 * I;
    <span style="color: #fa8072;">static</span> <span style="color: #9acd32; font-weight: bold;">float</span> <span style="color: #fa8072;">const</span> <span style="color: #7fffd4; font-weight: bold;">complex</span> static_float_const_complex = 0 + 1 * I;
    <span style="color: #fa8072;">static</span> <span style="color: #9acd32; font-weight: bold;">float</span> <span style="color: #7fffd4; font-weight: bold;">complex</span> <span style="color: #fa8072;">const</span> static_float_complex_const = 0 + 1 * I;
    <span style="color: #fa8072;">static</span> <span style="color: #9acd32; font-weight: bold;">complex</span> <span style="color: #fa8072;">const</span> <span style="color: #9acd32; font-weight: bold;">float</span> static_complex_const_float = 0 + 1 * I;
    <span style="color: #fa8072;">static</span> complex <span style="color: #9acd32; font-weight: bold;">float</span> <span style="color: #fa8072;">const</span> static_complex_float_const = 0 + 1 * I;
    <span style="color: #fa8072;">const</span> <span style="color: #fa8072;">static</span> <span style="color: #9acd32; font-weight: bold;">float</span> <span style="color: #7fffd4; font-weight: bold;">complex</span> const_static_float_complex = 0 + 1 * I;
    <span style="color: #fa8072;">const</span> <span style="color: #fa8072;">static</span> complex <span style="color: #9acd32; font-weight: bold;">float</span> <span style="color: #7fffd4; font-weight: bold;">const_static_complex_float</span> = 0 + 1 * I;
    <span style="color: #fa8072;">const</span> <span style="color: #9acd32; font-weight: bold;">float</span> <span style="color: #fa8072;">static</span> <span style="color: #7fffd4; font-weight: bold;">complex</span> const_float_static_complex = 0 + 1 * I;
    <span style="color: #fa8072;">const</span> <span style="color: #9acd32; font-weight: bold;">float</span> <span style="color: #7fffd4; font-weight: bold;">complex</span> <span style="color: #fa8072;">static</span> const_float_complex_static = 0 + 1 * I;
    <span style="color: #fa8072;">const</span> complex <span style="color: #fa8072;">static</span> <span style="color: #9acd32; font-weight: bold;">float</span> <span style="color: #7fffd4; font-weight: bold;">const_complex_static_float</span> = 0 + 1 * I;
    <span style="color: #fa8072;">const</span> complex <span style="color: #9acd32; font-weight: bold;">float</span> <span style="color: #fa8072;">static</span> <span style="color: #7fffd4; font-weight: bold;">const_complex_float_static</span> = 0 + 1 * I;
    <span style="color: #9acd32; font-weight: bold;">float</span> <span style="color: #fa8072;">static</span> <span style="color: #fa8072;">const</span> <span style="color: #7fffd4; font-weight: bold;">complex</span> float_static_const_complex = 0 + 1 * I;
    <span style="color: #9acd32; font-weight: bold;">float</span> <span style="color: #fa8072;">static</span> <span style="color: #7fffd4; font-weight: bold;">complex</span> <span style="color: #fa8072;">const</span> float_static_complex_const = 0 + 1 * I;
    <span style="color: #9acd32; font-weight: bold;">float</span> <span style="color: #fa8072;">const</span> <span style="color: #fa8072;">static</span> <span style="color: #7fffd4; font-weight: bold;">complex</span> float_const_static_complex = 0 + 1 * I;
    <span style="color: #9acd32; font-weight: bold;">float</span> <span style="color: #fa8072;">const</span> <span style="color: #7fffd4; font-weight: bold;">complex</span> <span style="color: #fa8072;">static</span> float_const_complex_static = 0 + 1 * I;
    <span style="color: #9acd32; font-weight: bold;">float</span> <span style="color: #7fffd4; font-weight: bold;">complex</span> <span style="color: #fa8072;">static</span> <span style="color: #fa8072;">const</span> float_complex_static_const = 0 + 1 * I;
    <span style="color: #9acd32; font-weight: bold;">float</span> <span style="color: #7fffd4; font-weight: bold;">complex</span> <span style="color: #fa8072;">const</span> <span style="color: #fa8072;">static</span> float_complex_const_static = 0 + 1 * I;
    complex <span style="color: #fa8072;">static</span> <span style="color: #fa8072;">const</span> <span style="color: #9acd32; font-weight: bold;">float</span> <span style="color: #7fffd4; font-weight: bold;">complex_static_const_float</span> = 0 + 1 * I;
    complex <span style="color: #fa8072;">static</span> <span style="color: #9acd32; font-weight: bold;">float</span> <span style="color: #fa8072;">const</span> <span style="color: #7fffd4; font-weight: bold;">complex_static_float_const</span> = 0 + 1 * I;
    <span style="color: #9acd32; font-weight: bold;">complex</span> <span style="color: #fa8072;">const</span> <span style="color: #fa8072;">static</span> <span style="color: #9acd32; font-weight: bold;">float</span> complex_const_static_float = 0 + 1 * I;
    <span style="color: #9acd32; font-weight: bold;">complex</span> <span style="color: #fa8072;">const</span> <span style="color: #9acd32; font-weight: bold;">float</span> <span style="color: #fa8072;">static</span> complex_const_float_static = 0 + 1 * I;
    complex <span style="color: #9acd32; font-weight: bold;">float</span> <span style="color: #fa8072;">static</span> <span style="color: #fa8072;">const</span> <span style="color: #7fffd4; font-weight: bold;">complex_float_static_const</span> = 0 + 1 * I;
    complex <span style="color: #9acd32; font-weight: bold;">float</span> <span style="color: #fa8072;">const</span> <span style="color: #fa8072;">static</span> <span style="color: #7fffd4; font-weight: bold;">complex_float_const_static</span> = 0 + 1 * I;

    printf(<span style="color: #ffa07a;">"static_const_float_complex: (%f,%f)\n"</span>, crealf(static_const_float_complex), cimagf(static_const_float_complex));
    printf(<span style="color: #ffa07a;">"static_const_complex_float: (%f,%f)\n"</span>, crealf(static_const_complex_float), cimagf(static_const_complex_float));
    printf(<span style="color: #ffa07a;">"static_float_const_complex: (%f,%f)\n"</span>, crealf(static_float_const_complex), cimagf(static_float_const_complex));
    printf(<span style="color: #ffa07a;">"static_float_complex_const: (%f,%f)\n"</span>, crealf(static_float_complex_const), cimagf(static_float_complex_const));
    printf(<span style="color: #ffa07a;">"static_complex_const_float: (%f,%f)\n"</span>, crealf(static_complex_const_float), cimagf(static_complex_const_float));
    printf(<span style="color: #ffa07a;">"static_complex_float_const: (%f,%f)\n"</span>, crealf(static_complex_float_const), cimagf(static_complex_float_const));
    printf(<span style="color: #ffa07a;">"const_static_float_complex: (%f,%f)\n"</span>, crealf(const_static_float_complex), cimagf(const_static_float_complex));
    printf(<span style="color: #ffa07a;">"const_static_complex_float: (%f,%f)\n"</span>, crealf(const_static_complex_float), cimagf(const_static_complex_float));
    printf(<span style="color: #ffa07a;">"const_float_static_complex: (%f,%f)\n"</span>, crealf(const_float_static_complex), cimagf(const_float_static_complex));
    printf(<span style="color: #ffa07a;">"const_float_complex_static: (%f,%f)\n"</span>, crealf(const_float_complex_static), cimagf(const_float_complex_static));
    printf(<span style="color: #ffa07a;">"const_complex_static_float: (%f,%f)\n"</span>, crealf(const_complex_static_float), cimagf(const_complex_static_float));
    printf(<span style="color: #ffa07a;">"const_complex_float_static: (%f,%f)\n"</span>, crealf(const_complex_float_static), cimagf(const_complex_float_static));
    printf(<span style="color: #ffa07a;">"float_static_const_complex: (%f,%f)\n"</span>, crealf(float_static_const_complex), cimagf(float_static_const_complex));
    printf(<span style="color: #ffa07a;">"float_static_complex_const: (%f,%f)\n"</span>, crealf(float_static_complex_const), cimagf(float_static_complex_const));
    printf(<span style="color: #ffa07a;">"float_const_static_complex: (%f,%f)\n"</span>, crealf(float_const_static_complex), cimagf(float_const_static_complex));
    printf(<span style="color: #ffa07a;">"float_const_complex_static: (%f,%f)\n"</span>, crealf(float_const_complex_static), cimagf(float_const_complex_static));
    printf(<span style="color: #ffa07a;">"float_complex_static_const: (%f,%f)\n"</span>, crealf(float_complex_static_const), cimagf(float_complex_static_const));
    printf(<span style="color: #ffa07a;">"float_complex_const_static: (%f,%f)\n"</span>, crealf(float_complex_const_static), cimagf(float_complex_const_static));
    printf(<span style="color: #ffa07a;">"complex_static_const_float: (%f,%f)\n"</span>, crealf(complex_static_const_float), cimagf(complex_static_const_float));
    printf(<span style="color: #ffa07a;">"complex_static_float_const: (%f,%f)\n"</span>, crealf(complex_static_float_const), cimagf(complex_static_float_const));
    printf(<span style="color: #ffa07a;">"complex_const_static_float: (%f,%f)\n"</span>, crealf(complex_const_static_float), cimagf(complex_const_static_float));
    printf(<span style="color: #ffa07a;">"complex_const_float_static: (%f,%f)\n"</span>, crealf(complex_const_float_static), cimagf(complex_const_float_static));
    printf(<span style="color: #ffa07a;">"complex_float_static_const: (%f,%f)\n"</span>, crealf(complex_float_static_const), cimagf(complex_float_static_const));
    printf(<span style="color: #ffa07a;">"complex_float_const_static: (%f,%f)\n"</span>, crealf(complex_float_const_static), cimagf(complex_float_const_static));
}
</pre>
</div>

<pre class="example" id="org61a970d">
$ make
gcc -Wall -Wpedantic -o scfc scfc.c  -lm
$ ./scfc
static_const_float_complex: (0.000000,1.000000)
static_const_complex_float: (0.000000,1.000000)
static_float_const_complex: (0.000000,1.000000)
static_float_complex_const: (0.000000,1.000000)
static_complex_const_float: (0.000000,1.000000)
static_complex_float_const: (0.000000,1.000000)
const_static_float_complex: (0.000000,1.000000)
const_static_complex_float: (0.000000,1.000000)
const_float_static_complex: (0.000000,1.000000)
const_float_complex_static: (0.000000,1.000000)
const_complex_static_float: (0.000000,1.000000)
const_complex_float_static: (0.000000,1.000000)
float_static_const_complex: (0.000000,1.000000)
float_static_complex_const: (0.000000,1.000000)
float_const_static_complex: (0.000000,1.000000)
float_const_complex_static: (0.000000,1.000000)
float_complex_static_const: (0.000000,1.000000)
float_complex_const_static: (0.000000,1.000000)
complex_static_const_float: (0.000000,1.000000)
complex_static_float_const: (0.000000,1.000000)
complex_const_static_float: (0.000000,1.000000)
complex_const_float_static: (0.000000,1.000000)
complex_float_static_const: (0.000000,1.000000)
complex_float_const_static: (0.000000,1.000000)
</pre>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Schematic Shoes</title>
<link>https://remcycles.net/blog/schematic_shoes.html</link>
<pubDate>Sun, 26 Apr 2020 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/schematic_shoes.html</guid>
<description>
<![CDATA[
<div id="orgdb2a3af" class="figure">
<p><a href="https://remcycles.net/blog/../images/schematic_shoes.jpg" width="500px"><img src="https://remcycles.net/blog/../images/schematic_shoes.jpg" alt="schematic_shoes.jpg" width="500px" /></a>
</p>
</div>

<p>
Here's a pair of shoes I embroidered with some schematics.
</p>

<p>
On the left shoe, two digital circuits: an SR latch (which can be
combined to form my favorite digital circuit, the D flip-flop) and a
CMOS inverter.
</p>

<p>
And on the right shoe, two analog circuits: a differential pair, and a
precision rectifier.
</p>

<p>
The schematics were drawn in the quirky <a href="http://opencircuitdesign.com/xcircuit/">XCircuit</a> program, because it
generates nice Postscript output, and then they were traced onto the
shoes with a pencil.
</p>

<p>
The lines and circles are all done in a simple backstitch, the one
diode is filled with a satin stitch, and there are tiny Chinese knots
at the connecting dots.
</p>

<p>
I recently learned that Converse high tops have the star logos on the
</p>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>LibreOffice Calc Tricks</title>
<link>https://remcycles.net/blog/libreoffice_calc.html</link>
<pubDate>Sat, 29 Mar 2025 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/libreoffice_calc.html</guid>
<description>
<![CDATA[<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Resistor Color Code Bookmarks</title>
<link>https://remcycles.net/blog/resistor_code_bookmark.html</link>
<pubDate>Sat, 11 Apr 2020 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/resistor_code_bookmark.html</guid>
<description>
<![CDATA[
<div id="org3e305ed" class="figure">
<p><img src="https://remcycles.net/blog/../images/resistor_code_bookmark.jpg" alt="resistor_code_bookmark.jpg" width="500px" />
</p>
</div>

<p>
One of my favorite books is the "bible" of electrical engineering,
</p>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>A Picocom Wrapper</title>
<link>https://remcycles.net/blog/picocom.html</link>
<pubDate>Tue, 04 Jan 2022 00:00:00 -0800</pubDate>
<guid>https://remcycles.net/blog/picocom.html</guid>
<description>
<![CDATA[<p>
My favorite serial port program is <code>picocom</code> because it's simple and
runs right in my existing terminal emulator (no PuTTY or other GUI
terminal emulator funkiness).
</p>

<p>
When I first started using it a few years ago, I kept forgetting how
to exit it, so I wrote this wrapper to remind myself in the terminal's
title bar.
</p>

<p>
<a href="https://remcycles.net/blog/../files/picocom.sh">picocom.sh</a>:
</p>
<div class="org-src-container">
<pre class="src src-sh"><span style="color: #add8e6;">#</span><span style="color: #add8e6;">!/bin/</span><span style="color: #fa8072;">sh</span>

<span style="color: #add8e6;"># </span><span style="color: #add8e6;">picocom.sh: Start picocom and remind the user how to exit.</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Copyright (C) 2021, Remington Furman</span>

<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Copying and distribution of this file, with or without modification,</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">are permitted in any medium without royalty, provided the copyright</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">notice and this notice are preserved. This file is offered as-is,</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">without any warranty.</span>

<span style="color: #7fffd4; font-weight: bold;">DEVICE</span>=${<span style="color: #7fffd4; font-weight: bold;">1</span>:-/dev/ttyUSB0}
<span style="color: #7fffd4; font-weight: bold;">BAUD</span>=${<span style="color: #7fffd4; font-weight: bold;">2</span>:-115200}

<span style="color: #7fffd4; font-weight: bold;">TITLE</span> ()
{
    <span style="color: #98fb98; font-weight: bold;">echo</span> <span style="color: #ffa07a;">"\033]0;${1}\007"</span>
}

<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Set window title</span>
<span style="color: #98fb98; font-weight: bold;">echo</span> -ne <span style="color: #ffa07a;">"$(</span><span style="color: #fa8072;">TITLE "picocom $DEVICE -- C-a C-x to exit"</span><span style="color: #ffa07a;">)"</span>

/usr/bin/picocom -b <span style="color: #ffa07a;">"$BAUD"</span> <span style="color: #ffa07a;">"$DEVICE"</span>
</pre>
</div>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Line Encoding Bitstreams with Ragel</title>
<link>https://remcycles.net/blog/ragel_line_code.html</link>
<pubDate>Mon, 04 Apr 2022 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/ragel_line_code.html</guid>
<description>
<![CDATA[<p>
<a href="https://www.colm.net/open-source/ragel/">Ragel</a> is a neat code generator for compiling efficient state machine
programs.  A quick way to describe it is "regular expressions on
steroids".  The input is essentially regular expressions interspersed
with C code that will run whenever the corresponding transistions are
taken.
</p>

<p>
I wanted to practice using it and thought that the <a href="https://en.wikipedia.org/wiki/Line_code">line codes</a>
described on Wikipedia would provide very simple state machines to try
out.  The output of this program provides input to <a href="https://wavedrom.com/">WaveDrom</a>, which is
another fun tool for creating timing diagrams from text.  In WaveDrom,
<code>h</code> means "high state", <code>l</code> means "low state", and <code>.</code> means hold the
previous state.
</p>

<p>
Here's the source (<a href="https://remcycles.net/blog/../files/linecode/lc.rl">lc.rl</a>):
</p>
<div class="org-src-container">
<pre class="src src-c"><span style="color: #add8e6;">/* </span><span style="color: #add8e6;">lc -- Line encode a bitstream with output in WaveDrom format.</span>
<span style="color: #add8e6;">   Copyright (C) 2022 Remington Furman</span>
<span style="color: #add8e6;">   This program is free software: you can redistribute it and/or modify</span>
<span style="color: #add8e6;">   it under the terms of the GNU General Public License as published by</span>
<span style="color: #add8e6;">   the Free Software Foundation, either version 3 of the License, or</span>
<span style="color: #add8e6;">   (at your option) any later version.</span>
<span style="color: #add8e6;">   This program is distributed in the hope that it will be useful,</span>
<span style="color: #add8e6;">   but WITHOUT ANY WARRANTY; without even the implied warranty of</span>
<span style="color: #add8e6;">   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span>
<span style="color: #add8e6;">   GNU General Public License for more details.</span>
<span style="color: #add8e6;">   You should have received a copy of the GNU General Public License</span>
<span style="color: #add8e6;">   along with this program.  If not, see <a href="https://www.gnu.org/licenses/&gt;.
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h&gt;
#include &lt;stdlib.h">&lt;https://www.gnu.org/licenses/&gt;.</a></span><a href="https://www.gnu.org/licenses/&gt;.
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h&gt;
#include &lt;stdlib.h">
</a><span style="color: #add8e6;"><a href="https://www.gnu.org/licenses/&gt;.
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h&gt;
#include &lt;stdlib.h"> */</a></span><a href="https://www.gnu.org/licenses/&gt;.
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h&gt;
#include &lt;stdlib.h">

</a><span style="color: #fa8072;"><a href="https://www.gnu.org/licenses/&gt;.
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h&gt;
#include &lt;stdlib.h">#include</a></span><a href="https://www.gnu.org/licenses/&gt;.
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h&gt;
#include &lt;stdlib.h"> </a><span style="color: #ffa07a;"><a href="https://www.gnu.org/licenses/&gt;.
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h&gt;
#include &lt;stdlib.h">&lt;stdio.h&gt;</a></span><a href="https://www.gnu.org/licenses/&gt;.
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h&gt;
#include &lt;stdlib.h">
</a><span style="color: #fa8072;"><a href="https://www.gnu.org/licenses/&gt;.
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h&gt;
#include &lt;stdlib.h">#include</a></span><a href="https://www.gnu.org/licenses/&gt;.
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h&gt;
#include &lt;stdlib.h"> </a><span style="color: #ffa07a;"><a href="https://www.gnu.org/licenses/&gt;.
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h&gt;
#include &lt;stdlib.h">&lt;string.h&gt;</a></span><a href="https://www.gnu.org/licenses/&gt;.
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h&gt;
#include &lt;stdlib.h">
</a><span style="color: #fa8072;"><a href="https://www.gnu.org/licenses/&gt;.
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h&gt;
#include &lt;stdlib.h">#include</a></span><a href="https://www.gnu.org/licenses/&gt;.
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h&gt;
#include &lt;stdlib.h"> </a><span style="color: #ffa07a;"><a href="https://www.gnu.org/licenses/&gt;.
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h&gt;
#include &lt;stdlib.h">&lt;getopt.h&gt;</a></span><a href="https://www.gnu.org/licenses/&gt;.
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h&gt;
#include &lt;stdlib.h">
</a><span style="color: #fa8072;"><a href="https://www.gnu.org/licenses/&gt;.
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h&gt;
#include &lt;stdlib.h">#include</a></span><a href="https://www.gnu.org/licenses/&gt;.
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h&gt;
#include &lt;stdlib.h"> </a><span style="color: #ffa07a;"><a href="https://www.gnu.org/licenses/&gt;.
 */

#include &lt;stdio.h&gt;
#include &lt;string.h&gt;
#include &lt;getopt.h&gt;
#include &lt;stdlib.h">&lt;stdlib.h&gt;</a></span>

<span style="color: #fa8072;">struct</span> <span style="color: #9acd32; font-weight: bold;">line_code</span>
{
    <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">cs</span>;   <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">Current state.</span><span style="color: #add8e6;"> */</span>
    <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">bit</span>;  <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">Current bit value.</span><span style="color: #add8e6;"> */</span>
};

%%{
    <span style="color: #9acd32; font-weight: bold;">machine</span> <span style="color: #7fffd4; font-weight: bold;">line_code</span>;
    access fsm-&gt;;

    <span style="color: #9acd32; font-weight: bold;">action</span> <span style="color: #7fffd4; font-weight: bold;">low</span>     { fsm-&gt;bit  = 0;  putchar(<span style="color: #ffa07a;">'l'</span>); }
    <span style="color: #9acd32; font-weight: bold;">action</span> <span style="color: #7fffd4; font-weight: bold;">high</span>    { fsm-&gt;bit  = 1;  putchar(<span style="color: #ffa07a;">'h'</span>); }
    <span style="color: #9acd32; font-weight: bold;">action</span> <span style="color: #7fffd4; font-weight: bold;">toggle</span>  { fsm-&gt;bit ^= 1;  putchar(fsm-&gt;bit ? <span style="color: #ffa07a;">'h'</span> : <span style="color: #ffa07a;">'l'</span>); }
    <span style="color: #9acd32; font-weight: bold;">action</span> <span style="color: #7fffd4; font-weight: bold;">toggle2</span> { fsm-&gt;bit ^= 1;  putchar(fsm-&gt;bit ? <span style="color: #ffa07a;">'h'</span> : <span style="color: #ffa07a;">'l'</span>);
                     fsm-&gt;bit ^= 1;  putchar(fsm-&gt;bit ? <span style="color: #ffa07a;">'h'</span> : <span style="color: #ffa07a;">'l'</span>); }
    <span style="color: #9acd32; font-weight: bold;">action</span> <span style="color: #7fffd4; font-weight: bold;">hold</span>    {                 putchar(<span style="color: #ffa07a;">'.'</span>); }
    <span style="color: #9acd32; font-weight: bold;">action</span> <span style="color: #7fffd4; font-weight: bold;">nl</span>      {                 putchar(<span style="color: #ffa07a;">'\n'</span>); }

    zero_low_h  = (<span style="color: #ffa07a;">'0'</span> @low  (<span style="color: #ffa07a;">'0'</span> @hold)*); # Emit one  low then hold <span style="color: #fa8072;">for</span> rest
    zero_high_h = (<span style="color: #ffa07a;">'0'</span> @high (<span style="color: #ffa07a;">'0'</span> @hold)*); # Emit one high then hold <span style="color: #fa8072;">for</span> rest
    one_low_h   = (<span style="color: #ffa07a;">'1'</span> @low  (<span style="color: #ffa07a;">'1'</span> @hold)*); # Emit one  low then hold <span style="color: #fa8072;">for</span> rest
    one_high_h  = (<span style="color: #ffa07a;">'1'</span> @high (<span style="color: #ffa07a;">'1'</span> @hold)*); # Emit one high then hold <span style="color: #fa8072;">for</span> rest

<span style="color: #fa8072;">    # Line</span> code machines
    nrz_l := ((zero_low_h  | one_high_h )** 0 @nl)*; # Non-<span style="color: #fa8072;">return</span>-to-zero level
    nrz_i := ((zero_high_h | one_low_h  )** 0 @nl)*; # Non-<span style="color: #fa8072;">return</span>-to-zero invert
    nrz_s := ((<span style="color: #ffa07a;">'0'</span> @toggle | <span style="color: #ffa07a;">'1'</span> @hold  )*  0 @nl)*; # Non-<span style="color: #fa8072;">return</span>-to-zero space
    nrz_m := ((<span style="color: #ffa07a;">'0'</span> @hold   | <span style="color: #ffa07a;">'1'</span> @toggle)*  0 @nl)*; # Non-<span style="color: #fa8072;">return</span>-to-zero mark

    bph_l := ((<span style="color: #ffa07a;">'0'</span> @low @high    | <span style="color: #ffa07a;">'1'</span> @high @low   )* 0 @nl)*; # Bi-phase level
    bph_s := ((<span style="color: #ffa07a;">'0'</span> @toggle2      | <span style="color: #ffa07a;">'1'</span> @toggle @hold)* 0 @nl)*; # Bi-phase space
    bph_m := ((<span style="color: #ffa07a;">'0'</span> @toggle @hold | <span style="color: #ffa07a;">'1'</span> @toggle2     )* 0 @nl)*; # Bi-phase mark

<span style="color: #fa8072;">    # Aliases</span>
    pass   := any @{ fhold; <span style="color: #9acd32; font-weight: bold;">fgoto</span> <span style="color: #7fffd4; font-weight: bold;">nrz_l</span>; };
    <span style="color: #7fffd4;">invert</span> := any @{ fhold; <span style="color: #9acd32; font-weight: bold;">fgoto</span> <span style="color: #7fffd4; font-weight: bold;">nrz_i</span>; };
    <span style="color: #7fffd4;">manch</span>  := any @{ fhold; <span style="color: #9acd32; font-weight: bold;">fgoto</span> <span style="color: #7fffd4; font-weight: bold;">bph_l</span>; };
    <span style="color: #7fffd4;">main</span>   := any @{ fhold; <span style="color: #9acd32; font-weight: bold;">fgoto</span> <span style="color: #7fffd4; font-weight: bold;">nrz_l</span>; };
}%%

%% write data;

<span style="color: #9acd32; font-weight: bold;">void</span> <span style="color: #7fffd4; font-weight: bold;">line_code_init</span>(<span style="color: #fa8072;">struct</span> <span style="color: #9acd32; font-weight: bold;">line_code</span> *<span style="color: #7fffd4; font-weight: bold;">fsm</span>, <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">first_bit</span>, <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">start</span>)
{
    fsm-&gt;bit = first_bit;

    %% write init;

    fsm-&gt;cs = start;
}

<span style="color: #9acd32; font-weight: bold;">void</span> <span style="color: #7fffd4; font-weight: bold;">line_code_execute</span>(<span style="color: #fa8072;">struct</span> <span style="color: #9acd32; font-weight: bold;">line_code</span> *<span style="color: #7fffd4; font-weight: bold;">fsm</span>, <span style="color: #fa8072;">const</span> <span style="color: #9acd32; font-weight: bold;">char</span> *<span style="color: #7fffd4; font-weight: bold;">data</span>, <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">len</span>)
{
    <span style="color: #fa8072;">const</span> <span style="color: #9acd32; font-weight: bold;">char</span> *<span style="color: #7fffd4; font-weight: bold;">p</span> = data;
    <span style="color: #fa8072;">const</span> <span style="color: #9acd32; font-weight: bold;">char</span> *<span style="color: #7fffd4; font-weight: bold;">pe</span> = data + len;

    %% write exec;
}

<span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">line_code_finish</span>(<span style="color: #fa8072;">struct</span> <span style="color: #9acd32; font-weight: bold;">line_code</span> *<span style="color: #7fffd4; font-weight: bold;">fsm</span>)
{
    <span style="color: #fa8072;">if</span> (fsm-&gt;cs == line_code_error) {
        <span style="color: #fa8072;">return</span> -1;
    }

    <span style="color: #fa8072;">if</span> (fsm-&gt;cs &gt;= line_code_first_final) {
        <span style="color: #fa8072;">return</span> 1;
    }
    <span style="color: #fa8072;">return</span> 0;
}

<span style="color: #fa8072;">#define</span> <span style="color: #7fffd4; font-weight: bold;">NUM_ELEMENTS</span>(<span style="color: #7fffd4; font-weight: bold;">a</span>) (<span style="color: #fa8072;">sizeof</span>(a)/<span style="color: #fa8072;">sizeof</span>(a[0]))
<span style="color: #fa8072;">#define</span> <span style="color: #7fffd4; font-weight: bold;">XSTRINGIFY</span>(<span style="color: #7fffd4; font-weight: bold;">s</span>) #s
<span style="color: #fa8072;">#define</span> <span style="color: #7fffd4; font-weight: bold;">STRINGIFY</span>(<span style="color: #7fffd4; font-weight: bold;">s</span>) XSTRINGIFY(s)
<span style="color: #fa8072;">#define</span> <span style="color: #7fffd4; font-weight: bold;">MACHINE</span>(<span style="color: #7fffd4; font-weight: bold;">name</span>, <span style="color: #7fffd4; font-weight: bold;">desc</span>) { STRINGIFY(name), desc, &amp;line_code_en_ ## name }

<span style="color: #fa8072;">struct</span> { <span style="color: #fa8072;">const</span> <span style="color: #9acd32; font-weight: bold;">char</span> *<span style="color: #7fffd4; font-weight: bold;">name</span>; <span style="color: #9acd32; font-weight: bold;">char</span>* <span style="color: #7fffd4; font-weight: bold;">desc</span>; <span style="color: #fa8072;">const</span> <span style="color: #9acd32; font-weight: bold;">int</span> *<span style="color: #7fffd4; font-weight: bold;">start</span>; } <span style="color: #7fffd4; font-weight: bold;">machines</span>[] = {
    MACHINE(nrz_l,  <span style="color: #ffa07a;">"Non-return-to-zero level"</span>),
    MACHINE(nrz_i,  <span style="color: #ffa07a;">"Non-return-to-zero invert"</span>),
    MACHINE(nrz_s,  <span style="color: #ffa07a;">"Non-return-to-zero space"</span>),
    MACHINE(nrz_m,  <span style="color: #ffa07a;">"Non-return-to-zero mark"</span>),
    MACHINE(bph_l,  <span style="color: #ffa07a;">"Bi-phase level"</span>),
    MACHINE(bph_s,  <span style="color: #ffa07a;">"Bi-phase space"</span>),
    MACHINE(bph_m,  <span style="color: #ffa07a;">"Bi-phase mark"</span>),
    MACHINE(pass,   <span style="color: #ffa07a;">"Passthrough (alias of nrz_l)"</span>),
    MACHINE(invert, <span style="color: #ffa07a;">"Invert (alias of nrz_i)"</span>),
    MACHINE(manch,  <span style="color: #ffa07a;">"Manchester (alias of bph_l)"</span>),
};

<span style="color: #9acd32; font-weight: bold;">void</span> <span style="color: #7fffd4; font-weight: bold;">usage</span>(<span style="color: #9acd32; font-weight: bold;">char</span> *<span style="color: #7fffd4; font-weight: bold;">name</span>) {
    printf(<span style="color: #ffa07a;">"%s [flags] input"</span> , name);
    printf(<span style="color: #ffa07a;">"    input\n"</span>
           <span style="color: #ffa07a;">"        One or more strings of 0's and 1's\n"</span>
           <span style="color: #ffa07a;">"    -i n\n"</span>
           <span style="color: #ffa07a;">"        Initial line state (default: 0)\n"</span>
           <span style="color: #ffa07a;">"    -c name\n"</span>
           <span style="color: #ffa07a;">"        Line code to use (default: pass)\n"</span>);
    printf(<span style="color: #ffa07a;">"\nAvailable codes:\n"</span>);
    <span style="color: #fa8072;">for</span> (<span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">i</span> = 0; i &lt; NUM_ELEMENTS(machines); i++) {
        printf(<span style="color: #ffa07a;">"  %-7s- %s\n"</span>, machines[i].name, machines[i].desc);
    }
}

<span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">main</span>(<span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">argc</span>, <span style="color: #9acd32; font-weight: bold;">char</span> **<span style="color: #7fffd4; font-weight: bold;">argv</span>)
{
    <span style="color: #fa8072;">struct</span> <span style="color: #9acd32; font-weight: bold;">line_code</span> <span style="color: #7fffd4; font-weight: bold;">lc</span>;

    <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">first_bit</span> = 0;
    <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">start</span> = line_code_en_nrz_l;

    <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">opt</span>;
    <span style="color: #fa8072;">while</span> ((opt = getopt(argc, argv, <span style="color: #ffa07a;">"f:m:h"</span>)) != -1) {
        <span style="color: #fa8072;">switch</span> (opt) {
            <span style="color: #fa8072;">case</span> <span style="color: #ffa07a;">'f'</span>: {
                first_bit = !!atoi(optarg);
                <span style="color: #fa8072;">break</span>;
            }
            <span style="color: #fa8072;">case</span> <span style="color: #ffa07a;">'m'</span>: {
                <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">found</span> = 0;
                <span style="color: #fa8072;">for</span> (<span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">i</span> = 0; i &lt; NUM_ELEMENTS(machines); i++) {
                    <span style="color: #fa8072;">if</span> (strcmp(optarg, machines[i].name) == 0) {
                        start = *machines[i].start;
                        found = 1;
                        <span style="color: #fa8072;">break</span>;
                    }
                }
                <span style="color: #fa8072;">if</span> (!found) {
                    printf(<span style="color: #ffa07a;">"Invalid machine name: %s\n"</span>, optarg);
                    usage(argv[0]);
                    exit(EXIT_FAILURE);
                }
                <span style="color: #fa8072;">break</span>;
            }
            <span style="color: #fa8072;">case</span> <span style="color: #ffa07a;">'h'</span>: {
                usage(argv[0]);
                exit(EXIT_SUCCESS);
                <span style="color: #fa8072;">break</span>;
            }
            <span style="color: #fa8072;">default</span>: {
                usage(argv[0]);
                exit(EXIT_FAILURE);
                <span style="color: #fa8072;">break</span>;
            }
        }
    }

    <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">Initialize state machine</span><span style="color: #add8e6;"> */</span>
    line_code_init(&amp;lc, first_bit, start);

    <span style="color: #fa8072;">for</span> (<span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">i</span> = optind; i &lt; argc; i++) {
        <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">Encode each input argument.</span><span style="color: #add8e6;"> */</span>
        line_code_execute(&amp;lc, argv[i], strlen(argv[i])+1);
    }

    <span style="color: #fa8072;">if</span> (line_code_finish(&amp;lc) != 1) {
        fprintf(stderr, <span style="color: #ffa07a;">"%s: bad input\n"</span>, argv[0]);
        usage(argv[0]);
        exit(EXIT_FAILURE);
    }

    <span style="color: #fa8072;">return</span> 0;
}
</pre>
</div>


<p>
Here are the generated state machines:
</p>

<div id="org0efda6f" class="figure">
<p><img src="https://remcycles.net/blog/../images/lc.svg" alt="Line encoding state machines" class="org-svg" width="80%" />
</p>
<p><span class="figure-number">Figure 1: </span>Line encoding state machines</p>
</div>


<p>
And here is some example output:
</p>
<pre class="example" id="orgd71898d">
$ cat ./lc.sh
#!/bin/sh
INPUT=01001100011100001111

for machine in nrz_l nrz_i nrz_s nrz_m bph_l bph_s bph_m pass invert manch ; do
    echo ${machine} $(./lc -m ${machine} ${INPUT})
done

$ ./lc.sh
pass lhl.h.l..h..l...h...
invert hlh.l.h..l..h...l...
nrz_l lhl.h.l..h..l...h...
nrz_i hlh.l.h..l..h...l...
nrz_s h.lh..lhl...hlhl....
nrz_m .h..lh...lhl....hlhl
manch lhhllhlhhlhllhlhlhhlhlhllhlhlhlhhlhlhlhl
bph_l lhhllhlhhlhllhlhlhhlhlhllhlhlhlhhlhlhlhl
bph_s hlh.lhlhl.h.lhlhlhl.h.l.hlhlhlhlh.l.h.l.
bph_m h.lhl.h.lhlhl.h.l.hlhlhlh.l.h.l.hlhlhlhl
</pre>

<div class="org-src-container">
<pre class="src src-js">{signal: [
  {name: <span style="color: #ffa07a;">'pass'</span>,   wave: <span style="color: #ffa07a;">'lhl.h.l..h..l...h...'</span>},
  {name: <span style="color: #ffa07a;">'invert'</span>, wave: <span style="color: #ffa07a;">'hlh.l.h..l..h...l...'</span>},
  {name: <span style="color: #ffa07a;">'nrz_l'</span>,  wave: <span style="color: #ffa07a;">'lhl.h.l..h..l...h...'</span>},
  {name: <span style="color: #ffa07a;">'nrz_i'</span>,  wave: <span style="color: #ffa07a;">'hlh.l.h..l..h...l...'</span>},
  {name: <span style="color: #ffa07a;">'nrz_s'</span>,  wave: <span style="color: #ffa07a;">'h.lh..lhl...hlhl....'</span>},
  {name: <span style="color: #ffa07a;">'nrz_m'</span>,  wave: <span style="color: #ffa07a;">'.h..lh...lhl....hlhl'</span>},
  {name: <span style="color: #ffa07a;">'manch'</span>,  wave: <span style="color: #ffa07a;">'lhhllhlhhlhllhlhlhhlhlhllhlhlhlhhlhlhlhl'</span>},
  {name: <span style="color: #ffa07a;">'bph_l'</span>,  wave: <span style="color: #ffa07a;">'lhhllhlhhlhllhlhlhhlhlhllhlhlhlhhlhlhlhl'</span>},
  {name: <span style="color: #ffa07a;">'bph_s'</span>,  wave: <span style="color: #ffa07a;">'hlh.lhlhl.h.lhlhlhl.h.l.hlhlhlhlh.l.h.l.'</span>},
  {name: <span style="color: #ffa07a;">'bph_m'</span>,  wave: <span style="color: #ffa07a;">'h.lhl.h.lhlhl.h.l.hlhlhlh.l.h.l.hlhlhlhl'</span>},
]}
</pre>
</div>


<div id="org42f2288" class="figure">
<p><a href="https://remcycles.net/blog/../images/lc_wavedrom.svg" alt="Line encoding output rendered by WaveDrom" width="100%"><img src="https://remcycles.net/blog/../images/lc_wavedrom.png" alt="Line encoding output rendered by WaveDrom" width="100%" /></a>
</p>
<p><span class="figure-number">Figure 2: </span>Line encoding output rendered by WaveDrom</p>
</div>


<p>
All the code (including a Makefile) can be found here:
</p>

<p>
<a href="https://remcycles.net/blog/../files/linecode/linecode.tar.gz">linecode.tar.gz</a>
</p>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Phasor Diagrams and Z-Plane Plots with Pikchr</title>
<link>https://remcycles.net/blog/pikchr_plots.html</link>
<pubDate>Sun, 16 Apr 2023 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/pikchr_plots.html</guid>
<description>
<![CDATA[<style>
.figure-number {
    display: none;
}
</style>

<p>
I thought it might be nice to have some rectangular and polar graph
paper for studying pole-zero plots by hand on the Z-plane, so I
whipped this up in Pikchr:
</p>

<p>
(<a href="https://remcycles.net/blog/../files/z_plane.pikchr">source code</a>)
</p>

<p>
I was pleasantly surpised to learn that Pikchr supports macros.  It's
only documented in the language grammar, but it works well to simplify
diagram source code and extend the little language.
</p>

<p>
And for when I want to make SVG files for phasor diagrams there's this:
(<a href="https://remcycles.net/blog/../files/phasor.pikchr">source code</a>)
</p>

</br>
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/">
  <img alt="Creative Commons License" style="border-width:0"
     src="../images/cc/cc_4p0_88x31.png" /></a>
<br/>
This work is licensed under a
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/">
  Creative Commons Attribution 4.0 International License</a>.

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Numeronyms</title>
<link>https://remcycles.net/blog/numeronyms.html</link>
<pubDate>Sat, 02 Feb 2019 00:00:00 -0800</pubDate>
<guid>https://remcycles.net/blog/numeronyms.html</guid>
<description>
<![CDATA[<p>
Lately one of the strange concepts that interest me is that of
<a href="https://en.wikipedia.org/wiki/Numeronym">numeronyms</a>.  Those funny shortenings of long words, where the middle
letters are replaced with the count of those letters.  For example,
"example" would become "e5e".
</p>

<p>
My first exposure to them came while I worked on the localization of
the now defunct Nike+ Connect desktop app, which supported 13
different languages.  I had a lot of fun on that project and learned
a lot about world languages and orthography, and the technologies
behind their computer representation (Unicode, other historical text
encodings, input methods, GNU gettext, C locales, etc).
</p>

<p>
I also learned that the words "localization" and
"internationalization" are too long for many people to write out in
full.  They are commonly shortened to "l10n" and "i18n",
respectively.  I understand that those are long English words, but I
found the practice to be strangely Anglo-centric and therefore a
little arrogant.
</p>

<p>
The point of localization is to enable users to interact with
applications in their native language and that requires us to
realize that not everyone speaks the same language we do.  Proper
software localization is a difficult and somewhat tedious task that
could be seen as boring, especially by monoglots.  But I see it as a
sign of respect.  Such numeronym shortenings of "localization" and
"internationalization" seem to belittle that important task.  But
perhaps this is just my own opinion and a polyglot would be apt to
shorten as well.
</p>

<p>
But there are other problems with numeronyms.
</p>

<p>
Language understanding has a large statistical component.  The
expansion of "l10n" requires an in-depth knowledge of English
(assuming that the numeronym shortens an English word in the first
place) and what words might possibly fit, which of course depends on
the context.  For example, "l10n" can be expanded to the following
English words:
</p>

<pre class="example" id="org196c157">
legalization
liquefaction
localization
longshoreman
longshoremen
</pre>

<p>
Depending on who you are, each of the expansions might be more
important than the others.
</p>

<p>
To help illustrate this point I wrote the following <code>bash</code> script
around a relatively simple <code>grep</code> search through
<code>/usr/share/dict/words</code>:
</p>

<div class="org-src-container">
<pre class="src src-bash">~/scripts $ cat ./annoyances.sh
<span style="color: #add8e6;">#</span><span style="color: #add8e6;">!/bin/bash</span>

<span style="color: #fa8072;">if</span> [[ $<span style="color: #7fffd4; font-weight: bold;">1</span> =~ ^([a-z])([0-9]+)([a-z])$ ]] ; <span style="color: #fa8072;">then</span>
  grep <span style="color: #ffa07a;">"^${BASH_REMATCH[1]}[^']\{${BASH_REMATCH[2]}\}${BASH_REMATCH[3]}$"</span> /usr/share/dict/words
<span style="color: #fa8072;">else</span>
  <span style="color: #98fb98; font-weight: bold;">echo</span> Poor form.
<span style="color: #fa8072;">fi</span>
</pre>
</div>

<p>
Prior to this I didn't know that bash had a <code>=~</code> operator similar to
Perl.  I use it here to parse the input as first letter, count, and
last letter.  Unfortunately, the <code>BASH_REMATCH</code> array variable it
stores results to can't be easily renamed, so the one-line <code>grep</code>
command is a little uglier than it could be.  It simply tries to
match the input pattern with the proper number of non-apostrophe
characters.
</p>

<p>
Let's run it on "k8s", another recent numeronym I've seen:
</p>

<pre class="example" id="org233abff">
$ ./annoyances.sh k8s
kerchieves
keypunches
keystrokes
kickstands
kidnappers
kilocycles
kilometers
kindliness
kindnesses
kinematics
kohlrabies
</pre>

<p>
Hmm, it doesn't seem like the intended expansion is in here.  And
that's because it's actually the Greek "kubernetes" meaning
"helmsman".
</p>

<p>
So in a way, I realize that a numeronym used often enough and with
enough context might develop a well-understood meaning across
languages.  Acronyms, of course have similar problems and
possibilities.
</p>

<p>
Then again, you might wrongly assume that the <a href="https://teespring.com/stores/runk8s">"RUN K8S" shirts</a> out
there mean "Run Kilometers".  And if you wanted to shorten the name
of my script to "a8s" you'd have 171 possible expansions (at least
with my system's dictionary).
</p>

<p>
To explore those problems and possibilities further, I wrote the
inverse of the above script.  This one shortens each group of
letters into a numeronym:
</p>

<div class="org-src-container">
<pre class="src src-awk">$ cat numeronym.awk
<span style="color: #add8e6;">#</span><span style="color: #add8e6;">!/usr/bin/awk -f</span>

<span style="color: #fa8072;">BEGIN</span> { savings = 0 }

{
  nwords = <span style="color: #fa8072;">split</span>($0, a, <span style="color: #ffa07a;">/[^[:alpha:]]+/</span>, seps)
  <span style="color: #fa8072;">for</span> (i=1; i&lt;=nwords; i++) {
    <span style="color: #fa8072;">if</span>(<span style="color: #fa8072;">match</span>(a[i], <span style="color: #ffa07a;">/^([[:alpha:]])([[:alpha:]]{2,})([[:alpha:]])$/</span>, b)) {
      <span style="color: #fa8072;">printf</span> <span style="color: #ffa07a;">"%s"</span>, b[1]<span style="color: #fa8072;">length</span>(b[2])b[3]
      savings += <span style="color: #fa8072;">length</span>(b[2]) - 1
    }
    <span style="color: #fa8072;">else</span> {
      <span style="color: #fa8072;">printf</span> <span style="color: #ffa07a;">"%s"</span>, a[i]
    }

    <span style="color: #fa8072;">printf</span> <span style="color: #ffa07a;">"%s"</span>, seps[i] 
  }
  <span style="color: #fa8072;">printf</span> <span style="color: #ffa07a;">"\n"</span>
}

<span style="color: #fa8072;">END</span> {
  <span style="color: #fa8072;">printf</span> <span style="color: #ffa07a;">"You saved %d chars today!\n"</span>, savings
}
</pre>
</div>

<p>
The only real complication here is that by default awk discards the
field separators when parsing, so we're forced to <code>split()</code> each
line ourselves so we can print both the (modified) fields and
separators.
</p>

<p>
Changing the "at least 2" clause from <code>{2,}</code> to <code>{0,}</code> (aka <code>*</code>)
leads to the seemingly valid reductions of "it" to "i0t", but since
that <b>adds</b> characters I haven't done that here.  Likewise,
replacing a single letter with the number "1" seems less than
helpful.
</p>

<p>
Despite a parallel with <a href="https://www.sciencealert.com/word-jumble-meme-first-last-letters-cambridge-typoglycaemia">a popular meme</a> that shows recognizing words
with jumbled inner letters (where the first and last are kept the
same like in numeronyms) can be fairly easy, numeronyms do not seem
easy to read.
</p>

<p>
To provide an example of the resulting reading difficulty, here is
the preface to <a href="http://www.gutenberg.org/files/74/74-0.txt">Tom Sawyer</a>:
</p>
<blockquote>
<p>
P5E
</p>

<p>
M2t of the a8s r6d in t2s b2k r4y o6d; one or two
w2e e9s of my own, the r2t t3e of b2s who w2e s9s
of m2e. H2k F2n is d3n f2m l2e; Tom S4r a2o, but not f2m an
i8l&#x2013;he is a c9n of the c13s of t3e b2s w2m
I k2w, and t7e b5s to the c7e o3r of a10e.
</p>

<p>
The odd s11s t5d u2n w2e all p7t a3g c6n and
s4s in the W2t at the p4d of t2s s3y&#x2013;t2t is to say, t4y or
f3y y3s ago.
</p>

<p>
A6h my b2k is i6d m4y for the e11t of b2s and
g3s, I h2e it w2l not be s5d by men and w3n on t2t a5t,
for p2t of my p2n has b2n to try to p8y r4d a4s of w2t
t2y o2e w2e t8s, and of how t2y f2t and t5t and t4d,
and w2t q3r e9s t2y s7s e5d in.
</p>

<p>
THE A4R.
</p>

<p>
H6D, 1876.
</p>

<p>
You saved 273 chars today!
</p>
</blockquote>

<p>
Now go forth and save the world from the hassle of reading all those
extraneous letters!
</p>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>A Knuth Reward Check</title>
<link>https://remcycles.net/blog/knuth_check.html</link>
<pubDate>Fri, 21 Feb 2025 00:00:00 -0800</pubDate>
<guid>https://remcycles.net/blog/knuth_check.html</guid>
<description>
<![CDATA[<p>
Last week I got a <a href="https://en.wikipedia.org/wiki/Knuth_reward_check">check in the mail from Donald Knuth</a>, for 0x$1.00
($2.56).  Such checks are awarded for being the first to report a
particular error in a published work.  In this case, it was in a draft
for the The Art of Computer Programming.  I'm still giddy about it.
</p>


<div id="org29c0814" class="figure">
<p><a href="https://remcycles.net/blog/../images/knuth_check_2021_f9b.40.jpg" width="500px"><img src="https://remcycles.net/blog/../images/knuth_check_2021_f9b.40.jpg" alt="knuth_check_2021_f9b.40.jpg" width="500px" /></a>
</p>
</div>

<p>
The report I sent on April 1st, 2024 in read:
</p>
<blockquote>
<p>
I found two missing names in the index margin notes for Pre-Fascicle
9b (A Potpourri of Puzzles), dated April 22, 2023.
</p>

<p>
Loyd and Frederickson are both mentioned in the answer to exercise 88
in section 7.2.2.8, but they do not appear in the margin notes for
compiling the index.
</p>
</blockquote>

<p>
He replied in pencil:
</p>
<blockquote>
<p>
Frederickson was omitted intentionally, since he is cited in the
<span class="underline">statement</span> of ex 88.  But I should indeed have indexed Loyd.
</p>
</blockquote>

<p>
This is the easiest way to get a reward check, since I didn't have to
actually understand the exercise or answer, but Knuth cares about the
quality of his index and so it's worth a reward to him.
</p>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Merge Sorting Images with TCL</title>
<link>https://remcycles.net/blog/image_sort.html</link>
<pubDate>Sun, 30 Jan 2022 00:00:00 -0800</pubDate>
<guid>https://remcycles.net/blog/image_sort.html</guid>
<description>
<![CDATA[<p>
I've been having fun shooting film photography this year.  Digital
scans of film don't have metadata about when each photo was taken, and
rolls can get developed and scanned out of order, etc.  That makes
sorting the photos chronologically difficult to automate.
</p>

<p>
I wanted a quick way to manually sort a list of images
(chronologically or otherwise), and I figured merge sort might be a
fun way to do it.  It turns out to be rather tedious, especially
without an "undo" feature for incorrect input, but it was a fun
experiment.  A drag and drop GUI tool would be easier.
</p>

<p>
I decided to do this with Tcl/Tk because it's the most terse GUI
framework I've seen, and it was fun practice.  The built-in <code>sort</code>
command uses merge sort, so I didn't have to write my own.  The
<code>-command</code> option takes a procedure to compare to items.  For my
compare procedure I use the <code>vwait</code> command to run the Tk GUI runloop
and wait until the variable <code>compare_result</code> is changed via the GUI
interface.  I was pleased that this works rather well.
</p>

<p>
I used this script by Keith Vetter as an example for how to manage the
image display code and stripped out all the features I didn't want,
like toolbar buttons, etc:
<a href="https://wiki.tcl-lang.org/page/Image+Viewer">https://wiki.tcl-lang.org/page/Image+Viewer</a>
</p>


<div id="org95d374b" class="figure">
<p><img src="https://remcycles.net/blog/../images/image_sort.png" alt="image_sort.png" />
</p>
</div>

<p>
<a href="https://remcycles.net/blog/../files/image_sort/image_sort.tcl">image<sub>sort.tcl</sub></a>:
</p>
<div class="org-src-container">
<pre class="src src-tcl"><span style="color: #add8e6;"># </span><span style="color: #add8e6;">image_sort.tcl -- merge sort images with user input</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">by Remington Furman 2021-01-08</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Based on image_viewer.tcl by Keith Vetter 2013-08-31</span>
<span style="color: #add8e6;">#</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Merge sort a list of images based on user input.  Each comparison</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">step presents the user with two images, and the image that should</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">come first is selected with a key (`a` or `h` for the left image and</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">`d` or `l` for the right image).</span>
<span style="color: #add8e6;">#</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Write the list of filenames to a file, then call this script like so:</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">$ wish image_sort.tcl file_list.txt</span>
<span style="color: #add8e6;">#</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Or use Bash process substitution:</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">$ wish image_sort.tcl &lt;(ls photos/*.jpg)</span>

<span style="color: #98fb98; font-weight: bold;">package</span> require Tk
<span style="color: #98fb98; font-weight: bold;">package</span> require Img

<span style="color: #98fb98; font-weight: bold;">set</span> <span style="color: #7fffd4; font-weight: bold;">S</span>(title) <span style="color: #ffa07a;">"Image Sorter"</span>
<span style="color: #98fb98; font-weight: bold;">set</span> <span style="color: #7fffd4; font-weight: bold;">S</span>(fnamel) <span style="color: #ffa07a;">""</span>
<span style="color: #98fb98; font-weight: bold;">set</span> <span style="color: #7fffd4; font-weight: bold;">S</span>(fnamer) <span style="color: #ffa07a;">""</span>

<span style="color: #98fb98; font-weight: bold;">set</span> <span style="color: #7fffd4; font-weight: bold;">SCALING_FACTORS</span> [dict create 1 1 2 1/2 3 1/3 4 1/4 1/2 2 1/3 3 1/4 4]

<span style="color: #fa8072;">proc</span> <span style="color: #7fffd4; font-weight: bold;">init_display</span> {} {
    <span style="color: #9acd32; font-weight: bold;">global</span> S

    wm title . $<span style="color: #7fffd4; font-weight: bold;">S</span>(title)
    destroy {*}[winfo child .]

    <span style="color: #98fb98; font-weight: bold;">set</span> <span style="color: #7fffd4; font-weight: bold;">::S</span>(max,width)  [<span style="color: #98fb98; font-weight: bold;">expr</span> {([winfo screenwidth .] / 2) - 100}]
    <span style="color: #98fb98; font-weight: bold;">set</span> <span style="color: #7fffd4; font-weight: bold;">::S</span>(max,height) [<span style="color: #98fb98; font-weight: bold;">expr</span> {[winfo screenheight .] - 200}]

    <span style="color: #fa8072;">foreach</span> side {l r} {
        canvas <span style="color: #ffa07a;">".c${side}"</span> -bd 5 -highlightthickness 0 <span style="color: #ffa07a;">\</span>
            -width 600 -height 700 -bg dimgray
        label <span style="color: #ffa07a;">".fn${side}"</span> -textvariable <span style="color: #ffa07a;">"S(fname${side})"</span>
    }

    grid .fnl .fnr
    grid .cl .cr -sticky ns
    grid rowconfigure . 1 -weight 1
    grid columnconfigure . 0 -weight 1
    grid configure .cl -sticky news
    grid configure .cr -sticky news

    <span style="color: #fa8072;">foreach</span> canvas {.cl .cr} {
        $<span style="color: #7fffd4; font-weight: bold;">canvas</span> create image 0 0 -tag img -anchor nw
        $<span style="color: #7fffd4; font-weight: bold;">canvas</span> create rect -100 -100 -100 -100 <span style="color: #ffa07a;">\</span>
            -tag cropBox -fill {} -outline red -width 3 -dash <span style="color: #ffa07a;">"-"</span>
    }

    bind all &lt;Control-w&gt; <span style="color: #fa8072;">exit</span>
    bind . &lt;Destroy&gt; <span style="color: #fa8072;">exit</span>

    <span style="color: #fa8072;">foreach</span> event { &lt;Left&gt; &lt;Prior&gt; &lt;leftarrow&gt; a h } {
        bind all $<span style="color: #7fffd4; font-weight: bold;">event</span> [<span style="color: #98fb98; font-weight: bold;">list</span> <span style="color: #98fb98; font-weight: bold;">set</span> <span style="color: #7fffd4; font-weight: bold;">compare_result</span> -1]
    }

    <span style="color: #fa8072;">foreach</span> event { &lt;Right&gt; &lt;Next&gt; &lt;rightarrow&gt; d l } {
        bind all $<span style="color: #7fffd4; font-weight: bold;">event</span> [<span style="color: #98fb98; font-weight: bold;">list</span> <span style="color: #98fb98; font-weight: bold;">set</span> <span style="color: #7fffd4; font-weight: bold;">compare_result</span> 1]
    }

    bind all &lt;Alt-c&gt; {<span style="color: #98fb98; font-weight: bold;">catch</span> {<span style="color: #98fb98; font-weight: bold;">console</span> show}}
}

<span style="color: #fa8072;">proc</span> <span style="color: #7fffd4; font-weight: bold;">shrink_image_to_fit_screen</span> {canvas} {
    <span style="color: #98fb98; font-weight: bold;">set</span> <span style="color: #7fffd4; font-weight: bold;">w</span> [image width <span style="color: #ffa07a;">"::img::img$canvas"</span>]
    <span style="color: #98fb98; font-weight: bold;">set</span> <span style="color: #7fffd4; font-weight: bold;">h</span> [image height <span style="color: #ffa07a;">"::img::img$canvas"</span>]
    <span style="color: #fa8072;">foreach</span> factor {1 2 3 4} {
        <span style="color: #fa8072;">if</span> {$<span style="color: #7fffd4; font-weight: bold;">w</span> / $<span style="color: #7fffd4; font-weight: bold;">factor</span> &lt; $<span style="color: #7fffd4; font-weight: bold;">::S</span>(max,width) &amp;&amp; <span style="color: #ffa07a;">\</span>
            $<span style="color: #7fffd4; font-weight: bold;">h</span> / $<span style="color: #7fffd4; font-weight: bold;">factor</span> &lt; $<span style="color: #7fffd4; font-weight: bold;">::S</span>(max,height)} <span style="color: #fa8072;">break</span>
    }
    <span style="color: #98fb98; font-weight: bold;">set</span> <span style="color: #7fffd4; font-weight: bold;">::S</span>("shrunk$<span style="color: #7fffd4; font-weight: bold;">canvas</span>") [dict get $<span style="color: #7fffd4; font-weight: bold;">::SCALING_FACTORS</span> $<span style="color: #7fffd4; font-weight: bold;">factor</span>]
}

<span style="color: #fa8072;">proc</span> <span style="color: #7fffd4; font-weight: bold;">make_display_image</span> {canvas} {
    <span style="color: #9acd32; font-weight: bold;">global</span> S

    <span style="color: #fa8072;">if</span> {<span style="color: #ffa07a;">"::img::display$canvas"</span> <span style="color: #fa8072;">in</span> [image names]} {
        image delete <span style="color: #ffa07a;">"::img::display$canvas"</span>
    }

    ::image create photo <span style="color: #ffa07a;">"::img::display$canvas"</span>
    <span style="color: #ffa07a;">"::img::display$canvas"</span> copy <span style="color: #ffa07a;">"::img::working$canvas"</span>
    $<span style="color: #7fffd4; font-weight: bold;">canvas</span> coords img 0 0
    <span style="color: #98fb98; font-weight: bold;">set</span> <span style="color: #7fffd4; font-weight: bold;">S</span>(width,display)  $<span style="color: #7fffd4; font-weight: bold;">S</span>(width)
    <span style="color: #98fb98; font-weight: bold;">set</span> <span style="color: #7fffd4; font-weight: bold;">S</span>(height,display) $<span style="color: #7fffd4; font-weight: bold;">S</span>(height)

    $<span style="color: #7fffd4; font-weight: bold;">canvas</span> config -scrollregion [$<span style="color: #7fffd4; font-weight: bold;">canvas</span> bbox img]
    $<span style="color: #7fffd4; font-weight: bold;">canvas</span> itemconfig img -image <span style="color: #ffa07a;">"::img::display$canvas"</span>
    $<span style="color: #7fffd4; font-weight: bold;">canvas</span> xview moveto 0
    $<span style="color: #7fffd4; font-weight: bold;">canvas</span> yview moveto 0
}

<span style="color: #fa8072;">proc</span> <span style="color: #7fffd4; font-weight: bold;">load_image</span> {fname canvas} {
    <span style="color: #9acd32; font-weight: bold;">global</span> S

    <span style="color: #fa8072;">foreach</span> img {<span style="color: #ffa07a;">"::img::img$canvas"</span> <span style="color: #ffa07a;">"::img::working$canvas"</span>} {
        <span style="color: #fa8072;">if</span> {$<span style="color: #7fffd4; font-weight: bold;">img</span> <span style="color: #fa8072;">in</span> [image names]} {image delete $<span style="color: #7fffd4; font-weight: bold;">img</span>}
    }

    image create photo <span style="color: #ffa07a;">"::img::img$canvas"</span> -file $<span style="color: #7fffd4; font-weight: bold;">fname</span>
    image create photo <span style="color: #ffa07a;">"::img::working$canvas"</span>
    shrink_image_to_fit_screen $<span style="color: #7fffd4; font-weight: bold;">canvas</span>
    resize_image $<span style="color: #7fffd4; font-weight: bold;">canvas</span>

    wm geom . {}
    $<span style="color: #7fffd4; font-weight: bold;">canvas</span> config -width $<span style="color: #7fffd4; font-weight: bold;">S</span>(width,display) -height $<span style="color: #7fffd4; font-weight: bold;">S</span>(height,display)
}

<span style="color: #fa8072;">proc</span> <span style="color: #7fffd4; font-weight: bold;">resize_image</span> {canvas} {
    <span style="color: #9acd32; font-weight: bold;">global</span> S
    <span style="color: #98fb98; font-weight: bold;">set</span> <span style="color: #7fffd4; font-weight: bold;">factor</span> [dict get $<span style="color: #7fffd4; font-weight: bold;">::SCALING_FACTORS</span> $<span style="color: #7fffd4; font-weight: bold;">S</span>("shrunk$<span style="color: #7fffd4; font-weight: bold;">canvas</span>")]
    <span style="color: #fa8072;">if</span> {<span style="color: #ffa07a;">"::img::working$canvas"</span> <span style="color: #fa8072;">in</span> [image names]} {
        image delete <span style="color: #ffa07a;">"::img::working$canvas"</span>
    }
    image create photo <span style="color: #ffa07a;">"::img::working$canvas"</span>
    <span style="color: #ffa07a;">"::img::working$canvas"</span> copy <span style="color: #ffa07a;">"::img::img$canvas"</span> -subsample $<span style="color: #7fffd4; font-weight: bold;">factor</span>
    <span style="color: #98fb98; font-weight: bold;">set</span> <span style="color: #7fffd4; font-weight: bold;">S</span>(width) [image width <span style="color: #ffa07a;">"::img::working$canvas"</span>]
    <span style="color: #98fb98; font-weight: bold;">set</span> <span style="color: #7fffd4; font-weight: bold;">S</span>(height) [image height <span style="color: #ffa07a;">"::img::working$canvas"</span>]
    <span style="color: #98fb98; font-weight: bold;">set</span> <span style="color: #7fffd4; font-weight: bold;">S</span>(size) <span style="color: #ffa07a;">"${S(width)}x$S(height)"</span>

    make_display_image $<span style="color: #7fffd4; font-weight: bold;">canvas</span>
    $<span style="color: #7fffd4; font-weight: bold;">canvas</span> config -scrollregion [$<span style="color: #7fffd4; font-weight: bold;">canvas</span> bbox img]
    $<span style="color: #7fffd4; font-weight: bold;">canvas</span> coords cropBox -100 -100 -100 -100
}

<span style="color: #fa8072;">proc</span> <span style="color: #7fffd4; font-weight: bold;">compare_images</span> {a b} {
    <span style="color: #9acd32; font-weight: bold;">global</span> compare_result
    <span style="color: #9acd32; font-weight: bold;">global</span> S

    <span style="color: #98fb98; font-weight: bold;">puts</span> -nonewline <span style="color: #ffa07a;">"Comparing $a and $b: "</span>

    <span style="color: #add8e6;"># Display both images.</span>
    load_image $<span style="color: #7fffd4; font-weight: bold;">a</span> .cl
    load_image $<span style="color: #7fffd4; font-weight: bold;">b</span> .cr
    <span style="color: #98fb98; font-weight: bold;">set</span> <span style="color: #7fffd4; font-weight: bold;">S</span>(fnamel) [<span style="color: #98fb98; font-weight: bold;">file</span> tail $<span style="color: #7fffd4; font-weight: bold;">a</span>]
    <span style="color: #98fb98; font-weight: bold;">set</span> <span style="color: #7fffd4; font-weight: bold;">S</span>(fnamer) [<span style="color: #98fb98; font-weight: bold;">file</span> tail $<span style="color: #7fffd4; font-weight: bold;">b</span>]

    <span style="color: #add8e6;"># Wait for user input.</span>
    <span style="color: #98fb98; font-weight: bold;">vwait</span> compare_result
    <span style="color: #98fb98; font-weight: bold;">puts</span> $<span style="color: #7fffd4; font-weight: bold;">compare_result</span>

    <span style="color: #add8e6;"># Return result.</span>
    <span style="color: #fa8072;">return</span> $<span style="color: #7fffd4; font-weight: bold;">compare_result</span>
}

<span style="color: #fa8072;">proc</span> <span style="color: #7fffd4; font-weight: bold;">read_file_list</span> {<span style="color: #98fb98; font-weight: bold;">file</span>} {
    <span style="color: #98fb98; font-weight: bold;">set</span> <span style="color: #7fffd4; font-weight: bold;">f</span> [<span style="color: #98fb98; font-weight: bold;">open</span> $<span style="color: #7fffd4; font-weight: bold;">file</span> r]
    <span style="color: #add8e6;"># Split the file by newlines, and remove the empty element from</span>
    <span style="color: #add8e6;"># the end of the list.</span>
    <span style="color: #98fb98; font-weight: bold;">set</span> <span style="color: #7fffd4; font-weight: bold;">files</span> [<span style="color: #98fb98; font-weight: bold;">lreplace</span> [<span style="color: #98fb98; font-weight: bold;">split</span> [<span style="color: #98fb98; font-weight: bold;">read</span> $<span style="color: #7fffd4; font-weight: bold;">f</span>] <span style="color: #ffa07a;">"\n"</span>] end end]
    <span style="color: #98fb98; font-weight: bold;">close</span> $<span style="color: #7fffd4; font-weight: bold;">f</span>
    <span style="color: #fa8072;">return</span> $<span style="color: #7fffd4; font-weight: bold;">files</span>
}

init_display
<span style="color: #98fb98; font-weight: bold;">set</span> <span style="color: #7fffd4; font-weight: bold;">files</span> [read_file_list [<span style="color: #98fb98; font-weight: bold;">lindex</span> $<span style="color: #7fffd4; font-weight: bold;">argv</span> 0]]
<span style="color: #98fb98; font-weight: bold;">puts</span> <span style="color: #ffa07a;">"Sorting:  $files"</span>
<span style="color: #98fb98; font-weight: bold;">set</span> <span style="color: #7fffd4; font-weight: bold;">files</span> [<span style="color: #98fb98; font-weight: bold;">lsort</span> -command compare_images $<span style="color: #7fffd4; font-weight: bold;">files</span>]
<span style="color: #98fb98; font-weight: bold;">puts</span> <span style="color: #ffa07a;">"Finished sorting:"</span>
<span style="color: #98fb98; font-weight: bold;">puts</span> $<span style="color: #7fffd4; font-weight: bold;">files</span>

<span style="color: #fa8072;">exit</span>
</pre>
</div>

<p>
This makefile creates images of numbers to test the program with.
</p>

<p>
<a href="https://remcycles.net/blog/../files/image_sort/Makefile">Makefile</a>:
</p>
<div class="org-src-container">
<pre class="src src-makefile"><span style="color: #add8e6;"># </span><span style="color: #add8e6;">Make test images for image_sort.tcl</span>
<span style="color: #add8e6;">#</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">The parallelized Make loop trick is inspired by:</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">https://stackoverflow.com/a/12110773/182734</span>
<span style="color: #add8e6;">#</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">The imagemagick command is from:</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">https://stackoverflow.com/a/63043486/182734</span>

<span style="color: #7fffd4; font-weight: bold;">IMGDIR</span>=img
<span style="color: #7fffd4; font-weight: bold;">N</span> := 16
<span style="color: #7fffd4; font-weight: bold;">IMAGES</span> := $(<span style="color: #7fffd4; font-weight: bold;">addprefix</span> $(<span style="color: #7fffd4; font-weight: bold;">IMGDIR</span>)/test_image_, \
          $(<span style="color: #7fffd4; font-weight: bold;">addsuffix</span> .png, \
          $(<span style="color: #7fffd4; font-weight: bold;">shell</span> seq -w $(<span style="color: #7fffd4; font-weight: bold;">N</span>))))

<span style="color: #7fffd4; font-weight: bold;">all</span>: $(<span style="color: #7fffd4; font-weight: bold;">IMAGES</span>)

<span style="color: #7fffd4; font-weight: bold;">$(</span><span style="color: #7fffd4; font-weight: bold;">IMGDIR</span><span style="color: #7fffd4; font-weight: bold;">)</span>:
        mkdir <span style="color: #7fffd4; font-weight: bold;">$</span><span style="color: #7fffd4; font-weight: bold;">@</span>
<span style="color: #7fffd4; font-weight: bold;">$(</span><span style="color: #7fffd4; font-weight: bold;">IMAGES</span><span style="color: #7fffd4; font-weight: bold;">)</span>: $(<span style="color: #7fffd4; font-weight: bold;">IMGDIR</span>)/test_image_%.png:  | $(<span style="color: #7fffd4; font-weight: bold;">IMGDIR</span>)
        convert -gravity center -background black -fill white -size 200x150 \
        caption:<span style="color: #ffa07a;">"</span><span style="color: #ffa07a; font-weight: bold;">$</span><span style="color: #7fffd4; font-weight: bold;">*</span><span style="color: #ffa07a;">"</span> <span style="color: #7fffd4; font-weight: bold;">$</span><span style="color: #7fffd4; font-weight: bold;">@</span>
</pre>
</div>


<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Hex Address Cheatsheet</title>
<link>https://remcycles.net/blog/hex_address_cheatsheet.html</link>
<pubDate>Mon, 24 Jan 2022 00:00:00 -0800</pubDate>
<guid>https://remcycles.net/blog/hex_address_cheatsheet.html</guid>
<description>
<![CDATA[<p>
I find this table useful anytime I'm working with computer memories.
</p>

<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">


<colgroup>
<col  class="org-right" />

<col  class="org-right" />

<col  class="org-right" />

<col  class="org-right" />

<col  class="org-right" />

<col  class="org-right" />

<col  class="org-right" />
</colgroup>
<thead>
<tr>
<th scope="col" class="org-right">Num Addr Bits</th>
<th scope="col" class="org-right">Num bytes (dec)</th>
<th scope="col" class="org-right">Num bytes (hex)</th>
<th scope="col" class="org-right">Max addr (hex)</th>
<th scope="col" class="org-right">Size (kiB)</th>
<th scope="col" class="org-right">Size (MiB)</th>
<th scope="col" class="org-right">Size (GiB)</th>
</tr>
</thead>
<tbody>
<tr>
<td class="org-right">0</td>
<td class="org-right">1</td>
<td class="org-right">1</td>
<td class="org-right">0</td>
<td class="org-right">0</td>
<td class="org-right">0</td>
<td class="org-right">0</td>
</tr>

<tr>
<td class="org-right">1</td>
<td class="org-right">2</td>
<td class="org-right">2</td>
<td class="org-right">1</td>
<td class="org-right">0</td>
<td class="org-right">0</td>
<td class="org-right">0</td>
</tr>

<tr>
<td class="org-right">2</td>
<td class="org-right">4</td>
<td class="org-right">4</td>
<td class="org-right">3</td>
<td class="org-right">0</td>
<td class="org-right">0</td>
<td class="org-right">0</td>
</tr>

<tr>
<td class="org-right">3</td>
<td class="org-right">8</td>
<td class="org-right">8</td>
<td class="org-right">7</td>
<td class="org-right">0.01</td>
<td class="org-right">0</td>
<td class="org-right">0</td>
</tr>

<tr>
<td class="org-right">4</td>
<td class="org-right">16</td>
<td class="org-right">10</td>
<td class="org-right">F</td>
<td class="org-right">0.02</td>
<td class="org-right">0</td>
<td class="org-right">0</td>
</tr>

<tr>
<td class="org-right">5</td>
<td class="org-right">32</td>
<td class="org-right">20</td>
<td class="org-right">1F</td>
<td class="org-right">0.03</td>
<td class="org-right">0</td>
<td class="org-right">0</td>
</tr>

<tr>
<td class="org-right">6</td>
<td class="org-right">64</td>
<td class="org-right">40</td>
<td class="org-right">3F</td>
<td class="org-right">0.06</td>
<td class="org-right">0</td>
<td class="org-right">0</td>
</tr>

<tr>
<td class="org-right">7</td>
<td class="org-right">128</td>
<td class="org-right">80</td>
<td class="org-right">7F</td>
<td class="org-right">0.13</td>
<td class="org-right">0</td>
<td class="org-right">0</td>
</tr>

<tr>
<td class="org-right">8</td>
<td class="org-right">256</td>
<td class="org-right">100</td>
<td class="org-right">FF</td>
<td class="org-right">0.25</td>
<td class="org-right">0</td>
<td class="org-right">0</td>
</tr>

<tr>
<td class="org-right">9</td>
<td class="org-right">512</td>
<td class="org-right">200</td>
<td class="org-right">1FF</td>
<td class="org-right">0.5</td>
<td class="org-right">0</td>
<td class="org-right">0</td>
</tr>

<tr>
<td class="org-right">10</td>
<td class="org-right">1,024</td>
<td class="org-right">400</td>
<td class="org-right">3FF</td>
<td class="org-right">1</td>
<td class="org-right">0</td>
<td class="org-right">0</td>
</tr>

<tr>
<td class="org-right">11</td>
<td class="org-right">2,048</td>
<td class="org-right">800</td>
<td class="org-right">7FF</td>
<td class="org-right">2</td>
<td class="org-right">0</td>
<td class="org-right">0</td>
</tr>

<tr>
<td class="org-right">12</td>
<td class="org-right">4,096</td>
<td class="org-right">1000</td>
<td class="org-right">FFF</td>
<td class="org-right">4</td>
<td class="org-right">0</td>
<td class="org-right">0</td>
</tr>

<tr>
<td class="org-right">13</td>
<td class="org-right">8,192</td>
<td class="org-right">2000</td>
<td class="org-right">1FFF</td>
<td class="org-right">8</td>
<td class="org-right">0.01</td>
<td class="org-right">0</td>
</tr>

<tr>
<td class="org-right">14</td>
<td class="org-right">16,384</td>
<td class="org-right">4000</td>
<td class="org-right">3FFF</td>
<td class="org-right">16</td>
<td class="org-right">0.02</td>
<td class="org-right">0</td>
</tr>

<tr>
<td class="org-right">15</td>
<td class="org-right">32,768</td>
<td class="org-right">8000</td>
<td class="org-right">7FFF</td>
<td class="org-right">32</td>
<td class="org-right">0.03</td>
<td class="org-right">0</td>
</tr>

<tr>
<td class="org-right">16</td>
<td class="org-right">65,536</td>
<td class="org-right">10000</td>
<td class="org-right">FFFF</td>
<td class="org-right">64</td>
<td class="org-right">0.06</td>
<td class="org-right">0</td>
</tr>

<tr>
<td class="org-right">17</td>
<td class="org-right">131,072</td>
<td class="org-right">20000</td>
<td class="org-right">1FFFF</td>
<td class="org-right">128</td>
<td class="org-right">0.13</td>
<td class="org-right">0</td>
</tr>

<tr>
<td class="org-right">18</td>
<td class="org-right">262,144</td>
<td class="org-right">40000</td>
<td class="org-right">3FFFF</td>
<td class="org-right">256</td>
<td class="org-right">0.25</td>
<td class="org-right">0</td>
</tr>

<tr>
<td class="org-right">19</td>
<td class="org-right">524,288</td>
<td class="org-right">80000</td>
<td class="org-right">7FFFF</td>
<td class="org-right">512</td>
<td class="org-right">0.5</td>
<td class="org-right">0</td>
</tr>

<tr>
<td class="org-right">20</td>
<td class="org-right">1,048,576</td>
<td class="org-right">100000</td>
<td class="org-right">FFFFF</td>
<td class="org-right">1,024</td>
<td class="org-right">1</td>
<td class="org-right">0</td>
</tr>

<tr>
<td class="org-right">21</td>
<td class="org-right">2,097,152</td>
<td class="org-right">200000</td>
<td class="org-right">1FFFFF</td>
<td class="org-right">2,048</td>
<td class="org-right">2</td>
<td class="org-right">0</td>
</tr>

<tr>
<td class="org-right">22</td>
<td class="org-right">4,194,304</td>
<td class="org-right">400000</td>
<td class="org-right">3FFFFF</td>
<td class="org-right">4,096</td>
<td class="org-right">4</td>
<td class="org-right">0</td>
</tr>

<tr>
<td class="org-right">23</td>
<td class="org-right">8,388,608</td>
<td class="org-right">800000</td>
<td class="org-right">7FFFFF</td>
<td class="org-right">8,192</td>
<td class="org-right">8</td>
<td class="org-right">0.01</td>
</tr>

<tr>
<td class="org-right">24</td>
<td class="org-right">16,777,216</td>
<td class="org-right">1000000</td>
<td class="org-right">FFFFFF</td>
<td class="org-right">16,384</td>
<td class="org-right">16</td>
<td class="org-right">0.02</td>
</tr>

<tr>
<td class="org-right">25</td>
<td class="org-right">33,554,432</td>
<td class="org-right">2000000</td>
<td class="org-right">1FFFFFF</td>
<td class="org-right">32,768</td>
<td class="org-right">32</td>
<td class="org-right">0.03</td>
</tr>

<tr>
<td class="org-right">26</td>
<td class="org-right">67,108,864</td>
<td class="org-right">4000000</td>
<td class="org-right">3FFFFFF</td>
<td class="org-right">65,536</td>
<td class="org-right">64</td>
<td class="org-right">0.06</td>
</tr>

<tr>
<td class="org-right">27</td>
<td class="org-right">134,217,728</td>
<td class="org-right">8000000</td>
<td class="org-right">7FFFFFF</td>
<td class="org-right">131,072</td>
<td class="org-right">128</td>
<td class="org-right">0.13</td>
</tr>

<tr>
<td class="org-right">28</td>
<td class="org-right">268,435,456</td>
<td class="org-right">10000000</td>
<td class="org-right">FFFFFFF</td>
<td class="org-right">262,144</td>
<td class="org-right">256</td>
<td class="org-right">0.25</td>
</tr>

<tr>
<td class="org-right">29</td>
<td class="org-right">536,870,912</td>
<td class="org-right">20000000</td>
<td class="org-right">1FFFFFFF</td>
<td class="org-right">524,288</td>
<td class="org-right">512</td>
<td class="org-right">0.5</td>
</tr>

<tr>
<td class="org-right">30</td>
<td class="org-right">1,073,741,824</td>
<td class="org-right">40000000</td>
<td class="org-right">3FFFFFFF</td>
<td class="org-right">1,048,576</td>
<td class="org-right">1,024</td>
<td class="org-right">1</td>
</tr>

<tr>
<td class="org-right">31</td>
<td class="org-right">2,147,483,648</td>
<td class="org-right">80000000</td>
<td class="org-right">7FFFFFFF</td>
<td class="org-right">2,097,152</td>
<td class="org-right">2,048</td>
<td class="org-right">2</td>
</tr>

<tr>
<td class="org-right">32</td>
<td class="org-right">4,294,967,296</td>
<td class="org-right">100000000</td>
<td class="org-right">FFFFFFFF</td>
<td class="org-right">4,194,304</td>
<td class="org-right">4,096</td>
<td class="org-right">4</td>
</tr>

<tr>
<td class="org-right">33</td>
<td class="org-right">8,589,934,592</td>
<td class="org-right">200000000</td>
<td class="org-right">1FFFFFFFF</td>
<td class="org-right">8,388,608</td>
<td class="org-right">8,192</td>
<td class="org-right">8</td>
</tr>

<tr>
<td class="org-right">34</td>
<td class="org-right">17,179,869,184</td>
<td class="org-right">400000000</td>
<td class="org-right">3FFFFFFFF</td>
<td class="org-right">16,777,216</td>
<td class="org-right">16,384</td>
<td class="org-right">16</td>
</tr>

<tr>
<td class="org-right">35</td>
<td class="org-right">34,359,738,368</td>
<td class="org-right">800000000</td>
<td class="org-right">7FFFFFFFF</td>
<td class="org-right">33,554,432</td>
<td class="org-right">32,768</td>
<td class="org-right">32</td>
</tr>

<tr>
<td class="org-right">36</td>
<td class="org-right">68,719,476,736</td>
<td class="org-right">1000000000</td>
<td class="org-right">FFFFFFFFF</td>
<td class="org-right">67,108,864</td>
<td class="org-right">65,536</td>
<td class="org-right">64</td>
</tr>

<tr>
<td class="org-right">37</td>
<td class="org-right">137,438,953,472</td>
<td class="org-right">2000000000</td>
<td class="org-right">1FFFFFFFFF</td>
<td class="org-right">134,217,728</td>
<td class="org-right">131,072</td>
<td class="org-right">128</td>
</tr>

<tr>
<td class="org-right">38</td>
<td class="org-right">274,877,906,944</td>
<td class="org-right">4000000000</td>
<td class="org-right">3FFFFFFFFF</td>
<td class="org-right">268,435,456</td>
<td class="org-right">262,144</td>
<td class="org-right">256</td>
</tr>

<tr>
<td class="org-right">39</td>
<td class="org-right">549,755,813,888</td>
<td class="org-right">8000000000</td>
<td class="org-right">7FFFFFFFFF</td>
<td class="org-right">536,870,912</td>
<td class="org-right">524,288</td>
<td class="org-right">512</td>
</tr>

<tr>
<td class="org-right">40</td>
<td class="org-right">1,099,511,627,776</td>
<td class="org-right">10000000000</td>
<td class="org-right">FFFFFFFFFF</td>
<td class="org-right">1,073,741,824</td>
<td class="org-right">1,048,576</td>
<td class="org-right">1,024</td>
</tr>
</tbody>
</table>

<p>
Here is a <a href="https://remcycles.net/blog/../files/hex_address_cheat_sheet.pdf">printable PDF</a> and the <a href="https://remcycles.net/blog/../files/hex_address_cheat_sheet.ods">source file</a> (LibreOffice Calc).
</p>

</br>
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/">
  <img alt="Creative Commons License" style="border-width:0"
     src="../images/cc/cc_4p0_88x31.png" /></a>
<br/>
This work is licensed under a
<a rel="license" href="http://creativecommons.org/licenses/by/4.0/">
  Creative Commons Attribution 4.0 International License</a>.

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Modifying Graphviz Edge Labels with GVPR</title>
<link>https://remcycles.net/blog/gvpr_labels.html</link>
<pubDate>Sun, 30 Mar 2025 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/gvpr_labels.html</guid>
<description>
<![CDATA[<p>
I recently made a <a href="https://graphviz.org/">Graphviz</a> graph with long <a href="https://graphviz.org/docs/attrs/label/">edge label text</a> and I was
unhappy with the layout results.  The text was often placed too far
from an edge to make it clear which edge it was attached to.  The
<a href="https://graphviz.org/docs/attrs/decorate/">decorate</a> attribute helped, but was ugly.
</p>

<p>
To make the diagram more clear, I moved the label text into new nodes
in the middle of the edge.  I automated this with GVPR, part of the
Graphviz tools.
</p>

<p>
<a href="https://graphviz.org/pdf/gvpr.1.pdf">GVPR</a> is a neat language heavily influenced by Awk designed to modify
graphs notated in Graphviz.  It walks through all the edges and nodes
of a graph for you, so your code can focus on the operations you want
to perform, not how to traverse the graph.
</p>

<p>
This script was a little tricky to figure out.  Modifying the graph in
place would cause infinite loops, because splitting an edge in two
made two more edges for the <code>E</code> pattern matcher to process.  So I had
to learn how to copy the input graph to the output graph (<code>$O</code>) as it
iterated over the input.
</p>

<p>
For example, here's the bridges of Koenigsberg:
</p>


<div id="org6293b8e" class="figure">
<p><img src="https://remcycles.net/blog/../images/koenigsberg.svg" alt="koenigsberg.svg" class="org-svg" width="70%" />
</p>
</div>

<div id="orgc1c55f0" class="figure">
<p><img src="https://remcycles.net/blog/../images/koenigsberg_label.svg" alt="koenigsberg_label.svg" class="org-svg" width="70%" />
</p>
</div>

<p>
And the <a href="https://graphviz.org/Gallery/directed/fsm.html">finite state machine example from the Graphviz gallery</a>:
</p>


<div id="org449cde1" class="figure">
<p><img src="https://remcycles.net/blog/../images/fsm.svg" alt="fsm.svg" class="org-svg" width="70%" />
</p>
</div>

<div id="orgf6b96a9" class="figure">
<p><img src="https://remcycles.net/blog/../images/fsm_label.svg" alt="fsm_label.svg" class="org-svg" width="70%" />
</p>
</div>

<p>
Here's the source code:
</p>

<p>
<a href="https://remcycles.net/blog/../files/label_box.gvpr">label<sub>box.gvpr</sub></a>:
</p>
<div class="org-src-container">
<pre class="src src-c"><span style="color: #add8e6;">/*</span>
<span style="color: #add8e6;">  Copyright (C) 2025 Remington Furman</span>

<span style="color: #add8e6;">  Permission is hereby granted, free of charge, to any person</span>
<span style="color: #add8e6;">  obtaining a copy of this software and associated documentation files</span>
<span style="color: #add8e6;">  (the "Software"), to deal in the Software without restriction,</span>
<span style="color: #add8e6;">  including without limitation the rights to use, copy, modify, merge,</span>
<span style="color: #add8e6;">  publish, distribute, sublicense, and/or sell copies of the Software,</span>
<span style="color: #add8e6;">  and to permit persons to whom the Software is furnished to do so,</span>
<span style="color: #add8e6;">  subject to the following conditions:</span>

<span style="color: #add8e6;">  The above copyright notice and this permission notice shall be</span>
<span style="color: #add8e6;">  included in all copies or substantial portions of the Software.</span>

<span style="color: #add8e6;">  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,</span>
<span style="color: #add8e6;">  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF</span>
<span style="color: #add8e6;">  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND</span>
<span style="color: #add8e6;">  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS</span>
<span style="color: #add8e6;">  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN</span>
<span style="color: #add8e6;">  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN</span>
<span style="color: #add8e6;">  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE</span>
<span style="color: #add8e6;">  SOFTWARE.</span>

<span style="color: #add8e6;">  Replace edge labels with rectangular nodes that contain the label</span>
<span style="color: #add8e6;">  text.</span>

<span style="color: #add8e6;">  Inspired by:</span>
<span style="color: #add8e6;">  https://forum.graphviz.org/t/how-to-tell-dot-to-put-the-edge-label-in-a-box/1578/8</span>
<span style="color: #add8e6;">  and:</span>
<span style="color: #add8e6;">  https://www.exchangetuts.com/how-can-i-reverse-the-direction-of-every-edge-in-a-graphviz-dot-language-graph-1640404624170374</span>
<span style="color: #add8e6;">*/</span>

BEG_G {
  <span style="color: #9acd32; font-weight: bold;">string</span> <span style="color: #7fffd4; font-weight: bold;">nodeName</span>, <span style="color: #7fffd4; font-weight: bold;">prefix</span>=<span style="color: #ffa07a;">"__LabelNode_"</span>;
  <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">I</span>=0;
  <span style="color: #9acd32; font-weight: bold;">node_t</span> <span style="color: #7fffd4; font-weight: bold;">labelNode</span>;
  <span style="color: #9acd32; font-weight: bold;">edge_t</span> <span style="color: #7fffd4; font-weight: bold;">begEdge</span>;
  <span style="color: #9acd32; font-weight: bold;">edge_t</span> <span style="color: #7fffd4; font-weight: bold;">endEdge</span>;
  $O = graph($.name + <span style="color: #ffa07a;">"_box"</span>, <span style="color: #ffa07a;">"D"</span>);
  copyA($G, $O);
}

N {
  clone($O, $);
}

E {
  <span style="color: #fa8072;">if</span> (hasAttr($,<span style="color: #ffa07a;">"label"</span>)){
    I++;
    printf(<span style="color: #ffa07a;">"edge %d, %s\n"</span>, I, $.label);
    nodeName = prefix+(<span style="color: #9acd32; font-weight: bold;">string</span>)I;
    labelNode = node($O,nodeName);
    labelNode.label = $.label;
    labelNode.shape=<span style="color: #ffa07a;">"rect"</span>;
    begEdge = edge_sg($O, clone($O, $.tail), labelNode, <span style="color: #ffa07a;">""</span>);
    endEdge = edge_sg($O, labelNode, clone($O, $.head), <span style="color: #ffa07a;">""</span>);
    <span style="color: #fa8072;">switch</span> ($.dir) {
      <span style="color: #fa8072;">default</span>:
      <span style="color: #fa8072;">case</span> <span style="color: #ffa07a;">"forward"</span>: {
        begEdge.dir = <span style="color: #ffa07a;">"none"</span>;
        endEdge.dir = <span style="color: #ffa07a;">"forward"</span>;
        <span style="color: #fa8072;">break</span>;
      }
      <span style="color: #fa8072;">case</span> <span style="color: #ffa07a;">"back"</span>: {
        begEdge.dir = <span style="color: #ffa07a;">"back"</span>;
        endEdge.dir = <span style="color: #ffa07a;">"none"</span>;
        <span style="color: #fa8072;">break</span>;
      }
      <span style="color: #fa8072;">case</span> <span style="color: #ffa07a;">"both"</span>: {
        begEdge.dir = <span style="color: #ffa07a;">"back"</span>;
        endEdge.dir = <span style="color: #ffa07a;">"forward"</span>;
        <span style="color: #fa8072;">break</span>;
      }
      <span style="color: #fa8072;">case</span> <span style="color: #ffa07a;">"none"</span>: {
        begEdge.dir = <span style="color: #ffa07a;">"none"</span>;
        endEdge.dir = <span style="color: #ffa07a;">"none"</span>;
        <span style="color: #fa8072;">break</span>;
      }
    }
  } <span style="color: #fa8072;">else</span> {
    copy($O, $);
  }
}

END {
  printf(<span style="color: #ffa07a;">"done.\n"</span>)
}
</pre>
</div>

<p>
And a Makefile for using it:
</p>
<div class="org-src-container">
<pre class="src src-makefile"><span style="color: #7fffd4; font-weight: bold;">DOTS</span>=$(<span style="color: #7fffd4; font-weight: bold;">wildcard</span> *.dot)

<span style="color: #7fffd4; font-weight: bold;">SVGS</span>=$(<span style="color: #7fffd4; font-weight: bold;">patsubst</span> %.dot,%.svg,$(<span style="color: #7fffd4; font-weight: bold;">DOTS</span>))
<span style="color: #7fffd4; font-weight: bold;">LABELED_SVGS</span>=$(<span style="color: #7fffd4; font-weight: bold;">patsubst</span> %.dot,%_label.svg,$(<span style="color: #7fffd4; font-weight: bold;">DOTS</span>))
<span style="color: #7fffd4; font-weight: bold;">PNGS</span>=$(<span style="color: #7fffd4; font-weight: bold;">patsubst</span> %.dot,%.png,$(<span style="color: #7fffd4; font-weight: bold;">DOTS</span>))
<span style="color: #7fffd4; font-weight: bold;">LABELED_PNGS</span>=$(<span style="color: #7fffd4; font-weight: bold;">patsubst</span> %.dot,%_label.png,$(<span style="color: #7fffd4; font-weight: bold;">DOTS</span>))

<span style="color: #7fffd4; font-weight: bold;">all</span>: $(<span style="color: #7fffd4; font-weight: bold;">SVGS</span>) $(<span style="color: #7fffd4; font-weight: bold;">LABELED_SVGS</span>) $(<span style="color: #7fffd4; font-weight: bold;">PNGS</span>) $(<span style="color: #7fffd4; font-weight: bold;">LABELED_PNGS</span>)

<span style="color: #7fffd4; font-weight: bold;">%.svg</span>: %.dot
        dot -Tsvg $<span style="color: #7fffd4;">&lt;</span> &gt; <span style="color: #7fffd4; font-weight: bold;">$</span><span style="color: #7fffd4; font-weight: bold;">@</span>

<span style="color: #7fffd4; font-weight: bold;">%.png</span>: %.dot
        dot -Tpng $<span style="color: #7fffd4;">&lt;</span> &gt; <span style="color: #7fffd4; font-weight: bold;">$</span><span style="color: #7fffd4; font-weight: bold;">@</span>

<span style="color: #7fffd4; font-weight: bold;">%_label.dot</span>: %.dot label_box.gvpr
        gvpr -o <span style="color: #7fffd4; font-weight: bold;">$</span><span style="color: #7fffd4; font-weight: bold;">@</span> -f label_box.gvpr $<span style="color: #7fffd4;">&lt;</span>
</pre>
</div>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>A Fixed-Point Implementation of the Goertzel Algorithm in C</title>
<link>https://remcycles.net/blog/goertzel.html</link>
<pubDate>Wed, 26 Oct 2022 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/goertzel.html</guid>
<description>
<![CDATA[<p>
This is a practice project I did at the end of 2020. It's very on
theme with the "Remcycles" moniker of this blog, because it's about a
single tone detection algorithm, which detects "cycles" in a signal
that occur at a specific frequency.
</p>

<p>
The <a href="https://en.wikipedia.org/wiki/Goertzel_algorithm">Goertzel algorithm</a> is a digital signal processing technique for
calculating a single bin of a <a href="https://en.wikipedia.org/wiki/Discrete_Fourier_transform">DFT</a>/<a href="https://en.wikipedia.org/wiki/Fast_Fourier_transform">FFT</a>.  It's useful when you want to
detect and measure the strength of a signal at just one or a few
frequencies and don't need to calculate the signal strength at all the
frequencies that an FFT would calculate.  Possible use cases include
decoding DTMF signals and demodulating on-off-keying or frequency
shift keying signals.
</p>

<p>
I first read about it in this wonderful book by Richard Lyons:
</p>

<p>
<a href="https://www.powells.com/book/understanding-digital-signal-processing-9780137027415">Understanding Digital Signal Processing 3rd Edition</a>
</p>

<p>
Lyons' book includes the following diagram, redrawn here using <a href="https://pikchr.org/home/doc/trunk/homepage.md">Pikchr</a>
and included via <a href="https://github.com/kljohann/pikchr-mode">pikchr-mode</a> (<a href="https://remcycles.net/blog/../files/goertzel.pikchr">source code</a>):
</p>

<div id="org7db337f" class="figure">
<p><img src="https://remcycles.net/blog/../images/goertzel.svg" alt="goertzel.svg" class="org-svg" />
</p>
</div>

<p>
The structure above is a resonant filter.  It's transfer function has
a pole and zero that cancel each other, leaving a single pole on the
unit circle: \[H(z) = \frac{(1 - e^{-j 2 \pi m/N}z^{-1})}{(1 - e^{+j 2
\pi m/N} z^{-1})(1 - e^{-j 2 \pi m/N} z^{-1})} = \frac{1}{1 - e^{+j 2
\pi m/N}}\]
</p>

<p>
That's a recipe for instability, but part of the Goertzel algorithm
trick is to only run the filter for a fixed number of input samples
before computing the final output, and then resetting the filter's
state for the next set of samples.
</p>

<p>
The following time-domain difference equations are the core of the
algorithm and show how to calculate new values from previous values:
\[w(n) = 2 cos(2 \pi m / N) w(n-1)-w(n-2) +x(n)\]
\[y(n) = w(n) - e^{-j 2 \pi m / N} w(n-1)\]
</p>

<p>
The \(2 cos(2 \pi m / N)\) and \(e^{-j 2 \pi m / N}\) terms are constants
that can be calculated once at run time (or even compile time), and
\(y(n)\) only needs to be evaluated once at the end of each computation,
after N+1 iterations of the main loop.  Each iteration is only one
multiplication and two additions.
</p>

<p>
I implemented this using floating-point math for practice first, but
my goal was to write a fixed-point implementation that can run on
microcontrollers or a DSP like the <a href="https://www.analog.com/en/design-center/evaluation-hardware-and-software/evaluation-boards-kits/eval-bf706-mini.html">ADSP-BF706</a> without an FPU.
</p>

<p>
The two tricky parts of fixed-point programming are keeping the binary
points aligned before and after operations and avoiding overflow.
Randy Yates wrote two great guides on fixed-point math and signal
processing that I highly recommend:
</p>

<p>
<a href="http://www.digitalsignallabs.com/downloads/fp.pdf">Fixed-Point Arithmetic: An Introduction</a>
</p>

<p>
<a href="http://www.digitalsignallabs.com/downloads/fir.pdf">Practical Considerations in Fixed-Point FIR Implementations</a>
</p>

<p>
There is also this helpful Wikipedia page on the different notations
for fixed point numbers:
</p>

<p>
<a href="https://en.wikipedia.org/wiki/Q_(number_format)">https://en.wikipedia.org/wiki/Q_(number_format)</a>
</p>

<p>
My full test program used <a href="http://portaudio.com/">PortAudio</a> for input and I used my system's
audio mixer to route audio to it.  The signal source was a simple
direct digital synthesis (DDS) program that I wrote.
</p>

<p>
Here's a simplified version:
</p>

<div class="org-src-container">
<pre class="src src-c"><span style="color: #add8e6;">/* </span><span style="color: #add8e6;">goertzel_fixed -- Detect a single tone in an audio signal.</span>
<span style="color: #add8e6;">   Copyright (C) 2022 Remington Furman</span>
<span style="color: #add8e6;">   This program is free software: you can redistribute it and/or modify</span>
<span style="color: #add8e6;">   it under the terms of the GNU General Public License as published by</span>
<span style="color: #add8e6;">   the Free Software Foundation, either version 3 of the License, or</span>
<span style="color: #add8e6;">   (at your option) any later version.</span>
<span style="color: #add8e6;">   This program is distributed in the hope that it will be useful,</span>
<span style="color: #add8e6;">   but WITHOUT ANY WARRANTY; without even the implied warranty of</span>
<span style="color: #add8e6;">   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span>
<span style="color: #add8e6;">   GNU General Public License for more details.</span>
<span style="color: #add8e6;">   You should have received a copy of the GNU General Public License</span>
<span style="color: #add8e6;">   along with this program.  If not, see https://www.gnu.org/licenses/.</span>
<span style="color: #add8e6;">*/</span>

<span style="color: #fa8072;">#include</span> <span style="color: #ffa07a;">&lt;stdio.h&gt;</span>
<span style="color: #fa8072;">#include</span> <span style="color: #ffa07a;">&lt;stdlib.h&gt;</span>
<span style="color: #fa8072;">#include</span> <span style="color: #ffa07a;">&lt;stdint.h&gt;</span>
<span style="color: #fa8072;">#include</span> <span style="color: #ffa07a;">&lt;math.h&gt;</span>
<span style="color: #fa8072;">#include</span> <span style="color: #ffa07a;">&lt;complex.h&gt;</span>

<span style="color: #add8e6;">/* </span><span style="color: #add8e6;">These macros simplify working with signed fixed point numbers.</span>

<span style="color: #add8e6;">   In this notation, only the fractional bits are tracked in the macro</span>
<span style="color: #add8e6;">   names, so a Qm.n number is referred to as a Qn number, where n is</span>
<span style="color: #add8e6;">   the number of fractional bits.  This also sidesteps the issue of</span>
<span style="color: #add8e6;">   whether m includes the sign bit or not (ARM vs TI notation).</span>

<span style="color: #add8e6;">   The usual caveats of C preprocessor macros hold here.  Beware of</span>
<span style="color: #add8e6;">   multiple evaluations, side effects, etc.</span>
<span style="color: #add8e6;">*/</span>

<span style="color: #add8e6;">/* </span><span style="color: #add8e6;">Convert to and from doubles.</span><span style="color: #add8e6;"> */</span>
<span style="color: #fa8072;">#define</span> <span style="color: #7fffd4; font-weight: bold;">Qn_FROM_DOUBLE</span>(<span style="color: #7fffd4; font-weight: bold;">value</span>, <span style="color: #7fffd4; font-weight: bold;">n</span>) (lrint((value) * (1 &lt;&lt; (n))))
<span style="color: #fa8072;">#define</span> <span style="color: #7fffd4; font-weight: bold;">DOUBLE_FROM_Qn</span>(<span style="color: #7fffd4; font-weight: bold;">value</span>, <span style="color: #7fffd4; font-weight: bold;">n</span>) ((<span style="color: #9acd32; font-weight: bold;">double</span>)(value) / (1 &lt;&lt; (n)))

<span style="color: #add8e6;">/* </span><span style="color: #add8e6;">The number closest to +1.0 that can be represented.</span><span style="color: #add8e6;"> */</span>
<span style="color: #fa8072;">#define</span> <span style="color: #7fffd4; font-weight: bold;">ONE_Qn</span>(<span style="color: #7fffd4; font-weight: bold;">n</span>) ((1&lt;&lt;(n)) - 1)
<span style="color: #add8e6;">/* </span><span style="color: #add8e6;">One half (0.5).</span><span style="color: #add8e6;"> */</span>
<span style="color: #fa8072;">#define</span> <span style="color: #7fffd4; font-weight: bold;">HALF_Qn</span>(<span style="color: #7fffd4; font-weight: bold;">n</span>) (1&lt;&lt;((n) - 1))

<span style="color: #add8e6;">/* </span><span style="color: #add8e6;">Drop n bits from x (shift right) while rounding (add one half).</span><span style="color: #add8e6;"> */</span>
<span style="color: #fa8072;">#define</span> <span style="color: #7fffd4; font-weight: bold;">ROUND_OFF_Qn</span>(<span style="color: #7fffd4; font-weight: bold;">x</span>, <span style="color: #7fffd4; font-weight: bold;">n</span>)                      \
    ((n &gt; 0) ? (((x) + HALF_Qn(n)) &gt;&gt; n) : (x))

<span style="color: #add8e6;">/* </span><span style="color: #add8e6;">Multiply two Qn numbers, rounding to the precision of the first.</span>
<span style="color: #add8e6;">   Make sure to cast one of the arguments to the size needed to avoid</span>
<span style="color: #add8e6;">   overflow in the multiplication before shifting.</span><span style="color: #add8e6;"> */</span>
<span style="color: #fa8072;">#define</span> <span style="color: #7fffd4; font-weight: bold;">MUL_Qn_Qn</span>(<span style="color: #7fffd4; font-weight: bold;">x</span>, <span style="color: #7fffd4; font-weight: bold;">y</span>, <span style="color: #7fffd4; font-weight: bold;">xn</span>, <span style="color: #7fffd4; font-weight: bold;">yn</span>)                 \
    ROUND_OFF_Qn((x) * (y), (yn))

<span style="color: #add8e6;">/* </span><span style="color: #add8e6;">Add two Qn numbers, using the precision of the first.</span><span style="color: #add8e6;"> */</span>
<span style="color: #fa8072;">#define</span> <span style="color: #7fffd4; font-weight: bold;">ADD_Qn_Qn</span>(<span style="color: #7fffd4; font-weight: bold;">x</span>, <span style="color: #7fffd4; font-weight: bold;">y</span>, <span style="color: #7fffd4; font-weight: bold;">xn</span>, <span style="color: #7fffd4; font-weight: bold;">yn</span>)                 \
    ((xn) &gt; (yn) ? (x) + ((y) &lt;&lt; ((xn)-(yn))) : \
     (x) + ROUND_OFF_Qn((y), ((xn)-(yn))))

<span style="color: #fa8072;">typedef</span> <span style="color: #fa8072;">struct</span> {
    <span style="color: #9acd32; font-weight: bold;">int16_t</span> <span style="color: #7fffd4; font-weight: bold;">real</span>;
    <span style="color: #9acd32; font-weight: bold;">int16_t</span> <span style="color: #7fffd4; font-weight: bold;">imag</span>;
} <span style="color: #9acd32; font-weight: bold;">cint16_t</span>;

<span style="color: #add8e6;">/* </span><span style="color: #add8e6;">Return a larger type here, because a complex point outside of the</span>
<span style="color: #add8e6;">   unit circle will have a larger magnitude.</span><span style="color: #add8e6;"> */</span>
<span style="color: #9acd32; font-weight: bold;">int32_t</span> <span style="color: #7fffd4; font-weight: bold;">cint16_abs</span>(<span style="color: #9acd32; font-weight: bold;">cint16_t</span> <span style="color: #7fffd4; font-weight: bold;">z</span>) {
    <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">Cheat for now and use floating point sqrt().</span><span style="color: #add8e6;"> */</span>
    <span style="color: #fa8072;">return</span> lrint(sqrt((<span style="color: #9acd32; font-weight: bold;">double</span>)z.real*(<span style="color: #9acd32; font-weight: bold;">double</span>)z.real +
                      (<span style="color: #9acd32; font-weight: bold;">double</span>)z.imag*(<span style="color: #9acd32; font-weight: bold;">double</span>)z.imag));
}

<span style="color: #9acd32; font-weight: bold;">int16_t</span> <span style="color: #7fffd4; font-weight: bold;">read_sample</span>(<span style="color: #9acd32; font-weight: bold;">void</span>) {
    <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">This function should read and return an audio sample from some</span>
<span style="color: #add8e6;">       source.</span><span style="color: #add8e6;"> */</span>
    <span style="color: #fa8072;">return</span> 0;
}

<span style="color: #9acd32; font-weight: bold;">int32_t</span> <span style="color: #7fffd4; font-weight: bold;">goertzel</span>(<span style="color: #9acd32; font-weight: bold;">double</span> <span style="color: #7fffd4; font-weight: bold;">detect_hz</span>, <span style="color: #9acd32; font-weight: bold;">double</span> <span style="color: #7fffd4; font-weight: bold;">sample_rate_hz</span>, <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">N</span>) {
    <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">Notation from p. 710 of Lyons.</span><span style="color: #add8e6;"> */</span>

    <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">Index of DFT frequency bin to calculate.</span><span style="color: #add8e6;"> */</span>
    <span style="color: #fa8072;">const</span> <span style="color: #9acd32; font-weight: bold;">double</span> <span style="color: #7fffd4; font-weight: bold;">m</span> = (N * detect_hz) / sample_rate_hz;

    <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">This complex feedforward coefficient allows a single zero to</span>
<span style="color: #add8e6;">       cancel one of the complex poles.  It can be calculated in</span>
<span style="color: #add8e6;">       advance.</span><span style="color: #add8e6;"> */</span>
    <span style="color: #fa8072;">const</span> <span style="color: #9acd32; font-weight: bold;">double</span> <span style="color: #7fffd4; font-weight: bold;">complex</span> dbl_coeff_ff = -cexp(-I*2*M_PI*m/N);

    <span style="color: #fa8072;">const</span> <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">coeff_ff_Qn</span> = 15;  <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">Q1.15</span><span style="color: #add8e6;"> */</span>
    <span style="color: #9acd32; font-weight: bold;">cint16_t</span> <span style="color: #7fffd4; font-weight: bold;">coeff_ff</span>;
    coeff_ff.real = Qn_FROM_DOUBLE(creal(dbl_coeff_ff), coeff_ff_Qn);
    coeff_ff.imag = Qn_FROM_DOUBLE(cimag(dbl_coeff_ff), coeff_ff_Qn);

    <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">Feedback coefficient.</span><span style="color: #add8e6;"> */</span>
    <span style="color: #9acd32; font-weight: bold;">double</span> <span style="color: #7fffd4; font-weight: bold;">dbl_coeff_fb</span> = 2*cos(2*M_PI*m/N);
    <span style="color: #fa8072;">const</span> <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">coeff_fb_Qn</span> = 14;  <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">Q2.14</span><span style="color: #add8e6;"> */</span>
    <span style="color: #9acd32; font-weight: bold;">int16_t</span> <span style="color: #7fffd4; font-weight: bold;">coeff_fb</span> = Qn_FROM_DOUBLE(dbl_coeff_fb, coeff_fb_Qn);

    <span style="color: #fa8072;">const</span> <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">w_Qn</span> = 15;
    <span style="color: #9acd32; font-weight: bold;">int32_t</span> <span style="color: #7fffd4; font-weight: bold;">w</span>[3] = {0};         <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">Delay line. Q17.15.</span><span style="color: #add8e6;"> */</span>

    <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">sample_index</span> = 0;

    <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">Read and process N+1 samples.</span><span style="color: #add8e6;"> */</span>
    <span style="color: #fa8072;">while</span> (1) {
        <span style="color: #fa8072;">const</span> <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">x_Qn</span> = 15;  <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">Q1.15.</span><span style="color: #add8e6;"> */</span>
        <span style="color: #9acd32; font-weight: bold;">int16_t</span> <span style="color: #7fffd4; font-weight: bold;">x</span> = read_sample();

        <span style="color: #fa8072;">if</span> (sample_index == N) {
            <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">The final x input sample should be forced to zero.</span><span style="color: #add8e6;"> */</span>
            x = 0;
        }

        <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">Manually shift delay line and calculate next value.</span><span style="color: #add8e6;"> */</span>
        w[2] = w[1];
        w[1] = w[0];

        <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">w[0] = x + (coeff_fb * w[1]) - w[2]</span><span style="color: #add8e6;"> */</span>
        w[0] = MUL_Qn_Qn((<span style="color: #9acd32; font-weight: bold;">int64_t</span>)w[1], (<span style="color: #9acd32; font-weight: bold;">int64_t</span>)coeff_fb, w_Qn, coeff_fb_Qn);
        w[0] = ADD_Qn_Qn(w[0], x, w_Qn, x_Qn);
        w[0] = ADD_Qn_Qn(w[0], -w[2], w_Qn, w_Qn);

        <span style="color: #fa8072;">if</span> (sample_index++ == N) {
            <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">End of Goertzel alogorithm for this buffer. Apply the</span>
<span style="color: #add8e6;">             * feedforward coefficient to generate final output.</span><span style="color: #add8e6;"> */</span>
            <span style="color: #fa8072;">const</span> <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">y_Qn</span> = 5;
            <span style="color: #9acd32; font-weight: bold;">cint16_t</span> <span style="color: #7fffd4; font-weight: bold;">y</span>; <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">y = w[0] + coeff_ff * w[1];  complex multiply.</span><span style="color: #add8e6;"> */</span>
            y.real = ROUND_OFF_Qn(w[0] +
                                  MUL_Qn_Qn((<span style="color: #9acd32; font-weight: bold;">int64_t</span>)coeff_ff.real, w[1],
                                            coeff_ff_Qn, w_Qn), w_Qn - y_Qn);
            y.imag = ROUND_OFF_Qn(
                MUL_Qn_Qn((<span style="color: #9acd32; font-weight: bold;">int64_t</span>)coeff_ff.imag, w[1],
                          coeff_ff_Qn, w_Qn), w_Qn - y_Qn);

            <span style="color: #9acd32; font-weight: bold;">int32_t</span> <span style="color: #7fffd4; font-weight: bold;">dft_mag</span> = cint16_abs(y);

            <span style="color: #fa8072;">return</span> dft_mag;
        }
    }
}

<span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">main</span>(<span style="color: #9acd32; font-weight: bold;">void</span>) {
    <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">Input sample rate.</span><span style="color: #add8e6;"> */</span>
    <span style="color: #fa8072;">const</span> <span style="color: #9acd32; font-weight: bold;">double</span> <span style="color: #7fffd4; font-weight: bold;">sample_rate_hz</span> = 48000.0;

    <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">Frequency of DFT bin to calculate.</span><span style="color: #add8e6;"> */</span>
    <span style="color: #fa8072;">const</span> <span style="color: #9acd32; font-weight: bold;">double</span> <span style="color: #7fffd4; font-weight: bold;">detect_hz</span> = 440.0;

    <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">Number of samples for detection.  Need not be a power of 2.</span><span style="color: #add8e6;"> */</span>
    <span style="color: #fa8072;">const</span> <span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">N</span> = 1024;

    <span style="color: #fa8072;">while</span>(1) {
        <span style="color: #9acd32; font-weight: bold;">int32_t</span> <span style="color: #7fffd4; font-weight: bold;">dft_mag</span> = goertzel(detect_hz, sample_rate_hz, N);

        <span style="color: #add8e6;">/* </span><span style="color: #add8e6;">Normalize the DFT bin value by N.  A maximum amplitude</span>
<span style="color: #add8e6;">           signal at the detection frequency should give a value</span>
<span style="color: #add8e6;">           of 1/2.</span><span style="color: #add8e6;"> */</span>
        <span style="color: #9acd32; font-weight: bold;">double</span> <span style="color: #7fffd4; font-weight: bold;">dft_mag_norm</span> = dft_mag/N;
        printf(<span style="color: #ffa07a;">"dft_mag: %u, dft_mag_norm: %g\n"</span>, dft_mag, dft_mag_norm);
    }
}
</pre>
</div>

<p>
The following plots show the internal signals during each sample,
with the final filter state on the right of each plot.
</p>

<p>
The yellow \(|y|\) trace is the output, the magnitude of the DFT bin,
though it's poorly scaled to see relative to the other signals.  The
purple \(x\) trace shows the input signal scaled up to be more visible.
The other traces are the internal filter state \(w\) values.
</p>

<p>
The filter is configured to detect a 440Hz tone, and the input signals
are 440Hz, 500Hz, and 880Hz.
</p>


<div id="orga803bed" class="figure">
<p><img src="https://remcycles.net/blog/../images/goertzel_float_440.png" alt="goertzel_float_440.png" />
</p>
<p><span class="figure-number">Figure 1: </span>Goertzel state with 440Hz input</p>
</div>

<p>
At 440Hz the input frequency matches the detection frequency and you
can see that the internal filter state grows very quickly.  It would
continue to grow if the filter was run forever.  The \(|y|\) trace
steadily increases (again, hard to see with this scale).
</p>


<div id="org2c9bdab" class="figure">
<p><img src="https://remcycles.net/blog/../images/goertzel_float_500.png" alt="goertzel_float_500.png" />
</p>
<p><span class="figure-number">Figure 2: </span>Goertzel state with 500Hz input</p>
</div>

<p>
At 500Hz input the filter state's magnitude oscillates, but never
grows to a large value.
</p>


<div id="org68d6583" class="figure">
<p><img src="https://remcycles.net/blog/../images/goertzel_float_880.png" alt="goertzel_float_880.png" />
</p>
<p><span class="figure-number">Figure 3: </span>Goertzel state with 880Hz input</p>
</div>

<p>
At 880Hz it also oscillates, but at a much smaller magnitude.
</p>


<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Annotating Images with GIMP (aka Making Memes)</title>
<link>https://remcycles.net/blog/gimp_annotations.html</link>
<pubDate>Thu, 14 Sep 2023 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/gimp_annotations.html</guid>
<description>
<![CDATA[<style>
.figure-number {
    display: none;
}
</style>

<p>
Somewhat often I need to label parts of an image to document something
about an electrical design.  Simply putting lines and text over a
visually complicated image like a schematic, PCB layout, or picture
doesn't work well because it can be hard to trace a line or read text
when the background colors are changing.  Adding a border around the
label helps make it more readable.
</p>

<p>
Unfortunately, my preferred image editor, GIMP, does not have a
feature to do this quickly or automatically.  Fortunately, it does
have a scripting interface so I can add it myself.  Even more fun, it
uses Scheme (or Python), so it's another chance to use Lisp.
</p>

<p>
Here's an example of creating a very simple wiring diagram:
</p>

<div id="orgecfba6a" class="figure">
<p><a href="https://remcycles.net/blog/../images/pico_uarts_meme_it.png"><img src="https://remcycles.net/blog/../images/pico_uarts_meme_it.png" alt="pico_uarts_meme_it.png" /></a>
</p>
<p><span class="figure-number">Figure 1: </span>Pico UART connections (Source image: Raspberry Pi Ltd)</p>
</div>

<p>
When a text layer is selected, the "Script-Fu: Meme It" dialog will
create a layer underneath the text, stroke the text outline with the
current background color, and then by default merge the two layers.
</p>

<p>
If if a text layer is not selected and there is an active selection,
then it will stroke the selection twice, first with the background
color at twice the desired width, then with the foreground color with
the desired width.
</p>

<p>
Finally, if a text layer is not selected and a path is selected, then
it will stroke the path twice, first with the background color at
twice the desired width, then with the foreground color with the
desired width.  (Maybe this logic should be re-ordered to always favor
a selection first.)
</p>

<p>
It took a few hours to learn how to work with the GIMP <a href="https://docs.gimp.org/2.10/en/gimp-using-script-fu-tutorial-first-script.html">Scheme API</a>.
The examples helped, and hopefully this script will provide another
helpful example.
</p>

<p>
<a href="https://remcycles.net/blog/../files/meme_it.scm">meme<sub>it.scm</sub></a>:
</p>
<div class="org-src-container">
<pre class="src src-scheme"><span style="color: #add8e6;">; </span><span style="color: #add8e6;">Meme It</span>
<span style="color: #add8e6;">; </span><span style="color: #add8e6;">Copyright (C) 2023 Remington Furman</span>
<span style="color: #add8e6;">;</span>
<span style="color: #add8e6;">; </span><span style="color: #add8e6;">This program is free software: you can redistribute it and/or modify</span>
<span style="color: #add8e6;">; </span><span style="color: #add8e6;">it under the terms of the GNU General Public License as published by</span>
<span style="color: #add8e6;">; </span><span style="color: #add8e6;">the Free Software Foundation; either version 3 of the License, or</span>
<span style="color: #add8e6;">; </span><span style="color: #add8e6;">(at your option) any later version.</span>
<span style="color: #add8e6;">;</span>
<span style="color: #add8e6;">; </span><span style="color: #add8e6;">This program is distributed in the hope that it will be useful,</span>
<span style="color: #add8e6;">; </span><span style="color: #add8e6;">but WITHOUT ANY WARRANTY; without even the implied warranty of</span>
<span style="color: #add8e6;">; </span><span style="color: #add8e6;">MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span>
<span style="color: #add8e6;">; </span><span style="color: #add8e6;">GNU General Public License for more details.</span>
<span style="color: #add8e6;">;</span>
<span style="color: #add8e6;">; </span><span style="color: #add8e6;">You should have received a copy of the GNU General Public License</span>
<span style="color: #add8e6;">; </span><span style="color: #add8e6;">along with this program.  If not, see <a href="https://www.gnu.org/licenses/">&lt;https://www.gnu.org/licenses/&gt;</a>.</span>
<span style="color: #add8e6;">;</span>
<span style="color: #add8e6;">;</span>
<span style="color: #add8e6;">; </span><span style="color: #add8e6;">Adds a border beneath the current text layer, selection, or active</span>
<span style="color: #add8e6;">; </span><span style="color: #add8e6;">path as a layer below the active layer.</span>
<span style="color: #add8e6;">;</span>


(<span style="color: #fa8072;">define</span> (<span style="color: #7fffd4; font-weight: bold;">duplicate-layer-under</span> image drawable)
  (<span style="color: #fa8072;">let*</span> ((pos (car (gimp-image-get-item-position image drawable)))
         (parent (car (gimp-item-get-parent drawable)))
         (layer-copy (car (gimp-layer-copy drawable TRUE))))
    (gimp-image-insert-layer image layer-copy parent (+ pos 1))
    layer-copy))


(<span style="color: #fa8072;">define</span> (<span style="color: #7fffd4; font-weight: bold;">gimp-true</span> gimp-pred)
  (= (car gimp-pred) TRUE))


(<span style="color: #fa8072;">define</span> (<span style="color: #7fffd4; font-weight: bold;">script-fu-meme-it</span> image drawable width merge)
  (gimp-image-undo-group-start image)
  (gimp-context-push)

  (gimp-context-swap-colors)
  (gimp-context-set-opacity 100.0)
  (gimp-context-set-stroke-method STROKE-LINE)
  (gimp-context-set-line-width width)
  (gimp-context-set-line-cap-style CAP-ROUND)
  (gimp-context-set-antialias TRUE)

  <span style="color: #add8e6;">;; </span><span style="color: #add8e6;">Draw a new layer under the text layer.</span>
  (<span style="color: #fa8072;">if</span> (gimp-true (gimp-item-is-text-layer drawable))
      (<span style="color: #fa8072;">let*</span> ((text-copy (duplicate-layer-under image drawable))
             (text-vectors (car (gimp-vectors-new-from-text-layer image drawable))))
        (gimp-image-insert-vectors image text-vectors 0 0)
        (gimp-text-layer-set-color text-copy (car (gimp-context-get-foreground)))
        (gimp-layer-resize-to-image-size text-copy)
        (gimp-edit-stroke-vectors text-copy text-vectors)
        (gimp-image-remove-vectors image text-vectors)
        (gimp-selection-none image)
        (plug-in-autocrop-layer RUN-NONINTERACTIVE image text-copy)
        (<span style="color: #fa8072;">if</span> (= merge TRUE)
            (gimp-image-merge-down image drawable EXPAND-AS-NECESSARY)))
      <span style="color: #add8e6;">;; </span><span style="color: #add8e6;">else</span>
      (<span style="color: #fa8072;">if</span> (gimp-true (gimp-selection-is-empty image))
          <span style="color: #add8e6;">;; </span><span style="color: #add8e6;">Stroke the active path twice on the current layer.</span>
          (<span style="color: #fa8072;">let*</span> ((vectors (car (gimp-image-get-active-vectors image))))
            (<span style="color: #fa8072;">if</span> (not (= vectors -1))
                (<span style="color: #fa8072;">begin</span>
                  (gimp-context-set-line-width (* width 2))
                  (gimp-edit-stroke-vectors drawable vectors)

                  (gimp-context-swap-colors)
                  (gimp-context-set-line-width width)
                  (gimp-edit-stroke-vectors drawable vectors))))
          <span style="color: #add8e6;">;; </span><span style="color: #add8e6;">else</span>
          (<span style="color: #fa8072;">begin</span>
            <span style="color: #add8e6;">;; </span><span style="color: #add8e6;">Stroke the selection twice.  This doesn't look as good</span>
            <span style="color: #add8e6;">;; </span><span style="color: #add8e6;">as stroking a path, but there isn't a way to convert</span>
            <span style="color: #add8e6;">;; </span><span style="color: #add8e6;">the selection to a path first.</span>
            (gimp-context-set-line-width (* width 2))
            (gimp-drawable-edit-stroke-selection drawable)

            (gimp-context-swap-colors)
            (gimp-context-set-line-width width)
            (gimp-drawable-edit-stroke-selection drawable))))

  (gimp-displays-flush)                 <span style="color: #add8e6;">; </span><span style="color: #add8e6;">Show this masterpiece.</span>
  (gimp-context-pop)
  (gimp-image-undo-group-end image))


(script-fu-register <span style="color: #ffa07a;">"script-fu-meme-it"</span>
                    <span style="color: #ffa07a;">"M_eme It..."</span>
                    <span style="color: #ffa07a;">"Add a background border to the selected text (or path)"</span>
                    <span style="color: #ffa07a;">"Remington Furman <a href="mailto:remington%40remcycles.net">&lt;remington@remcycles.net&gt;</a>"</span>
                    <span style="color: #ffa07a;">"Remington Furman"</span>
                    <span style="color: #ffa07a;">"2023"</span>
                    <span style="color: #ffa07a;">"RGB*,GRAY*"</span>
                    SF-IMAGE       <span style="color: #ffa07a;">"Image"</span>           0
                    SF-DRAWABLE    <span style="color: #ffa07a;">"Drawable"</span>        0
                    SF-ADJUSTMENT  <span style="color: #ffa07a;">"Stroke Width"</span>    '(5 1 100 1 5 1 0)
                    SF-TOGGLE      <span style="color: #ffa07a;">"Merge layers"</span>    TRUE
                    )


(script-fu-menu-register <span style="color: #ffa07a;">"script-fu-meme-it"</span> <span style="color: #ffa07a;">"&lt;Image&gt;/Filters/Light and Shadow/"</span>)
</pre>
</div>

<p>
Follow <a href="https://docs.gimp.org/2.10/en/install-script-fu.html">the docs</a> to install it.  On my Linux system the user script
path is <code>~/.config/GIMP/2.10/scripts/</code>.
</p>

<p>
You can also make silly memes with it.
<a href="https://remcycles.net/blog/../images/pico_uarts_meme_it.png"><img src="https://remcycles.net/blog/../images/meme_it_demo.png" alt="meme_it_demo.png" /></a>
</p>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Diffing PDFs with GIMP</title>
<link>https://remcycles.net/blog/gimp_pdf_diff.html</link>
<pubDate>Sun, 02 Jun 2024 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/gimp_pdf_diff.html</guid>
<description>
<![CDATA[<style>
.figure-number {
    display: none;
}
</style>

<p>
Here's a simple script to make visually comparing pages of PDF files
easier.  It's particularly useful for comparing revisions of a
schematic.
</p>

<p>
It opens each page of both PDFs as a layer and interleaves them so
that it's easy to change the opacity of the top layer of each pair and
visually see the differences as you drag the opacity slider.
</p>

<p>
Here's an example, where we can see that revA has already swapped the
RX and TX lines of a UART circuit (uh-oh, a classic mistake).
</p>


<div id="org0109ae1" class="figure">
<p><a href="https://remcycles.net/blog/../images/diff_pdfs.gif" width="90%"><img src="https://remcycles.net/blog/../images/diff_pdfs.gif" alt="diff_pdfs.gif" width="90%" /></a>
</p>
<p><span class="figure-number">Figure 1: </span>Animation of changing page opacity</p>
</div>

<p>
In a schematic, crossing wires are not connected unless a "connecting
dot" is drawn at the intersection.  In this example, a small visual
difference that might be hard to notice when comparing PDFs
side-by-side corresponds to a large semantic difference.
</p>


<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>A Simplified Gnuplot Interface</title>
<link>https://remcycles.net/blog/gnuplot.html</link>
<pubDate>Sun, 12 Dec 2021 00:00:00 -0800</pubDate>
<guid>https://remcycles.net/blog/gnuplot.html</guid>
<description>
<![CDATA[<p>
I really like Gnuplot for plotting data, but the user interface has
always felt rather clunky to me.  I love that it's a command line
program, but it doesn't play well with <code>stdin</code> or pipes, which is odd.
The main problem is that Gnuplot only expects the plot parameters in
<code>stdin</code>, and the data to plot must come from files specified within
those plot parameters.  The parameters and data are two different
streams and there isn't a clean way to send data via <code>stdin</code>.  The
result is that you often write a shell script to wrap calls to
Gnuplot, usually with a "here-doc" to set the parameters and the
filenames using string interpolation in the shell.  Examples of such
scripts can be found on <a href="https://unix.stackexchange.com/a/34443">StackExchange</a>.
</p>

<p>
After writing enough of those wrapper scripts, I came up with this
universal wrapper script to simplify the interface and make the common
case of plotting from <code>stdin</code> (or one or more <code>.csv</code> files) very easy.
</p>

<p>
The main idea is that the plot parameters are now passed as command
line arguments and data comes from <code>stdin</code> or files named on the
command line with <code>-f</code>.  The command line arguments for this script
form a stateful mini-language.  Each parameter starts with a useful
default value and the script keeps track of each parameter's value as
it parses the command line.  Each time the <code>-p</code> flag is passed, the
current plot parameters are used to add a new plot line to the graph.
In other words, each <code>-p</code> plot can use different parameters and/or
files, as needed.
</p>

<p>
The most basic invocation simply pipes data to <code>gp_wrap.sh</code>:
</p>
<div class="org-src-container">
<pre class="src src-bash">seq 10 20 | ./gp_wrap.sh
</pre>
</div>
<p>
This will output <code>plot.png</code> with a plot labeled <code>stdin</code>.  The script
acts as if there is an implicit <code>-p</code> here.
</p>

<p>
The next most basic invocation uses only <code>-p</code> to plot columns from a
file:
</p>
<div class="org-src-container">
<pre class="src src-bash">./gp_wrap.sh -f file.csv -p -p -p
</pre>
</div>
<p>
The default x-axis plots against the row numbers in the data file and
the y-axis defaults to column 1.  The <code>-f</code> sets the file that
following plots will use.  Each <code>-p</code> increments the current column in
the plot parameter state, so the above invocation will plot columns 1,
2, and 3 from <code>file.csv</code>.
</p>

<p>
If the plot data starts with a header row, then those values can be
used to automatically label each plot line with the <code>-h</code> option, like
so:
</p>
<div class="org-src-container">
<pre class="src src-bash">./gp_wrap.sh -f file.csv -h -p -p -p
</pre>
</div>

<p>
The entire graph's title can be set with <code>-T title</code>, and the x and y
axes can be labelled with <code>-a x-axis-label</code> and <code>-o y-axis-label</code>,
respectively.
</p>

<p>
The usage notes in the script should make the rest of the options
clear.
</p>

<p>
This isn't a complete replacement for all the features in Gnuplot, of
course, but it does make it easier to make the types of plots I need
most often.
</p>

<p>
<a href="https://remcycles.net/blog/../files/gp_wrap.sh">gp<sub>wrap.sh</sub></a>:
</p>
<div class="org-src-container">
<pre class="src src-bash"><span style="color: #add8e6;">#</span><span style="color: #add8e6;">!/bin/</span><span style="color: #fa8072;">bash</span>

<span style="color: #add8e6;"># </span><span style="color: #add8e6;">gp_wrap.sh simplifies the Gnuplot interface and makes plotting</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">data from CSV files easier.</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Copyright (C) 2021  Remington Furman</span>

<span style="color: #add8e6;"># </span><span style="color: #add8e6;">This program is free software: you can redistribute it and/or modify</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">it under the terms of the GNU General Public License as published by</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">the Free Software Foundation, either version 3 of the License, or</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">(at your option) any later version.</span>

<span style="color: #add8e6;"># </span><span style="color: #add8e6;">This program is distributed in the hope that it will be useful,</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">but WITHOUT ANY WARRANTY; without even the implied warranty of</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">GNU General Public License for more details.</span>

<span style="color: #add8e6;"># </span><span style="color: #add8e6;">You should have received a copy of the GNU General Public License</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">along with this program.  If not, see <a href="https://www.gnu.org/licenses/">&lt;https://www.gnu.org/licenses/&gt;</a>.</span>


<span style="color: #add8e6;"># </span><span style="color: #add8e6;">The command line arguments form a mini language that modify the</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">current state of the plot parameters which are used when the -p</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">(plot) argument is given to add a line to the plot.  By default, the</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">plot parameters will plot the first column of the CSV file with no</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">labels or title, and subsequent plots will plot the next column (-y</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">will increment with each -p).</span>

<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Examples:</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">./gp_wrap.sh -f file.csv -p -p -p      # Plot columns 1, 2, 3 vs row number.</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">./gp_wrap.sh -f file.csv -h -p -p -p   # Same, but use headers from first row.</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">./gp_wrap.sh -h -p -p -p &lt; file.csv    # Same, but read from stdin.</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">./gp_wrap.sh -f file.csv -x 2 -y 3 -p  # Plot col3 vs col2.</span>


<span style="color: #7fffd4; font-weight: bold;">usage</span> () {
    cat &lt;&lt;EOF
<span style="color: #ffff00; font-weight: bold;">Usage:</span>

<span style="color: #ffff00; font-weight: bold;">    -f file    Plot data from File (default: stdin)</span>
<span style="color: #ffff00; font-weight: bold;">    -w file    Write output to file</span>
<span style="color: #ffff00; font-weight: bold;">    -F string  Use 'string' as Field separator (default: ",")</span>
<span style="color: #ffff00; font-weight: bold;">    -x n       Use column 'n' for X coordinates (default: use row number)</span>
<span style="color: #ffff00; font-weight: bold;">    -y n       Use column 'n' for Y coordinates (default: 1)</span>
<span style="color: #ffff00; font-weight: bold;">    -r range   Use Range for x and y axes (default: none)</span>
<span style="color: #ffff00; font-weight: bold;">    -a string  Label x axis (Abscissa) with 'string' (default: none)</span>
<span style="color: #ffff00; font-weight: bold;">    -o string  Label y axis (Ordinate) with 'string' (default: none)</span>
<span style="color: #ffff00; font-weight: bold;">    -t string  Label next plots with 'string' (default: filename)</span>
<span style="color: #ffff00; font-weight: bold;">    -T string  Set Title to 'string' (default: none)</span>
<span style="color: #ffff00; font-weight: bold;">    -s string  Style next plots with 'string' (default: lines)</span>
<span style="color: #ffff00; font-weight: bold;">    -k string  Place plot key at 'string' (default: top left)</span>
<span style="color: #ffff00; font-weight: bold;">    -i         Increment current column after each plot (default)</span>
<span style="color: #ffff00; font-weight: bold;">    -I         Don't Increment current column after each plot</span>
<span style="color: #ffff00; font-weight: bold;">    -m         Format Math in plot titles with TeX (default: off)</span>
<span style="color: #ffff00; font-weight: bold;">    -p         Make a Plot with the current parameters</span>
<span style="color: #ffff00; font-weight: bold;">    -l         List current parameters</span>
<span style="color: #ffff00; font-weight: bold;">    -h         Use first row (Header) as plot labels</span>
<span style="color: #ffff00; font-weight: bold;">    -c string  Add Custom Gnuplot commands to preamble (default: none)</span>
<span style="color: #ffff00; font-weight: bold;">    -u         Display Usage</span>
<span style="color: #ffff00; font-weight: bold;">    -d         Debug (print Gnuplot input)</span>
<span style="color: #ffff00; font-weight: bold;">EOF</span>
}

<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Set default parameters</span>
<span style="color: #7fffd4; font-weight: bold;">STDIN</span>=true                      <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Read from stdin.</span>
<span style="color: #7fffd4; font-weight: bold;">FILE</span>=$(<span style="color: #fa8072;">mktemp -u</span>)
<span style="color: #7fffd4; font-weight: bold;">OUTPUT</span>=<span style="color: #ffa07a;">"./plot.png"</span>
<span style="color: #7fffd4; font-weight: bold;">FIELD_SEP</span>=<span style="color: #ffa07a;">","</span>
<span style="color: #7fffd4; font-weight: bold;">X_COL</span>=
<span style="color: #7fffd4; font-weight: bold;">Y_COL</span>=1
<span style="color: #7fffd4; font-weight: bold;">RANGE</span>=
<span style="color: #7fffd4; font-weight: bold;">X_LABEL</span>=
<span style="color: #7fffd4; font-weight: bold;">Y_LABEL</span>=
<span style="color: #7fffd4; font-weight: bold;">TITLE</span>=
<span style="color: #7fffd4; font-weight: bold;">TITLE_MATH</span>=<span style="color: #ffa07a;">"set key noenhanced"</span>
<span style="color: #7fffd4; font-weight: bold;">STYLE</span>=<span style="color: #ffa07a;">"with lines"</span>
<span style="color: #7fffd4; font-weight: bold;">KEY_LOC</span>=<span style="color: #ffa07a;">"set key left top"</span>
<span style="color: #7fffd4; font-weight: bold;">HEADER</span>=
<span style="color: #7fffd4; font-weight: bold;">INCREMENT</span>=true
<span style="color: #7fffd4; font-weight: bold;">CUSTOM</span>=
<span style="color: #7fffd4; font-weight: bold;">PLOTS</span>=
<span style="color: #7fffd4; font-weight: bold;">DEBUG</span>=

<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Read command line arguments</span>
<span style="color: #7fffd4; font-weight: bold;">optstring</span>=<span style="color: #ffa07a;">"f:w:F:x:y:r:a:o:t:T:s:k:c:iImplhud"</span>
<span style="color: #fa8072;">while </span><span style="color: #98fb98; font-weight: bold;">getopts</span> ${<span style="color: #7fffd4; font-weight: bold;">optstring</span>} arg; <span style="color: #fa8072;">do</span>
    <span style="color: #fa8072;">case</span> ${<span style="color: #7fffd4; font-weight: bold;">arg</span>} <span style="color: #fa8072;">in</span>
        f)
            <span style="color: #7fffd4; font-weight: bold;">FILE</span>=<span style="color: #ffa07a;">"${OPTARG}"</span>
            <span style="color: #7fffd4; font-weight: bold;">STDIN</span>=false
            ;;
        w)
            <span style="color: #7fffd4; font-weight: bold;">OUTPUT</span>=<span style="color: #ffa07a;">"${OPTARG}"</span>
            ;;
        F)
            <span style="color: #7fffd4; font-weight: bold;">FIELD_SEP</span>=<span style="color: #ffa07a;">"${OPTARG}"</span>
            ;;
        x)
            <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Note the trailing : which is necessary for specifying</span>
            <span style="color: #add8e6;"># </span><span style="color: #add8e6;">the x and y coordinates.</span>
            <span style="color: #7fffd4; font-weight: bold;">X_COL</span>=<span style="color: #ffa07a;">"${OPTARG}:"</span>
            ;;
        y)
            <span style="color: #7fffd4; font-weight: bold;">Y_COL</span>=<span style="color: #ffa07a;">"${OPTARG}"</span>
            ;;
        r)
            <span style="color: #7fffd4; font-weight: bold;">RANGE</span>=<span style="color: #ffa07a;">"${OPTARG}"</span>
            ;;
        a)
            <span style="color: #7fffd4; font-weight: bold;">X_LABEL</span>=<span style="color: #ffa07a;">"${OPTARG}"</span>
            ;;
        o)
            <span style="color: #7fffd4; font-weight: bold;">Y_LABEL</span>=<span style="color: #ffa07a;">"${OPTARG}"</span>
            ;;
        t)
            <span style="color: #7fffd4; font-weight: bold;">PLOT_TITLE</span>=<span style="color: #ffa07a;">"title '${OPTARG}'"</span>
            ;;
        T)
            <span style="color: #7fffd4; font-weight: bold;">TITLE</span>=<span style="color: #ffa07a;">"${OPTARG}"</span>
            ;;
        s)
            <span style="color: #7fffd4; font-weight: bold;">STYLE</span>=<span style="color: #ffa07a;">"${OPTARG}"</span>
            ;;
        k)
            <span style="color: #7fffd4; font-weight: bold;">KEY_LOC</span>=<span style="color: #ffa07a;">"set key ${OPTARG}"</span>
            ;;
        i)
            <span style="color: #7fffd4; font-weight: bold;">INCREMENT</span>=true
            ;;
        I)
            <span style="color: #7fffd4; font-weight: bold;">INCREMENT</span>=false
            ;;
        m)
            <span style="color: #7fffd4; font-weight: bold;">TITLE_MATH</span>=<span style="color: #ffa07a;">""</span>
            ;;
        p)
            <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Add a new plot command with current parameters.</span>
            <span style="color: #fa8072;">if</span> [ <span style="color: #ffa07a;">"${STDIN}"</span> = true -a <span style="color: #ffa07a;">\</span>
                 -z <span style="color: #ffa07a;">"${HEADER}"</span> -a    <span style="color: #ffa07a;">\</span>
                 -z <span style="color: #ffa07a;">"${PLOT_TITLE}"</span> ] ; <span style="color: #fa8072;">then</span>
                <span style="color: #7fffd4; font-weight: bold;">PLOT_TITLE</span>=<span style="color: #ffa07a;">"title 'stdin'"</span>
            <span style="color: #fa8072;">fi</span>

            <span style="color: #7fffd4; font-weight: bold;">PLOTS</span>=<span style="color: #ffa07a;">"${PLOTS:+${PLOTS}, }"</span> <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Append comma if plots exist.</span>
            <span style="color: #7fffd4; font-weight: bold;">PLOTS</span>+=<span style="color: #ffa07a;">"'${FILE}' using ${X_COL}${Y_COL} ${STYLE} ${PLOT_TITLE}"</span>

            <span style="color: #fa8072;">if</span> <span style="color: #ffa07a;">"$INCREMENT"</span> = true ; <span style="color: #fa8072;">then</span>
                <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Move to next column.</span>
                <span style="color: #7fffd4; font-weight: bold;">Y_COL</span>=$(<span style="color: #fa8072;">(Y_COL+1</span>))
            <span style="color: #fa8072;">fi</span>
            ;;
        l)
            <span style="color: #98fb98; font-weight: bold;">echo</span> <span style="color: #7fffd4; font-weight: bold;">FILE</span>=<span style="color: #ffa07a;">"$FILE"</span>
            <span style="color: #98fb98; font-weight: bold;">echo</span> <span style="color: #7fffd4; font-weight: bold;">X_COL</span>=<span style="color: #ffa07a;">"$X_COL"</span>
            <span style="color: #98fb98; font-weight: bold;">echo</span> <span style="color: #7fffd4; font-weight: bold;">Y_COL</span>=<span style="color: #ffa07a;">"$Y_COL"</span>
            <span style="color: #98fb98; font-weight: bold;">echo</span> <span style="color: #7fffd4; font-weight: bold;">X_LABEL</span>=<span style="color: #ffa07a;">"$X_LABEL"</span>
            <span style="color: #98fb98; font-weight: bold;">echo</span> <span style="color: #7fffd4; font-weight: bold;">Y_LABEL</span>=<span style="color: #ffa07a;">"$Y_LABEL"</span>
            <span style="color: #98fb98; font-weight: bold;">echo</span> <span style="color: #7fffd4; font-weight: bold;">TITLE</span>=<span style="color: #ffa07a;">"$TITLE"</span>
            <span style="color: #98fb98; font-weight: bold;">echo</span> <span style="color: #7fffd4; font-weight: bold;">HEADER</span>=<span style="color: #ffa07a;">"$HEADER"</span>
            <span style="color: #98fb98; font-weight: bold;">echo</span> <span style="color: #7fffd4; font-weight: bold;">INCREMENT</span>=<span style="color: #ffa07a;">"$INCREMENT"</span>
            <span style="color: #98fb98; font-weight: bold;">echo</span> <span style="color: #7fffd4; font-weight: bold;">CUSTOM</span>=<span style="color: #ffa07a;">"$CUSTOM"</span>
            <span style="color: #98fb98; font-weight: bold;">echo</span> <span style="color: #7fffd4; font-weight: bold;">PLOTS</span>=<span style="color: #ffa07a;">"$PLOTS"</span>
            ;;
        h)
            <span style="color: #7fffd4; font-weight: bold;">HEADER</span>=<span style="color: #ffa07a;">"set key autotitle columnheader"</span>
            ;;
        c)
            <span style="color: #7fffd4; font-weight: bold;">CUSTOM</span>+=$<span style="color: #ffa07a;">'\n'</span>
            <span style="color: #7fffd4; font-weight: bold;">CUSTOM</span>+=<span style="color: #ffa07a;">"${OPTARG}"</span>
            ;;
        u)
            usage
            <span style="color: #fa8072;">exit</span>
            ;;
        d)
            <span style="color: #7fffd4; font-weight: bold;">DEBUG</span>=true
            ;;
    <span style="color: #fa8072;">esac</span>
<span style="color: #fa8072;">done</span>

<span style="color: #fa8072;">if</span> [ <span style="color: #ffa07a;">"${STDIN}"</span> = true ] ; <span style="color: #fa8072;">then</span>
    <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Save stdin to a file so that Gnuplot can read it for multiple</span>
    <span style="color: #add8e6;"># </span><span style="color: #add8e6;">plots.</span>
    cat /dev/stdin &gt; <span style="color: #ffa07a;">"${FILE}"</span>
    <span style="color: #fa8072;">trap</span> <span style="color: #ffa07a;">"rm ${FILE}"</span> EXIT      <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Make sure the temp file is deleted</span>
                                <span style="color: #add8e6;"># </span><span style="color: #add8e6;">when this script exits.</span>
    <span style="color: #7fffd4; font-weight: bold;">PLOT_TITLE</span>=<span style="color: #ffa07a;">"${PLOT_TITLE:-title 'stdin'}"</span>
<span style="color: #fa8072;">fi</span>

<span style="color: #fa8072;">if</span> [ -z <span style="color: #ffa07a;">"${PLOTS}"</span> ] ; <span style="color: #fa8072;">then</span>
    <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Make at least one plot if none are requested.</span>
    <span style="color: #7fffd4; font-weight: bold;">PLOTS</span>=<span style="color: #ffa07a;">"'${FILE}' using ${X_COL}${Y_COL} ${STYLE} ${PLOT_TITLE}"</span>
<span style="color: #fa8072;">fi</span>

<span style="color: #fa8072;">if</span> [ <span style="color: #ffa07a;">"${DEBUG}"</span> = true ] ; <span style="color: #fa8072;">then</span>
    <span style="color: #7fffd4; font-weight: bold;">COMMAND</span>=cat
<span style="color: #fa8072;">else</span>
    <span style="color: #7fffd4; font-weight: bold;">COMMAND</span>=gnuplot
<span style="color: #fa8072;">fi</span>

<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Generate Gnuplot command and call Gnuplot</span>
<span style="color: #ffa07a;">"${COMMAND}"</span> &lt;&lt;-EOF
<span style="color: #ffff00; font-weight: bold;">set terminal pngcairo</span>
<span style="color: #ffff00; font-weight: bold;">${CUSTOM}</span>
<span style="color: #ffff00; font-weight: bold;">set datafile separator ','</span>
<span style="color: #ffff00; font-weight: bold;">set output '${OUTPUT}'</span>
<span style="color: #ffff00; font-weight: bold;">set title '${TITLE}'</span>
<span style="color: #ffff00; font-weight: bold;">${TITLE_MATH}</span>
<span style="color: #ffff00; font-weight: bold;">${KEY_LOC}</span>
<span style="color: #ffff00; font-weight: bold;">${HEADER}</span>
<span style="color: #ffff00; font-weight: bold;">set xlabel '${X_LABEL}'</span>
<span style="color: #ffff00; font-weight: bold;">set ylabel '${Y_LABEL}'</span>

<span style="color: #ffff00; font-weight: bold;">plot ${RANGE} ${PLOTS}</span>
<span style="color: #ffff00; font-weight: bold;">EOF</span>

<span style="color: #fa8072;">if</span> [ <span style="color: #ffa07a;">"${DEBUG}"</span> = true ] ; <span style="color: #fa8072;">then</span>
    cat <span style="color: #ffa07a;">"${FILE}"</span>
<span style="color: #fa8072;">fi</span>
</pre>
</div>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Awk Saves the Day</title>
<link>https://remcycles.net/blog/gdb_and_awk.html</link>
<pubDate>Mon, 08 Apr 2019 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/gdb_and_awk.html</guid>
<description>
<![CDATA[<p>
Awk saved the day during some serious bit-twiddling debugging last
week.  I was at a client's location trying to debug the bootloader
code on a custom Linux board, and the <code>gdb</code> debugger couldn't talk to
the JTAG debugging device correctly.  All I could get out was the CPU
program counter and the CPU registers after single stepping by each
assembly instruction.
</p>

<p>
Something like:
</p>
<pre class="example" id="orga21cade">
PC = 17800000, CPSR = 600001D3 (SVC mode, ARM FIQ dis. IRQ dis.)
R0 = 0091FA94, R1 = 00000001, R2 = 00000018, R3 = 17800000
</pre>
<p>
etc.
</p>

<p>
With an annotated assembly source listing I could manually compare the
program counter with the assembly code (and the C code that generated
it) and go through line by line.
</p>

<p>
But I also knew there had to be some way to make the computer do that
work for me and save a serious number of keystrokes.
</p>

<p>
Eventually I found a solution:
</p>
<ul class="org-ul">
<li>Enable logging to a file with in <code>gdb</code> (<code>set logging file gdb.log</code>,
<code>set logging on</code>)</li>
<li>Pipe <code>tail -f gdb.log</code> to an awk script to grab the PC</li>
<li>Use awk to call <code>grep</code> over the assembly source for the address</li>
<li>Have <code>grep</code> print out enough context for everything to make sense.</li>
</ul>

<p>
All of that was a bash one-liner:
</p>
<div class="org-src-container">
<pre class="src src-bash">tail -f gdb.log | awk <span style="color: #ffa07a;">'/PC =/ { sub(",", "", $3); print $3; system("grep-C3 ^" tolower($3) ": ~/path/to/code.S") }'</span>
</pre>
</div>

<p>
I was pretty happy with that, because it saved me a ton of time.
</p>

<p>
Turns out the bootloader was running thousands of instructions before
dying, which was much later than we thought.
</p>

<p>
(Normally GDB will tell you all of that information and much more with
a much nicer interface, but as I said, something was seriously broken
with the setup and I needed a workaround quick.)
</p>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>dBm Cheatsheet</title>
<link>https://remcycles.net/blog/dbm_cheatsheet.html</link>
<pubDate>Sat, 29 Mar 2025 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/dbm_cheatsheet.html</guid>
<description>
<![CDATA[<p>
I recently used an oscilloscope to probe some RF signals, and I wanted
to calculate the peak-to-peak voltage to expect from a known power
output (in dBm) into a 50 ohm load.  So I made this cheatsheet:
</p>

<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">


<colgroup>
<col  class="org-right" />

<col  class="org-right" />

<col  class="org-right" />

<col  class="org-right" />
</colgroup>
<thead>
<tr>
<th scope="col" class="org-right">dBm</th>
<th scope="col" class="org-right">Watts</th>
<th scope="col" class="org-right">V RMS</th>
<th scope="col" class="org-right">Vpk-pk</th>
</tr>
</thead>
<tbody>
<tr>
<td class="org-right">0</td>
<td class="org-right">1m</td>
<td class="org-right">223.61m</td>
<td class="org-right">316.23m</td>
</tr>

<tr>
<td class="org-right">1</td>
<td class="org-right">1.26m</td>
<td class="org-right">250.89m</td>
<td class="org-right">354.81m</td>
</tr>

<tr>
<td class="org-right">2</td>
<td class="org-right">1.58m</td>
<td class="org-right">281.5m</td>
<td class="org-right">398.11m</td>
</tr>

<tr>
<td class="org-right">3</td>
<td class="org-right">2m</td>
<td class="org-right">315.85m</td>
<td class="org-right">446.68m</td>
</tr>

<tr>
<td class="org-right">4</td>
<td class="org-right">2.51m</td>
<td class="org-right">354.39m</td>
<td class="org-right">501.19m</td>
</tr>

<tr>
<td class="org-right">5</td>
<td class="org-right">3.16m</td>
<td class="org-right">397.64m</td>
<td class="org-right">562.34m</td>
</tr>

<tr>
<td class="org-right">6</td>
<td class="org-right">3.98m</td>
<td class="org-right">446.15m</td>
<td class="org-right">630.96m</td>
</tr>

<tr>
<td class="org-right">7</td>
<td class="org-right">5.01m</td>
<td class="org-right">500.59m</td>
<td class="org-right">707.95m</td>
</tr>

<tr>
<td class="org-right">8</td>
<td class="org-right">6.31m</td>
<td class="org-right">561.67m</td>
<td class="org-right">794.33m</td>
</tr>

<tr>
<td class="org-right">9</td>
<td class="org-right">7.94m</td>
<td class="org-right">630.21m</td>
<td class="org-right">891.25m</td>
</tr>

<tr>
<td class="org-right">10</td>
<td class="org-right">10m</td>
<td class="org-right">707.11m</td>
<td class="org-right">1</td>
</tr>

<tr>
<td class="org-right">11</td>
<td class="org-right">12.59m</td>
<td class="org-right">793.39m</td>
<td class="org-right">1.12</td>
</tr>

<tr>
<td class="org-right">12</td>
<td class="org-right">15.85m</td>
<td class="org-right">890.19m</td>
<td class="org-right">1.26</td>
</tr>

<tr>
<td class="org-right">13</td>
<td class="org-right">19.95m</td>
<td class="org-right">998.81m</td>
<td class="org-right">1.41</td>
</tr>

<tr>
<td class="org-right">14</td>
<td class="org-right">25.12m</td>
<td class="org-right">1.12</td>
<td class="org-right">1.58</td>
</tr>

<tr>
<td class="org-right">15</td>
<td class="org-right">31.62m</td>
<td class="org-right">1.26</td>
<td class="org-right">1.78</td>
</tr>

<tr>
<td class="org-right">16</td>
<td class="org-right">39.81m</td>
<td class="org-right">1.41</td>
<td class="org-right">2</td>
</tr>

<tr>
<td class="org-right">17</td>
<td class="org-right">50.12m</td>
<td class="org-right">1.58</td>
<td class="org-right">2.24</td>
</tr>

<tr>
<td class="org-right">18</td>
<td class="org-right">63.1m</td>
<td class="org-right">1.78</td>
<td class="org-right">2.51</td>
</tr>

<tr>
<td class="org-right">19</td>
<td class="org-right">79.43m</td>
<td class="org-right">1.99</td>
<td class="org-right">2.82</td>
</tr>

<tr>
<td class="org-right">20</td>
<td class="org-right">100m</td>
<td class="org-right">2.24</td>
<td class="org-right">3.16</td>
</tr>

<tr>
<td class="org-right">21</td>
<td class="org-right">125.89m</td>
<td class="org-right">2.51</td>
<td class="org-right">3.55</td>
</tr>

<tr>
<td class="org-right">22</td>
<td class="org-right">158.49m</td>
<td class="org-right">2.82</td>
<td class="org-right">3.98</td>
</tr>

<tr>
<td class="org-right">23</td>
<td class="org-right">199.53m</td>
<td class="org-right">3.16</td>
<td class="org-right">4.47</td>
</tr>

<tr>
<td class="org-right">24</td>
<td class="org-right">251.19m</td>
<td class="org-right">3.54</td>
<td class="org-right">5.01</td>
</tr>

<tr>
<td class="org-right">25</td>
<td class="org-right">316.23m</td>
<td class="org-right">3.98</td>
<td class="org-right">5.62</td>
</tr>

<tr>
<td class="org-right">26</td>
<td class="org-right">398.11m</td>
<td class="org-right">4.46</td>
<td class="org-right">6.31</td>
</tr>

<tr>
<td class="org-right">27</td>
<td class="org-right">501.19m</td>
<td class="org-right">5.01</td>
<td class="org-right">7.08</td>
</tr>

<tr>
<td class="org-right">28</td>
<td class="org-right">630.96m</td>
<td class="org-right">5.62</td>
<td class="org-right">7.94</td>
</tr>

<tr>
<td class="org-right">29</td>
<td class="org-right">794.33m</td>
<td class="org-right">6.3</td>
<td class="org-right">8.91</td>
</tr>

<tr>
<td class="org-right">30</td>
<td class="org-right">1</td>
<td class="org-right">7.07</td>
<td class="org-right">10</td>
</tr>

<tr>
<td class="org-right">31</td>
<td class="org-right">1.26</td>
<td class="org-right">7.93</td>
<td class="org-right">11.22</td>
</tr>

<tr>
<td class="org-right">32</td>
<td class="org-right">1.58</td>
<td class="org-right">8.9</td>
<td class="org-right">12.59</td>
</tr>

<tr>
<td class="org-right">33</td>
<td class="org-right">2</td>
<td class="org-right">9.99</td>
<td class="org-right">14.13</td>
</tr>

<tr>
<td class="org-right">34</td>
<td class="org-right">2.51</td>
<td class="org-right">11.21</td>
<td class="org-right">15.85</td>
</tr>

<tr>
<td class="org-right">35</td>
<td class="org-right">3.16</td>
<td class="org-right">12.57</td>
<td class="org-right">17.78</td>
</tr>

<tr>
<td class="org-right">36</td>
<td class="org-right">3.98</td>
<td class="org-right">14.11</td>
<td class="org-right">19.95</td>
</tr>

<tr>
<td class="org-right">37</td>
<td class="org-right">5.01</td>
<td class="org-right">15.83</td>
<td class="org-right">22.39</td>
</tr>

<tr>
<td class="org-right">38</td>
<td class="org-right">6.31</td>
<td class="org-right">17.76</td>
<td class="org-right">25.12</td>
</tr>

<tr>
<td class="org-right">39</td>
<td class="org-right">7.94</td>
<td class="org-right">19.93</td>
<td class="org-right">28.18</td>
</tr>

<tr>
<td class="org-right">40</td>
<td class="org-right">10</td>
<td class="org-right">22.36</td>
<td class="org-right">31.62</td>
</tr>

<tr>
<td class="org-right">41</td>
<td class="org-right">12.59</td>
<td class="org-right">25.09</td>
<td class="org-right">35.48</td>
</tr>

<tr>
<td class="org-right">42</td>
<td class="org-right">15.85</td>
<td class="org-right">28.15</td>
<td class="org-right">39.81</td>
</tr>

<tr>
<td class="org-right">43</td>
<td class="org-right">19.95</td>
<td class="org-right">31.59</td>
<td class="org-right">44.67</td>
</tr>

<tr>
<td class="org-right">44</td>
<td class="org-right">25.12</td>
<td class="org-right">35.44</td>
<td class="org-right">50.12</td>
</tr>

<tr>
<td class="org-right">45</td>
<td class="org-right">31.62</td>
<td class="org-right">39.76</td>
<td class="org-right">56.23</td>
</tr>

<tr>
<td class="org-right">46</td>
<td class="org-right">39.81</td>
<td class="org-right">44.62</td>
<td class="org-right">63.1</td>
</tr>

<tr>
<td class="org-right">47</td>
<td class="org-right">50.12</td>
<td class="org-right">50.06</td>
<td class="org-right">70.79</td>
</tr>

<tr>
<td class="org-right">48</td>
<td class="org-right">63.1</td>
<td class="org-right">56.17</td>
<td class="org-right">79.43</td>
</tr>

<tr>
<td class="org-right">49</td>
<td class="org-right">79.43</td>
<td class="org-right">63.02</td>
<td class="org-right">89.13</td>
</tr>

<tr>
<td class="org-right">50</td>
<td class="org-right">100</td>
<td class="org-right">70.71</td>
<td class="org-right">100</td>
</tr>

<tr>
<td class="org-right">51</td>
<td class="org-right">125.89</td>
<td class="org-right">79.34</td>
<td class="org-right">112.2</td>
</tr>

<tr>
<td class="org-right">52</td>
<td class="org-right">158.49</td>
<td class="org-right">89.02</td>
<td class="org-right">125.89</td>
</tr>

<tr>
<td class="org-right">53</td>
<td class="org-right">199.53</td>
<td class="org-right">99.88</td>
<td class="org-right">141.25</td>
</tr>

<tr>
<td class="org-right">54</td>
<td class="org-right">251.19</td>
<td class="org-right">112.07</td>
<td class="org-right">158.49</td>
</tr>

<tr>
<td class="org-right">55</td>
<td class="org-right">316.23</td>
<td class="org-right">125.74</td>
<td class="org-right">177.83</td>
</tr>

<tr>
<td class="org-right">56</td>
<td class="org-right">398.11</td>
<td class="org-right">141.09</td>
<td class="org-right">199.53</td>
</tr>

<tr>
<td class="org-right">57</td>
<td class="org-right">501.19</td>
<td class="org-right">158.3</td>
<td class="org-right">223.87</td>
</tr>

<tr>
<td class="org-right">58</td>
<td class="org-right">630.96</td>
<td class="org-right">177.62</td>
<td class="org-right">251.19</td>
</tr>

<tr>
<td class="org-right">59</td>
<td class="org-right">794.33</td>
<td class="org-right">199.29</td>
<td class="org-right">281.84</td>
</tr>

<tr>
<td class="org-right">60</td>
<td class="org-right">1k</td>
<td class="org-right">223.61</td>
<td class="org-right">316.23</td>
</tr>
</tbody>
</table>

<p>
Here is a <a href="https://remcycles.net/blog/../files/dBm_cheat_sheet.pdf">printable PDF</a> and the <a href="https://remcycles.net/blog/../files/dBm_cheatsheet.ods">source file</a> (LibreOffice Calc).
</p>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>An Improved Echo</title>
<link>https://remcycles.net/blog/echo.html</link>
<pubDate>Wed, 26 Jun 2024 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/echo.html</guid>
<description>
<![CDATA[<p>
Here's an improvement on the standard <code>echo</code> utility:
</p>

<div class="org-src-container">
<pre class="src src-bash"><span style="color: #add8e6;">#</span><span style="color: #add8e6;">!/bin/</span><span style="color: #fa8072;">bash</span>

<span style="color: #7fffd4; font-weight: bold;">WORD</span>=<span style="color: #ffa07a;">"${1:-echo}"</span>
<span style="color: #7fffd4; font-weight: bold;">WORD</span>=<span style="color: #ffa07a;">"${WORD,,}"</span>
<span style="color: #98fb98; font-weight: bold;">echo</span> <span style="color: #ffa07a;">"${WORD^^}   ${WORD^}    ${WORD}     ${WORD: -3}      ${WORD: -1}"</span>
</pre>
</div>

<p>
Example usage:
</p>
<pre class="example" id="orga47bcaf">
$ ./echo.sh
ECHO   Echo    echo     cho      o

$ ./echo.sh "this is a test"
THIS IS A TEST   This is a test    this is a test     est      t
</pre>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Generating CRC Diagrams with Pikchr and Bash</title>
<link>https://remcycles.net/blog/crc_diagrams.html</link>
<pubDate>Mon, 07 Nov 2022 00:00:00 -0800</pubDate>
<guid>https://remcycles.net/blog/crc_diagrams.html</guid>
<description>
<![CDATA[<style>
.figure-number {
    display: none;
}
</style>

<p>
I recently helped a friend sort out a bug in a CRC function that
revolved around using the wrong hexadecimal encoding for the CRC's
generator polynomial.  Wikipedia's article on the <a href="https://en.wikipedia.org/wiki/Mathematics_of_cyclic_redundancy_checks#Reversed_representations_and_reciprocal_polynomials">mathematics of CRCs</a>
names three different ways to represent or encode the same generator
polynomial \(G(x)\) as a hexadecimal constant.  Even though they all
encode the same polynomial, the source code for a CRC implementation
needs to match the chosen polynomial encoding in order to function
properly.
</p>

<p>
In a future update or post I'll describe how exactly a C
implementation should change depending on the encoding of the
generator polynomial.  In the meantime, I can highly recommend the CRC
chapter in the second edition of <a href="https://www.pearson.com/en-us/subject-catalog/p/hackers-delight/P200000000672/9780321842688?tab=table-of-contents">Hacker's Delight</a> by Henry S. Warren,
Jr. as a good introduction to practical CRC implementations, though it
only describes one polynomial encoding format.  <a href="https://onlinelibrary.wiley.com/doi/book/10.1002/0471739219">Todd K. Moon's ECC
book</a> describes the CRC math more in depth, but leaves implementation
as an exercise to for the reader (rightfully so, considering it's use
as a textbook) and does not discuss alternative encoding formats
either.  Philip Koopman's <a href="https://users.ece.cmu.edu/~koopman/crc/crc8.html">CRC Polynomial Zoo</a> does provide encoded CRC
polynomials in different formats, but does not provide example code
for each format.
</p>

<p>
The three named polynomial encoding formats on Wikipedia are:
</p>
<ul class="org-ul">
<li>Normal</li>
<li>Reverse</li>
<li>Koopman</li>
</ul>

<p>
Wikipedia also points out that the "reciprocal" of a generator
polynomial \(G(x)\), \(x^n G(x^{-1})\), has the same error detection
abilities as the original generator polynomial.  It names two encoding
formats for the reciprocal:
</p>
<ul class="org-ul">
<li>Reciprocal</li>
<li>Reverse Reciprocal</li>
</ul>

<p>
So there are five different ways to interpret a hex constant like
<code>0x1021</code> as the generator polynomial of a CRC.
</p>


<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Custom Drop Bolt for Front Brake Mount</title>
<link>https://remcycles.net/blog/drop_bolt.html</link>
<pubDate>Wed, 12 Jul 2023 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/drop_bolt.html</guid>
<description>
<![CDATA[<p>
I recently bought an old Nishiki 62cm frame from <a href="https://www.thebikehub.org/">The Hub Community
Bike Shop</a> to ride as a fixed-gear bike.  It was built for 27-inch
wheels, but I want to use 700c for all my bikes.  That meant I needed
a long reach caliper brake to reach the extra 4mm down to the 700c
rim.  But this frame also has cantiliver brake bosses, and long reach
brakes interfere with those.
</p>

<p>
The solution was to mount my existing caliper brake to a homemade
"drop bolt", <a href="https://sheldonbrown.com/home-drop.html">as described by Sheldon Brown</a>.  It's been working well
for about a month.
</p>

<p>
In the photo below you can see how some extra washers push the caliber
brake forward just enough to clear the bosses.
</p>


<div id="org64b232c" class="figure">
<p><a href="https://remcycles.net/blog/../images/dropbolt.jpg" width="500px"><img src="https://remcycles.net/blog/../images/dropbolt.jpg" alt="dropbolt.jpg" width="500px" /></a>
</p>
</div>


<div id="org0b9ea11" class="figure">
<p><a href="https://remcycles.net/blog/../images/dropbolt_front.jpg" width="500px"><img src="https://remcycles.net/blog/../images/dropbolt_front.jpg" alt="dropbolt_front.jpg" width="500px" /></a>
</p>
</div>


<div id="org3c0dc86" class="figure">
<p><a href="https://remcycles.net/blog/../images/dropbolt_back.jpg" width="500px"><img src="https://remcycles.net/blog/../images/dropbolt_back.jpg" alt="dropbolt_back.jpg" width="500px" /></a>
</p>
</div>

<p>
Surprisingly, my junk bin had a pair of brass rectangles that were
already the perfect dimensions and were already drilled with two holes
at the correct spacing.  All I needed to do was enlarge the holes to
accept 6mm bolts, get a long stainless steel M6 bolt, washer, and lock
nut at the hardware store, and cut a section of lamp nipple to use as
a spacer on the lower bolt.
</p>

<p>
The brass bits came from an antique printer's cabinet that I got off
of Craigslist a few years ago.  They were used as stops for whatever
was placed on the sloping table top.  I took them off and saved them
when I refinished the cabinet.  I'm glad I did.
</p>


<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Visualizing Correlation Vector Math</title>
<link>https://remcycles.net/blog/corr_viz.html</link>
<pubDate>Fri, 06 Jun 2025 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/corr_viz.html</guid>
<description>
<![CDATA[<p>
In this post I'll share some visualizations I made while taking <a href="https://www.dsp-coach.com/courses">Dan
Boschen's</a> <a href="https://www.dsprelated.com/course/DSP_For_Wireless_Communications_2025_America">DSP for Wireless Communications</a> course and shared with the
rest of the class.
</p>

<p>
I modified Dan's example code to create <a href="https://pikchr.org">Pikchr</a> animations to gain a
better intuitive understanding of an very important concept in DSP:
correlation.
</p>

<p>
I highly recommend his courses for anyone interested in learning more
about digital signal processing fundamentals and/or refreshing their
skills.  I was <a href="https://courses.cs.washington.edu/courses/cse466/08wi/labs/l7/l7.html">exposed to some DSP in college</a> but never took a proper
DSP class, and it always helps to fill in gaps in the rest of my
self-taught knowledge.  His courses are a fantastic deal, in my
opinion.
</p>


<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>A Chromatic Button MIDI Keyboard</title>
<link>https://remcycles.net/blog/cba_keyboard.html</link>
<pubDate>Thu, 23 Jul 2020 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/cba_keyboard.html</guid>
<description>
<![CDATA[<p>
This is a project I've wanted to build since about 2013, and I finally
got around to finishing it in 2020.
</p>


<div id="org564ba49" class="figure">
<p><a href="https://remcycles.net/blog/../images/cba/three_octave_build.jpg" width="500px"><img src="https://remcycles.net/blog/../images/cba/three_octave_build.jpg" alt="three_octave_build.jpg" width="500px" /></a>
</p>
</div>

<p>
It's a velocity sensitive MIDI controller with the same layout as a
<a href="https://en.wikipedia.org/wiki/Chromatic_button_accordion">chromatic button accordion</a>.
</p>


<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Using Computers to Compute: Calculating Sine and Cosine Using CORDIC</title>
<link>https://remcycles.net/blog/cordic.html</link>
<pubDate>Thu, 26 Jul 2018 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/cordic.html</guid>
<description>
<![CDATA[<style>
.figure-number {
    display: none;
}
</style>

<p>
I gave this presentation at a <a href="https://bellingham.codes">Bellingham.Codes</a> meeting on July
26th, 2018:
</p>

<p>
<a href="https://remcycles.net/blog/../files/cordic_presentation.pdf">Using Computers to Compute: Calculating Sine and Cosine using CORDIC</a>
</p>


<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Emacs Calc Tricks</title>
<link>https://remcycles.net/blog/calc.html</link>
<pubDate>Wed, 05 Feb 2020 00:00:00 -0800</pubDate>
<guid>https://remcycles.net/blog/calc.html</guid>
<description>
<![CDATA[<p>
I've been learning and using the advanced RPN calculator included in
Emacs, known as <code>calc</code>.  The primary reason is that it is aware of
units.  As they say, a number without a unit is meaningless, and it
now baffles me that so few programming langauges care to track them at
all.  It's also built-in to my favorite text editor, which makes
copying data in and out of <code>calc</code> very easy.  And along those lines,
it's a useful tool with org-mode tables, turning them into mini
spreadsheets.
</p>

<p>
Like Emacs itself, <code>calc</code> is a deep and intimidating tool.  But after
getting comfortable with a few basics it's easy to learn more advanced
features from the built-in info documentation.
</p>


<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>A Makefile for Quick C Experiments</title>
<link>https://remcycles.net/blog/c_experiments.html</link>
<pubDate>Wed, 04 Sep 2024 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/c_experiments.html</guid>
<description>
<![CDATA[<p>
Here's a handy Makefile I use when I want to experiment with some C
code to check my understanding of the language or some library.  It
simply takes a directory of <code>.c</code> files, each with their own <code>main()</code>
functions, and compiles them into binaries, preprocessor output, and
assembly output.  The assembly output is nicer than using Godbolt's
Compiler Explorer when you have a large file or you want to keep your
code private.  With minor modifications, the Makefile can be
configured to match your exact cross-compiler settings for embedded
development.
</p>

<div class="org-src-container">
<pre class="src src-bash"><span style="color: #7fffd4; font-weight: bold;">SRCS</span>=$(<span style="color: #fa8072;">wildcard *.c</span>)        <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Find all the .c files in this directory.</span>
<span style="color: #7fffd4; font-weight: bold;">BINS</span>=$(<span style="color: #fa8072;">SRCS:.c=</span>)            <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Make binaries for them all.</span>
<span style="color: #7fffd4; font-weight: bold;">ASMS</span>=$(<span style="color: #fa8072;">SRCS:.c=.s</span>)          <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Output assembly code for them.</span>
<span style="color: #7fffd4; font-weight: bold;">PRES</span>=$(<span style="color: #fa8072;">SRCS:.c=.i</span>)          <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Save the pre-processor output.</span>


<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Set these as environment variables before running make if you want</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">to override these defaults:</span>
CC?=gcc
OPT?=-O3

<span style="color: #7fffd4; font-weight: bold;">CFLAGS</span>=-Wall -Wpedantic
<span style="color: #7fffd4; font-weight: bold;">CFLAGS</span>+=$(<span style="color: #fa8072;">OPT</span>)

<span style="color: #7fffd4; font-weight: bold;">LIBS</span>=-lm


all: $(<span style="color: #fa8072;">BINS</span>) $(<span style="color: #fa8072;">ASMS</span>) $(<span style="color: #fa8072;">PRES</span>)
bin: $(<span style="color: #fa8072;">BINS</span>)
asm: $(<span style="color: #fa8072;">ASMS</span>)
pre: $(<span style="color: #fa8072;">PRES</span>)


<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Make the binary.</span>
%: %.c
        $(<span style="color: #fa8072;">CC</span>) $(<span style="color: #fa8072;">CFLAGS</span>) -o $<span style="color: #7fffd4; font-weight: bold;">@</span> $&lt; $(<span style="color: #fa8072;">LIBS</span>)

<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Make the assembly output.</span>
%.s: %.c
        $(<span style="color: #fa8072;">CC</span>) $(<span style="color: #fa8072;">CFLAGS</span>) -S -fverbose-asm -o $<span style="color: #7fffd4; font-weight: bold;">@</span> $&lt; $(<span style="color: #fa8072;">LIBS</span>)

<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Make the preprocessor output.</span>
%.i: %.c
        $(<span style="color: #fa8072;">CC</span>) $(<span style="color: #fa8072;">CFLAGS</span>) -E -o $<span style="color: #7fffd4; font-weight: bold;">@</span> $&lt; $(<span style="color: #fa8072;">LIBS</span>)


.PHONY: clean
clean:
        rm -f $(<span style="color: #fa8072;">BINS</span>) $(<span style="color: #fa8072;">ASMS</span>) $(<span style="color: #fa8072;">PRES</span>)
</pre>
</div>

<p>
Some example usage follows.
</p>

<p>
<a href="https://remcycles.net/blog/../files/c_experiments/printf.c">printf.c</a>:
</p>
<div class="org-src-container">
<pre class="src src-c"><span style="color: #fa8072;">#include</span> <span style="color: #ffa07a;">&lt;stdio.h&gt;</span>

<span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">main</span>(<span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">argc</span>, <span style="color: #9acd32; font-weight: bold;">char</span> **<span style="color: #7fffd4; font-weight: bold;">argv</span>) {
    <span style="color: #fa8072;">for</span> (<span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">i</span> = 0; i &lt; argc; i++) {
        printf(<span style="color: #ffa07a;">"%s\n"</span>, argv[i]);
    }
}
</pre>
</div>

<p>
<a href="https://remcycles.net/blog/../files/c_experiments/int_overflow.c">int<sub>overflow.c</sub></a>:
</p>
<div class="org-src-container">
<pre class="src src-c"><span style="color: #fa8072;">#include</span> <span style="color: #ffa07a;">&lt;stdio.h&gt;</span>
<span style="color: #fa8072;">#include</span> <span style="color: #ffa07a;">&lt;stdint.h&gt;</span>

<span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">main</span>(<span style="color: #9acd32; font-weight: bold;">int</span> <span style="color: #7fffd4; font-weight: bold;">argc</span>, <span style="color: #9acd32; font-weight: bold;">char</span> **<span style="color: #7fffd4; font-weight: bold;">argv</span>) {
    <span style="color: #9acd32; font-weight: bold;">int8_t</span> <span style="color: #7fffd4; font-weight: bold;">max</span> = INT8_MAX;
    printf(<span style="color: #ffa07a;">"max:   % 4d\n"</span>, max);

    <span style="color: #9acd32; font-weight: bold;">int8_t</span> <span style="color: #7fffd4; font-weight: bold;">max_incr</span> = max + 1;
    printf(<span style="color: #ffa07a;">"max+1: % 4d\n"</span>, max_incr);

    <span style="color: #9acd32; font-weight: bold;">int8_t</span> <span style="color: #7fffd4; font-weight: bold;">min</span> = INT8_MIN;
    printf(<span style="color: #ffa07a;">"min:   % 4d\n"</span>, min);
}
</pre>
</div>

<pre class="example" id="org522376e">
~/code/experiments $ make
cc -Wall -Wpedantic -O3 -o int_overflow int_overflow.c -lm
cc -Wall -Wpedantic -O3 -o printf printf.c -lm
cc -Wall -Wpedantic -O3 -S -fverbose-asm -o int_overflow.s int_overflow.c -lm
cc -Wall -Wpedantic -O3 -S -fverbose-asm -o printf.s printf.c -lm
cc -Wall -Wpedantic -O3 -E -o int_overflow.i int_overflow.c -lm
cc -Wall -Wpedantic -O3 -E -o printf.i printf.c -lm

~/code/experiments $ ./printf this is a test
./printf
this
is
a
test

~/code/experiments $ ./int_overflow 
max:    127
max+1: -128
min:   -128
</pre>

<p>
Example output:
</p>
<table border="2" cellspacing="0" cellpadding="6" rules="groups" frame="hsides">


<colgroup>
<col  class="org-left" />

<col  class="org-left" />
</colgroup>
<tbody>
<tr>
<td class="org-left"><a href="https://remcycles.net/blog/../files/c_experiments/printf.i">printf.i</a></td>
<td class="org-left"><a href="https://remcycles.net/blog/../files/c_experiments/int_overflow.i">int<sub>overflow.i</sub></a></td>
</tr>

<tr>
<td class="org-left"><a href="https://remcycles.net/blog/../files/c_experiments/printf.s">printf.s</a></td>
<td class="org-left"><a href="https://remcycles.net/blog/../files/c_experiments/int_overflow.s">int<sub>overflow.s</sub></a></td>
</tr>
</tbody>
</table>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Brazing a Broken Dropout</title>
<link>https://remcycles.net/blog/brazing_broken_dropout.html</link>
<pubDate>Wed, 19 Aug 2020 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/brazing_broken_dropout.html</guid>
<description>
<![CDATA[
<div id="orge6425aa" class="figure">
<p><a href="https://remcycles.net/blog/../images/surly_dropout_crack.jpg" width="500px"><img src="https://remcycles.net/blog/../images/surly_dropout_crack.jpg" alt="surly_dropout_crack.jpg" width="500px" /></a>
</p>
</div>


<div id="org6f2efa0" class="figure">
<p><a href="https://remcycles.net/blog/../images/surly_dropout_cleaned.jpg" width="500px"><img src="https://remcycles.net/blog/../images/surly_dropout_cleaned.jpg" alt="surly_dropout_cleaned.jpg" width="500px" /></a>
</p>
</div>

<p>
Way back in 2011 my beloved Surly Crosscheck broke with a cracked rear
dropout.  I raced on it on the Husky Cycling team in college, toured
on it across Washington State; Switzerland, France, and Spain; Japan;
and across the US from California to Florida, and I was sad to lose
it.
</p>

<p>
Luckily I was only riding on the sidewalk when it happened and got
super wobbly.  It took me a while to understand what was going on,
because at first I just thought it was a flat.  Maybe jumping up onto
that sidewalk roughly is what broke it, I don't remember.
</p>

<p>
At the time, I decided to buy a 2011 Speciale Randonneur rather than
deal with the hassle of hiring someone to fix the frame.  That Masi is
still my primary ride, and I like it for many of the same reasons I
loved my Surly.
</p>

<p>
One of the reasons I like steel bikes is that they can be easily
repaired while on a tour.  It took nine years, but I finally decided
to try and fix it myself, by learning how to braze.
</p>


<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Analyzing Bit Errors with J and Tcl</title>
<link>https://remcycles.net/blog/bit_errors_j.html</link>
<pubDate>Mon, 04 Aug 2025 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/bit_errors_j.html</guid>
<description>
<![CDATA[<p>
I let this year's <a href="https://www.ioccc.org/">International Obfuscated C Code Contest (IOCCC)</a>
deadline pass because I've been having too much fun learning <a href="https://www.jsoftware.com/">J</a>, an
<a href="https://en.wikipedia.org/wiki/Array_programming">array language</a> where every line reads like an IOCCC <a href="https://raw.githubusercontent.com/ioccc-src/winner/refs/heads/master/2012/konno/konno.c">best one-liner</a>
entry.
</p>

<p>
J is a descendent of <a href="https://en.wikipedia.org/wiki/APL_(programming_language)">APL</a>, both created by <a href="https://en.wikipedia.org/wiki/Kenneth_E._Iverson">Ken Iverson</a>.  For the last
year I've been listening to the <a href="https://www.arraycast.com/">ArrayCast</a> and reading Henry Rich's
book "<a href="https://www.jsoftware.com/help/jforc/contents.htm">J for C Programmers</a>" cover to cover. The ArrayCast is
often more technical than my other favorite nerd podcasts, <a href="https://theamphour.com/">The Amp
Hour</a> and <a href="https://embedded.fm/">The Embedded FM Podcast</a>, and it frequently gets into the
detailed design and implementation of array languages.
</p>

<p>
As a quick introduction, J, like other array langauges, uses a set of
primitives to manipulate data stored in arrays of any dimension.  The
interpreter will automatically loop primatives over the data based on
the "rank" (or shape) of the primative and data, and primitives can be
composed to modify their behavior.  It's a unique style of functional
programming.  In J, all primatives are written with one or more ASCII
characters.  APL and other array languages use special symbols for
primitives.
</p>

<p>
I previously wrote a Tcl script to analyze bit errors in packet
payloads.  Simple things like counting the number of errors (the
<a href="https://en.wikipedia.org/wiki/Hamming_distance">Hamming distance</a>), the positions of each error and the distances
between them.  Writing that in Tcl was quick and easy since I already
know Tcl.  And Tcl is naturally a good fit for processing strings of
ones and zeros (or hex), and it also supports arbitrary precision
integers (big ints) for performing bitwise operators.
</p>

<p>
I figured J's support for operations on arbitrary length vectors would
also be a good fit for this task, so I wrote a similar program in J.
This was a much slower process, as expected, since I'm still learning
the language.  I'm a long way from knowing idiomatic J or really
grokking the array way of thinking, but I think experience with
bit-twiddling and masking in C and some functional programming
background was a helpful start.
</p>

<p>
The array langauges support a programming style called "tacit
programming".  Tacit code that does not explicitly reference its input
variables; it consists only of primitives that operate on the implied
arguments.  It's similar to how stack based (or concatenative)
langauges like Forth or Factor work, except that the syntax is built
around applying unary and binary operations and a syntax called
"forks" and "hooks".  In my opinion, that really complicates things,
and a stack based model would be easier for me to understand.
That said, I tried to write tacit verbs where I could.
</p>

<p>
Two annoyances with J: First, when an integer overflows in J the interpreter
promotes it to a double floating point value, not an extended
precision integer like in Tcl.  So you must first convert any number
that might overflow to an extended precision type in advance.
The <code>xfh</code> ("extended from hex") verb modifies <code>dfh</code> ("decimal from
hex") from the <code>stdlib.ijs</code> file to parse extended precision integers.
Otherwise long hex strings would be converted to a double.
</p>

<p>
Second, the J installation process on Linux is a bit messy, so I just
hardcoded a local directory in the shebang line for now.  And newer
versions of glibc complain about executing code on the stack, so I had
to run J with this wrapper script:
</p>
<div class="org-src-container">
<pre class="src src-bash"><span style="color: #add8e6;">#</span><span style="color: #add8e6;">!/bin/</span><span style="color: #fa8072;">bash</span>

<span style="color: #7fffd4; font-weight: bold;">GLIBC_TUNABLES</span>=glibc.rtld.execstack=2 $(<span style="color: #fa8072;">dirname "$0"</span>)/bin/jconsole <span style="color: #ffa07a;">"$@"</span>
</pre>
</div>

<pre class="example" id="org3e56f5c">
Load library /path/to/j9.6/bin/libj.so failed: /path/to/j9.6/bin/libj.so: cannot enable executable stack as shared object requires: Invalid argument
</pre>



<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>The Geometry of the Bilinear Transform</title>
<link>https://remcycles.net/blog/bilinear_transform_geometry.html</link>
<pubDate>Thu, 06 Apr 2023 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/bilinear_transform_geometry.html</guid>
<description>
<![CDATA[<p>
I'm taking Dan Boschen's <a href="https://www.dsprelated.com/course/DSP_For_Software_Radio_2023">DSP for Software Radio</a> class now and it
covers the <a href="https://en.wikipedia.org/wiki/Bilinear_transform">bilinear transform</a> for mapping between the s-plane and
z-plane:
</p>

<p>
\[s = \frac{2(z-1)}{T(z+1)}\]
</p>

<p>
The plot for the Z-plane after the mapping looks a lot like a Smith
chart, which I <a href="https://remcycles.net/blog/./smith_chart_geometry.html">posted about previously</a>.  Specifically, it resembles an
admittance chart, which is a Smith chart rotated 180 degrees.  In a
Smith chart, the right-hand side of the s-plane gets mapped to the
inside of the unit circle.  In the bilinear transform, the left-hand
side of the s-plane gets mapped to the inside of the unit circle.
</p>

<p>
I wanted to make another animation which shows how that looks, so I
updated my Julia code to do that.
</p>

<p>
Solving for \(z\) gives:
</p>

<p>
\[z = -\frac{s+2/T}{s-2/T}\]
</p>

<p>
This conformal mapping is another Mobius transformation \((a z + b)/(c
z + d)\) with \(a=-b=1\) and \(d=b=2/T\).
</p>


<div id="org8b58f31" class="figure">
<p><img src="https://remcycles.net/blog/../images/bilinear_transform.gif" alt="bilinear_transform.gif" />
</p>
</div>

<p>
Once again, I had to work out the math for how the vertical and
horizontal lines of the Cartesian grid map to the z-plane with this
new equation.  This time all the vertical lines map to circles with
centers on the real axis to the left of (0,0), and they all pass
through (-1,0).  The horizontal lines map to circles centered above
(-1,0).
</p>

<p>
By chance, the animation is now centered on the z-plane location where
s-plane points at infinity map to (the left hand side of the unit
circle), not s=(0,0) as in my Smith chart animations.  Since I only
draw a finite number of grid lines, the left-hand side of the circle
at (∞,∞) is rather sparse to begin with, until more and more grid
lines near the s-plane come closer as the transform tightens.
</p>

<p>
I don't have the time to sort that out and recenter the plot on the
(0,0) point.  But I also want to keep it this way since this new plot
also gives a different perspective on the situation.
</p>


<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Number Theory in Bash</title>
<link>https://remcycles.net/blog/bash_number_theory.html</link>
<pubDate>Sun, 18 Sep 2022 21:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/bash_number_theory.html</guid>
<description>
<![CDATA[<p>
I've been studying error correction codes, specfically the book <a href="https://onlinelibrary.wiley.com/doi/book/10.1002/0471739219">Error
Correction Coding: Mathematical Methods and Algorithms</a> 1st Ed. by Todd
K. Moon.
</p>

<p>
The order (number of elements) of any finite field (aka Galois field)
is a power of a prime number.  I was curious how many integers were
valid orders for a finite field and I knew I could quickly list them
all by parsing the output of the <code>factor</code> command. That led to
the following hack.
</p>

<div class="org-src-container">
<pre class="src src-bash"><span style="color: #add8e6;">#</span><span style="color: #add8e6;">!/bin/</span><span style="color: #fa8072;">bash</span>

<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Quick and dirty script to find all finite field orders less than a</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">given number.</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">See https://oeis.org/A000961 and https://oeis.org/A246655.</span>

<span style="color: #7fffd4; font-weight: bold;">limit</span>=${<span style="color: #7fffd4; font-weight: bold;">1</span>:-1000}

<span style="color: #98fb98; font-weight: bold;">echo</span> <span style="color: #ffa07a;">"q = p^m"</span>

<span style="color: #7fffd4; font-weight: bold;">gf_count</span>=0

<span style="color: #fa8072;">while </span><span style="color: #98fb98; font-weight: bold;">read</span> line ; <span style="color: #fa8072;">do</span>
    <span style="color: #7fffd4; font-weight: bold;">factors</span>=$(<span style="color: #fa8072;">echo $line | cut -d: -f2</span>)
    <span style="color: #7fffd4; font-weight: bold;">num_uniq_factors</span>=$(<span style="color: #fa8072;">echo $factors | tr ' ' '\n' | uniq | wc -w</span>)
    <span style="color: #fa8072;">if</span> [ $<span style="color: #7fffd4; font-weight: bold;">num_uniq_factors</span> = 1 ] ; <span style="color: #fa8072;">then</span>
        ((gf_count++))
        <span style="color: #7fffd4; font-weight: bold;">i</span>=$(<span style="color: #fa8072;">echo $line | cut -d: -f1</span>)
        <span style="color: #7fffd4; font-weight: bold;">base</span>=$(<span style="color: #fa8072;">echo $factors | cut -d ' ' -f1</span>)
        <span style="color: #7fffd4; font-weight: bold;">power</span>=$(<span style="color: #fa8072;">echo $factors | wc -w</span>)
        <span style="color: #98fb98; font-weight: bold;">echo</span> <span style="color: #ffa07a;">"${i} = ${base}^${power}"</span>
    <span style="color: #fa8072;">fi</span>
<span style="color: #fa8072;">done</span> &lt; &lt;(seq <span style="color: #ffa07a;">"$limit"</span> | factor)

<span style="color: #7fffd4; font-weight: bold;">gf_percent</span>=$(<span style="color: #fa8072;">echo "2k 100 ${gf_count} * ${limit} / p" | dc</span>)
<span style="color: #98fb98; font-weight: bold;">echo</span> -n <span style="color: #ffa07a;">"${gf_count} Galois fields of order less than or equal to ${limit} "</span>
<span style="color: #98fb98; font-weight: bold;">echo</span> <span style="color: #ffa07a;">"(${gf_percent}%)."</span>
</pre>
</div>


<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Running Stats with Awk</title>
<link>https://remcycles.net/blog/awk_stats.html</link>
<pubDate>Sun, 02 Jun 2024 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/awk_stats.html</guid>
<description>
<![CDATA[<p>
Here's some Awk code to implement the Welford algorithm as described
by <a href="https://www.johndcook.com/blog/standard_deviation/">John D. Cook</a>.  He cites Knuth's TAOCP Vol. 2, 3rd ed., p. 232,
which is recommended reading.  I added a root-mean-square (RMS)
calculation as well, since that is useful for electrical engineering
work.
</p>

<p>
<a href="https://remcycles.net/blog/../files/stats.awk">stats.awk</a>:
</p>
<div class="org-src-container">
<pre class="src src-awk"><span style="color: #add8e6;">#</span><span style="color: #add8e6;">!/usr/bin/awk -f</span>

<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Copyright (C) 2024 Remington Furman</span>
<span style="color: #add8e6;">#</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Permission is hereby granted, free of charge, to any person</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">obtaining a copy of this software and associated documentation files</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">(the "Software"), to deal in the Software without restriction,</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">including without limitation the rights to use, copy, modify, merge,</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">publish, distribute, sublicense, and/or sell copies of the Software,</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">and to permit persons to whom the Software is furnished to do so,</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">subject to the following conditions:</span>
<span style="color: #add8e6;">#</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">The above copyright notice and this permission notice shall be</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">included in all copies or substantial portions of the Software.</span>
<span style="color: #add8e6;">#</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">SOFTWARE.</span>

<span style="color: #add8e6;"># </span><span style="color: #add8e6;">This prints running statistics for a single input variable.</span>
<span style="color: #add8e6;">#</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">It implements the Welford algorithm as described by:</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">https://www.johndcook.com/blog/standard_deviation/</span>
<span style="color: #add8e6;">#</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">It also calculates the root-mean-square (RMS) of the input.</span>

<span style="color: #fa8072;">BEGIN</span> {<span style="color: #7fffd4; font-weight: bold;">OFS</span>=<span style="color: #ffa07a;">", "</span>;        <span style="color: #fa8072;">print</span>  <span style="color: #ffa07a;">"n, x, sum, mean, var, stddev, rms"</span>}
<span style="color: #fa8072;">function</span> <span style="color: #7fffd4; font-weight: bold;">print_stats</span>() {<span style="color: #fa8072;">print</span> <span style="color: #7fffd4; font-weight: bold;">NR</span>, $1, sum, currM, var, <span style="color: #fa8072;">sqrt</span>(var), <span style="color: #fa8072;">sqrt</span>(sum2/<span style="color: #7fffd4; font-weight: bold;">NR</span>)}

<span style="color: #7fffd4; font-weight: bold;">NR</span>==1 {
    sum = prevM = currM = $1
    sum2 = $1 * $1
    var = prevS = 0.0
    print_stats()
}

<span style="color: #7fffd4; font-weight: bold;">NR</span>!=1 {
    sum  += $1
    sum2 += $1 * $1
    currM = prevM + ($1 - prevM)/<span style="color: #7fffd4; font-weight: bold;">NR</span>
    currS = prevS + ($1 - prevM)*($1 - currM)
    prevM = currM
    prevS = currS
    var   = currS/(<span style="color: #7fffd4; font-weight: bold;">NR</span>-1)
    print_stats()
}
</pre>
</div>

<p>
As a quick test, I found that the output has zero error (except an
occasional round-trip floating-point parse error) compared to the
<code>SUM()</code>, <code>AVERAGE()</code>, <code>VAR()</code>, and <code>STDEV()</code> functions in LibreOffice
Calc, when printed with <code>OFMT="%.16g"</code>.  Both gawk and LibreOffice
Calc use double-precision floating point math by default.
</p>

<div class="org-src-container">
<pre class="src src-sh"><span style="color: #fa8072;">for</span> i<span style="color: #fa8072;"> in</span> {1..100} ; <span style="color: #fa8072;">do </span><span style="color: #98fb98; font-weight: bold;">echo</span> $<span style="color: #7fffd4; font-weight: bold;">RANDOM</span> ; <span style="color: #fa8072;">done</span> &gt; rand.txt
gawk -v <span style="color: #7fffd4; font-weight: bold;">OFMT</span>=<span style="color: #ffa07a;">"%.16g"</span> -f ./stats.awk rand.txt &gt; rand_stats.csv
</pre>
</div>

<p>
It also outputs expected values for <a href="https://remcycles.net/blog/./awk_noise.html">Awk Generated White Noise</a> (mean
approximately zero; variariance, standard deviation, and RMS
approximately one), and expected values for a sine wave (mean of zero
and RMS of \(\sqrt{2}\)).
</p>

<p>
Here's a spreadsheet which compares script output and LibreOffice Calc
results on random integers, white noise, and a sine wave:
<a href="https://remcycles.net/blog/../files/awk_stats.ods">awk<sub>stats.ods</sub></a>
</p>

<p>
Fun fact: RMS is the same as standard deviation when the mean is zero.
Check the equations and these two posts for more on that:
</p>
<ul class="org-ul">
<li><a href="https://www.allaboutcircuits.com/technical-articles/how-standard-deviations-relates-rms-values/">https://www.allaboutcircuits.com/technical-articles/how-standard-deviations-relates-rms-values/</a></li>
<li><a href="https://www.allaboutcircuits.com/technical-articles/introduction-to-statistical-noise-analysis-basic-calculations/">https://www.allaboutcircuits.com/technical-articles/introduction-to-statistical-noise-analysis-basic-calculations/</a></li>
</ul>

<p>
John D. Cook also wrote a version of his C++ class that includes
<a href="https://www.johndcook.com/blog/skewness_kurtosis/">skewness and kurtosis</a>.  I don't use them, so adding them to this
script is left as an exercise for the reader.
</p>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Awk: A Short Introduction</title>
<link>https://remcycles.net/blog/awk_presentation.html</link>
<pubDate>Thu, 07 Mar 2019 00:00:00 -0800</pubDate>
<guid>https://remcycles.net/blog/awk_presentation.html</guid>
<description>
<![CDATA[<p>
<a href="https://remcycles.net/blog/../files/awk_presentation.pdf">Awk: A Short Introduction</a>
</p>

<p>
I gave this presentation at a <a href="https://bellingham.codes">Bellingham.Codes</a> meeting on March
7th, 2019.
</p>

<p>
Note: The date is labeled wrong in the slides.  Whoops.  But trying to
re-export the .org file as a .pdf doesn't work with my newer version
of Emacs.
</p>

<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>An Analog Computer Circuit for the SIR Model</title>
<link>https://remcycles.net/blog/SIR_model.html</link>
<pubDate>Mon, 27 Jul 2020 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/SIR_model.html</guid>
<description>
<![CDATA[<style>
.figure-number {
    display: none;
}
</style>


<div id="orgf1889f7" class="figure">
<p><a href="https://remcycles.net/blog/../images/SIR_model_schematic.png" alt="SIR model schematic" width="300"><img src="https://remcycles.net/blog/../images/SIR_model_schematic.png" alt="SIR model schematic" width="300" /></a>
</p>
</div>


<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Finding Anagrams with Persistent Memory Gawk (pm-gawk)</title>
<link>https://remcycles.net/blog/awk_anagrams.html</link>
<pubDate>Tue, 12 Sep 2023 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/awk_anagrams.html</guid>
<description>
<![CDATA[<p>
This was a fun diversion while I was in a hotel room for a work trip.
I realized that I could efficiently determine if two words were
anagrams if I assigned each letter a prime number value and treated
each word as a prime factorization of an integer.  The commutative
property of multiplication means that every word using the same
letters (the anagrams) will multiply to the same number, and that
number will be unique because each letter value is prime.
</p>

<p>
While I was prototyping it with Awk I remembed about the <a href="https://www.gnu.org/software/gawk/manual/pm-gawk/html_node/Introduction.html">Persistent
Memory</a> feature in Gawk which could be used to cache the precomputed
table of integer values for an entire dictionary in a hash table.
Subsequent calls to the script would use the cached hash table for
efficient lookups.  This was perfect, because I've been looking for a
fun practice project for this feature since I first read about it <a href="https://queue.acm.org/detail.cfm?id=3534855">in
ACM's Queue</a> last year.
</p>

<p>
First I counted the letter frequencies in <code>/usr/share/dict/word</code>, and
then assigned the lowest prime numbers to the most frequently occuring
letters.  This isn't necessary, but was fun and easy and minimizes the
numeric value of each word.
</p>

<p>
Here are the assigned letter values:
</p>
<div class="org-src-container">
<pre class="src src-awk"><span style="color: #fa8072;">BEGIN</span> {
    letter_val[<span style="color: #ffa07a;">"e"</span>] = 2
    letter_val[<span style="color: #ffa07a;">"s"</span>] = 3
    letter_val[<span style="color: #ffa07a;">"i"</span>] = 5
    letter_val[<span style="color: #ffa07a;">"a"</span>] = 7
    letter_val[<span style="color: #ffa07a;">"r"</span>] = 11
    letter_val[<span style="color: #ffa07a;">"n"</span>] = 13
    letter_val[<span style="color: #ffa07a;">"t"</span>] = 17
    letter_val[<span style="color: #ffa07a;">"o"</span>] = 19
    letter_val[<span style="color: #ffa07a;">"l"</span>] = 23
    letter_val[<span style="color: #ffa07a;">"c"</span>] = 29
    letter_val[<span style="color: #ffa07a;">"d"</span>] = 31
    letter_val[<span style="color: #ffa07a;">"u"</span>] = 37
    letter_val[<span style="color: #ffa07a;">"g"</span>] = 41
    letter_val[<span style="color: #ffa07a;">"p"</span>] = 43
    letter_val[<span style="color: #ffa07a;">"m"</span>] = 47
    letter_val[<span style="color: #ffa07a;">"h"</span>] = 53
    letter_val[<span style="color: #ffa07a;">"b"</span>] = 59
    letter_val[<span style="color: #ffa07a;">"y"</span>] = 61
    letter_val[<span style="color: #ffa07a;">"f"</span>] = 67
    letter_val[<span style="color: #ffa07a;">"v"</span>] = 71
    letter_val[<span style="color: #ffa07a;">"k"</span>] = 73
    letter_val[<span style="color: #ffa07a;">"w"</span>] = 79
    letter_val[<span style="color: #ffa07a;">"z"</span>] = 83
    letter_val[<span style="color: #ffa07a;">"x"</span>] = 89
    letter_val[<span style="color: #ffa07a;">"j"</span>] = 97
    letter_val[<span style="color: #ffa07a;">"q"</span>] = 101
}
</pre>
</div>

<p>
An example:
</p>

<p>
\[t \cdot a \cdot x \cdot e \cdot s = t \cdot e \cdot x \cdot a \cdot s =\]
\[17 \cdot 7 \cdot 89 \cdot 2 \cdot 3 =
17 \cdot 2 \cdot 89 \cdot 7 \cdot 3 = 63546\]
</p>

<p>
Here's the code that builds the lookup table.  The persistent memory
allocator (PMA) will automatically save both the hash table <code>words</code>
and the function <code>word_val()</code> to a file when the <code>GAWK_PERSIST_FILE</code>
environment variable is set to a file name.  Generating this table
takes about 0.54s on my machine.
</p>
<div class="org-src-container">
<pre class="src src-awk"><span style="color: #add8e6;"># </span><span style="color: #add8e6;">Get the prime values for each letter.</span>
<span style="color: #fa8072;">@include</span> <span style="color: #ffa07a;">"letter_values.awk"</span>

<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Multiply the prime values for each letter in a word.</span>
<span style="color: #fa8072;">function</span> <span style="color: #7fffd4; font-weight: bold;">word_val</span>(word) {
    len = <span style="color: #fa8072;">split</span>(word, letters, <span style="color: #ffa07a;">""</span>)
    val = 1
    <span style="color: #fa8072;">for</span> (i=1; i &lt;= len; i++) {
        val *= letter_val[letters[i]]
    }
    <span style="color: #fa8072;">return</span> val
}

<span style="color: #add8e6;"># </span><span style="color: #add8e6;">Store the word values for each input word in a hash table.</span>
{
    val = word_val($0)
    words[val] = words[val] ? words[val] <span style="color: #ffa07a;">" "</span> $0 : $0
    <span style="color: #fa8072;">print</span> val, words[val]
}
</pre>
</div>


<p>
And here's the code that performs the lookup.  It will automatically
have access to the <code>words</code> hash table and <code>word_val()</code> function when
<code>GAWK_PERSIST_FILE</code> is set.  Therefore the lookup is a single line of
code.  Running this takes about 0.005 seconds on my machine.  Storing
the pre-computed hash table in the PMA file saves 0.54s on each run.
</p>
<div class="org-src-container">
<pre class="src src-awk"><span style="color: #add8e6;"># </span><span style="color: #add8e6;">Look up anagrams for words based on their prime factorization value.</span>
<span style="color: #add8e6;"># </span><span style="color: #add8e6;">This requires a .pma file with words and word_val defined.</span>
{ <span style="color: #fa8072;">print</span> $0 <span style="color: #ffa07a;">" -&gt; "</span> words[word_val($0)] }
</pre>
</div>

<p>
One usage warning: if you run the script interactively
(i.e. <code>./anagram.awk</code>) then you should close it nicely with <code>ctrl-d</code>
(EOF).  If you interrupt it with <code>ctrl-c</code> it will corrupt the PMA heap
and the next run will segfault.  You have to delete the PMA heap file
and rebuild the lookup table after that.
</p>

<p>
Here's a tarball with the source and a Makefile:
</p>

<p>
<a href="https://remcycles.net/blog/../files/anagrams.tar.gz">anagrams.tar.gz</a>
</p>



<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Ada Rendezvous Implemented in C with Pthreads</title>
<link>https://remcycles.net/blog/ada_rendezvous.html</link>
<pubDate>Mon, 12 Apr 2021 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/ada_rendezvous.html</guid>
<description>
<![CDATA[<p>
I've been curious about Ada 2012 ever since I read about it.  I
recently learned that Ada was originally designed for embedded systems
and that piqued my interest even more.  One particularly interesting
Ada feature is language support for tasks (aka threads), including a
built-in scheduler.  The task support includes a feature for
inter-task communication and synchronization called a "rendezvous".
Since I had never used a language with that feature, the concept was a
bit confusing at first.
</p>

<p>
After writing some Go code I realized that the Ada rendezvous was very
similar to using channels to communicate between goroutines.  Both Go
channels and the Ada rendezvous are descendants of Tony Hoare's
Communicating Sequential Processes (CSP), so there's a strong
theoretical basis behind them.
</p>

<p>
The basic idea is that a task can call a procedure provided by another
task, but the code will only run after they have both reached the
"rendezvous".  One task has a rendezvous "entry point" which looks
like a procedure (aka function).  When that task "accepts" the entry
point, it will sleep and wait for another task to call the procedure,
or "enter" the rendezvous.  If a task tries to enter the rendezvous
before the accepting task is ready to accept, then the entering task
will sleep until the accepting task is ready.  In other words, the
first task to reach the rendezvous sleeps until the other task reaches
the rendezvous.  When both tasks are ready, the rendezvous procedure
will run with input parameters passed by the entering task and it will
return values back to the entering task.  Both tasks are synchronized
while the rendezvous code runs, meaning they won't resume executing
their task code until the rendezvous finishes.  Since the two tasks
only exchange data while synchronized there is no need for mutexes.
</p>

<p>
To get an even better understanding of the Ada Rendezvous, I decided
to implement a subset of the functionality in C using Pthreads for the
Rosetta Code project.  I posted my implementation on September 9th,
2020:
</p>

<p>
<a href="https://rosettacode.org/wiki/Rendezvous#Pthreads_implementation">https://rosettacode.org/wiki/Rendezvous#Pthreads_implementation</a>
</p>


<p>
Read more&#x2026;
</p>
]]>
</description></item>
<item>
<title>Awk Generated White Noise (AGWN)</title>
<link>https://remcycles.net/blog/awk_noise.html</link>
<pubDate>Thu, 28 Sep 2023 00:00:00 -0700</pubDate>
<guid>https://remcycles.net/blog/awk_noise.html</guid>
<description>
<![CDATA[<p>
Here's some Awk code to implement the <a href="https://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform">Box-Muller transform</a>to generate
<a href="https://en.wikipedia.org/wiki/Additive_white_Gaussian_noise">Additive White Gaussian Noise (AWGN)</a>.  I found it nice to prototype
this in Awk instead of C or another scripting language.
</p>

<p>
<a href="https://remcycles.net/blog/../files/box_muller.awk">box<sub>muller.awk</sub></a>:
</p>
<div class="org-src-container">
<pre class="src src-awk"><span style="color: #add8e6;">#</span><span style="color: #add8e6;">!/usr/bin/awk -f</span>

<span style="color: #fa8072;">function</span> <span style="color: #7fffd4; font-weight: bold;">bm_normal_rect</span>(z,    u1, u2, r) {
    <span style="color: #fa8072;">do</span> { u1 = <span style="color: #fa8072;">rand</span>() } <span style="color: #fa8072;">while</span> (u1 == 0.0)  <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Avoid log(0).</span>
    u2 = <span style="color: #fa8072;">rand</span>()
    r = <span style="color: #fa8072;">sqrt</span>(-2.0 * <span style="color: #fa8072;">log</span>(u1))
    z[0] = r * <span style="color: #fa8072;">cos</span>(tau * u2)
    z[1] = r * <span style="color: #fa8072;">sin</span>(tau * u2)
}

<span style="color: #fa8072;">function</span> <span style="color: #7fffd4; font-weight: bold;">bm_normal_polar</span>(z,    u1, u2, s, r) {
    <span style="color: #fa8072;">do</span> {
        u1 = (<span style="color: #fa8072;">rand</span>() * 2.0) - 1.0
        u2 = (<span style="color: #fa8072;">rand</span>() * 2.0) - 1.0
        s  = u1*u1 + u2*u2
    } <span style="color: #fa8072;">while</span> (s &gt; 1)

    <span style="color: #fa8072;">if</span> (s == 0.0) {
        z[0] = z[1] = 0.0  <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Avoid division by zero.</span>
    } <span style="color: #fa8072;">else</span> {
        r = <span style="color: #fa8072;">sqrt</span>(-2.0 * <span style="color: #fa8072;">log</span>(s) / s)
        z[0] = u1 * r
        z[1] = u2 * r
    }
}

<span style="color: #fa8072;">BEGIN</span> {
    pi = <span style="color: #fa8072;">atan2</span>(0, -1)
    tau = 2.0*pi

    <span style="color: #fa8072;">delete</span> z[0]  <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Make an empty array for the return values.</span>
    <span style="color: #fa8072;">while</span> (1) {
        bm_normal_rect(z)              <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Faster.</span>
        <span style="color: #add8e6;"># </span><span style="color: #add8e6;">bm_normal_polar(z)           # Slower.</span>
        <span style="color: #fa8072;">printf</span> <span style="color: #ffa07a;">"%a\n%a\n"</span>, z[0], z[1]  <span style="color: #add8e6;"># </span><span style="color: #add8e6;">Hexadecimal float notation, faster</span>
        <span style="color: #add8e6;"># </span><span style="color: #add8e6;">printf "%.17e\n%.17e\n", z[0], z[1]  # Round-trip decimal precision</span>
    }
    <span style="color: #fa8072;">exit</span>
}
</pre>
</div>

<p>
And some example output, using my <a href="https://remcycles.net/blog/./gnuplot.html">GnuPlot wrapper</a>:
</p>
<div class="org-src-container">
<pre class="src src-sh">./box_muller.awk | head -n 10000 | ~/tools/gp_wrap/gp_wrap.sh -t <span style="color: #ffa07a;">" AGWN"</span> -p -w agwn.png
</pre>
</div>


<div id="org3a093a4" class="figure">
<p><img src="https://remcycles.net/blog/../images/agwn.png" alt="agwn.png" />
</p>
</div>

<p>
Interestingly, the polar method is an optimization that avoids \(\sin\)
and \(\cos\), but at least in this Awk implementation the rectangular
method runs faster on my machine (75.9s for 100e6 points) than the
polar method (85.5s for 100e6 points).  Always profile your code when
choosing between optimization stategies.  I haven't done any
statistical tests on either output.
</p>


<p>
Read more&#x2026;
</p>
]]>
</description></item>
</channel>
</rss>
