{
  "version": "https://jsonfeed.org/version/1.1",
  "title": "ctmlr.dev",
  "language": "en",
  "home_page_url": "https://ctmlr.dev",
  "feed_url": "https://ctmlr.dev/feed/feed.json",
  "description": "My coding, computer, and electronics tinkering project log",
  "author": {
    "name": "",
    "url": ""
  },
  "items": [{
      "id": "https://ctmlr.dev/posts/static-site-with-blackblaze-and-cloudflare/",
      "url": "https://ctmlr.dev/posts/static-site-with-blackblaze-and-cloudflare/",
      "title": "Static Website on Backblaze with a Cloudflare Worker",
      "content_html": "<p><picture><source type=\"image/png\" srcset=\"https://ctmlr.dev/img/I4rqZ-z6Bp-300.png 300w, https://ctmlr.dev/img/I4rqZ-z6Bp-580.png 580w\" sizes=\"100vw\" /><source type=\"image/jpeg\" srcset=\"https://ctmlr.dev/img/I4rqZ-z6Bp-300.jpeg 300w, https://ctmlr.dev/img/I4rqZ-z6Bp-580.jpeg 580w\" sizes=\"100vw\" /><img alt=\"CloudFlare DNS custom worker domain\" loading=\"lazy\" decoding=\"async\" src=\"https://ctmlr.dev/img/I4rqZ-z6Bp-300.jpeg\" width=\"580\" height=\"67\" /></picture></p>\n<p>Backblaze offers 10 GB of storage for free and CloudFlare offers free data transfer from backblaze, combining these services you can host a fast and reliable static website with SSL for little to no cost.</p>\n<p>To get started you'll need a public B2 storage bucket in Backblaze and a DNS zone in Cloudflare.</p>\n<h2>Cloudflare Worker</h2>\n<p>This worker script proxies requests to the B2 origin and caches the response on Cloudflare.</p>\n<h3>Add this script under <a href=\"https://dash.cloudflare.com/?to=/:account/workers-and-pages\">Workers &amp; Pages</a></h3>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token punctuation\">{</span><br />  <span class=\"token keyword\">async</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">req<span class=\"token punctuation\">,</span> env<span class=\"token punctuation\">,</span> ctx</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />    <span class=\"token comment\">// Cached response</span><br />    <span class=\"token keyword\">let</span> res <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> caches<span class=\"token punctuation\">.</span>default<span class=\"token punctuation\">.</span><span class=\"token function\">match</span><span class=\"token punctuation\">(</span>req<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>res<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span> res<span class=\"token punctuation\">;</span><br /><br />    <span class=\"token comment\">// Fetch object from origin</span><br />    <span class=\"token keyword\">let</span> reqPath <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">URL</span><span class=\"token punctuation\">(</span>req<span class=\"token punctuation\">.</span>url<span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span>pathname<span class=\"token punctuation\">;</span><br />    reqPath <span class=\"token operator\">=</span> reqPath<span class=\"token punctuation\">.</span><span class=\"token function\">replace</span><span class=\"token punctuation\">(</span><span class=\"token regex\"><span class=\"token regex-delimiter\">/</span><span class=\"token regex-source language-regex\">\\/$</span><span class=\"token regex-delimiter\">/</span></span><span class=\"token punctuation\">,</span> <span class=\"token string\">''</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// Remove trailing slash</span><br />    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>reqPath<span class=\"token punctuation\">.</span><span class=\"token function\">includes</span><span class=\"token punctuation\">(</span><span class=\"token string\">'.'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span> <span class=\"token comment\">// Check file extension</span><br />      reqPath <span class=\"token operator\">+=</span> <span class=\"token string\">'/index.html'</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// Default to index page</span><br /><br />    res <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">ORIGIN</span> <span class=\"token operator\">+</span> reqPath<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />    <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>res<span class=\"token punctuation\">.</span>status <span class=\"token operator\">===</span> <span class=\"token number\">404</span><span class=\"token punctuation\">)</span> <span class=\"token comment\">// Object not found</span><br />      res <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> <span class=\"token function\">fetch</span><span class=\"token punctuation\">(</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">ORIGIN</span> <span class=\"token operator\">+</span> <span class=\"token string\">'/404.html'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br />    <span class=\"token comment\">// Configure content cache</span><br />    res <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Response</span><span class=\"token punctuation\">(</span>res<span class=\"token punctuation\">.</span>body<span class=\"token punctuation\">,</span> res<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />    <span class=\"token keyword\">const</span> ttl <span class=\"token operator\">=</span> res<span class=\"token punctuation\">.</span>headers<span class=\"token punctuation\">.</span><span class=\"token function\">get</span><span class=\"token punctuation\">(</span><span class=\"token string\">'content-type'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">.</span><span class=\"token function\">startsWith</span><span class=\"token punctuation\">(</span><span class=\"token string\">'text'</span><span class=\"token punctuation\">)</span><br />      <span class=\"token operator\">?</span> <span class=\"token number\">14400</span> <span class=\"token operator\">:</span> <span class=\"token number\">31536000</span><span class=\"token punctuation\">;</span> <span class=\"token comment\">// Cache text 4 hours, 1 year default</span><br />    res<span class=\"token punctuation\">.</span>headers<span class=\"token punctuation\">.</span><span class=\"token function\">set</span><span class=\"token punctuation\">(</span><span class=\"token string\">'cache-control'</span><span class=\"token punctuation\">,</span> <span class=\"token string\">'public, max-age='</span> <span class=\"token operator\">+</span> ttl<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br />    <span class=\"token comment\">// Cache and return response</span><br />    ctx<span class=\"token punctuation\">.</span><span class=\"token function\">waitUntil</span><span class=\"token punctuation\">(</span>caches<span class=\"token punctuation\">.</span>default<span class=\"token punctuation\">.</span><span class=\"token function\">put</span><span class=\"token punctuation\">(</span>req<span class=\"token punctuation\">,</span> res<span class=\"token punctuation\">.</span><span class=\"token function\">clone</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />    <span class=\"token keyword\">return</span> res<span class=\"token punctuation\">;</span><br />  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre>\n<h3>Configure these worker settings</h3>\n<p><picture><source type=\"image/png\" srcset=\"https://ctmlr.dev/img/vCvgQs9925-300.png 300w, https://ctmlr.dev/img/vCvgQs9925-580.png 580w\" sizes=\"100vw\" /><source type=\"image/jpeg\" srcset=\"https://ctmlr.dev/img/vCvgQs9925-300.jpeg 300w, https://ctmlr.dev/img/vCvgQs9925-580.jpeg 580w\" sizes=\"100vw\" /><img alt=\"Cloudflare worker settings for Domains &amp; Routes and Variables and Secrets\" loading=\"lazy\" decoding=\"async\" src=\"https://ctmlr.dev/img/vCvgQs9925-300.jpeg\" width=\"580\" height=\"420\" /></picture></p>\n<ol>\n<li><code>Route</code> all requests through the worker</li>\n<li><code>Custom domain</code> creates a DNS record</li>\n<li><code>ORIGIN</code> is the public bucket URL<br /><code>https://f002.backblazeb2.com/file/&lt;BUCKET_NAME&gt;</code></li>\n</ol>\n",
      "date_published": "2024-01-16T00:00:00Z"
    },{
      "id": "https://ctmlr.dev/posts/7900xtx-h210-mini-itx-bracket/",
      "url": "https://ctmlr.dev/posts/7900xtx-h210-mini-itx-bracket/",
      "title": "7900 XTX in a Mini-ITX Case",
      "content_html": "<p><picture><source type=\"image/png\" srcset=\"https://ctmlr.dev/img/EwhfMzSC8F-300.png 300w, https://ctmlr.dev/img/EwhfMzSC8F-580.png 580w\" sizes=\"100vw\" /><source type=\"image/jpeg\" srcset=\"https://ctmlr.dev/img/EwhfMzSC8F-300.jpeg 300w, https://ctmlr.dev/img/EwhfMzSC8F-580.jpeg 580w\" sizes=\"100vw\" /><img alt=\"A computer case with a window on the side lit with LED lights displaying the graphics card\" loading=\"lazy\" decoding=\"async\" class=\"icon\" src=\"https://ctmlr.dev/img/EwhfMzSC8F-300.jpeg\" width=\"580\" height=\"471\" /></picture></p>\n<p>I like the portability of mini-ITX case and the NZXT H210 has room for a full-size power supply and graphics card but is still reasonably luggable. However I ran into trouble when I brought home a Gigabyte 7900 XTX, the mounting bracket provided only works in a fullsize ATX case.</p>\n<p>To solve this I made a custom 3D-printed support bracket in FreeCAD, it mounts the card to the front of the case with some heat-set inserts and M3 hardware.</p>\n<p><picture><source type=\"image/png\" srcset=\"https://ctmlr.dev/img/iY5jKRHVCA-300.png 300w, https://ctmlr.dev/img/iY5jKRHVCA-580.png 580w\" sizes=\"100vw\" /><source type=\"image/jpeg\" srcset=\"https://ctmlr.dev/img/iY5jKRHVCA-300.jpeg 300w, https://ctmlr.dev/img/iY5jKRHVCA-580.jpeg 580w\" sizes=\"100vw\" /><img alt=\"A rectangular 3D printed bracket with three holes to mount to the graphics card and two threaded heat-set inserts on each side to mount to the front of the case\" loading=\"lazy\" decoding=\"async\" src=\"https://ctmlr.dev/img/iY5jKRHVCA-300.jpeg\" width=\"580\" height=\"377\" /></picture></p>\n<h2>Files</h2>\n<ul>\n<li><a href=\"https://ctmlr.dev/content/doc/NZXT-H210-7900XTX-bracket.stl\">NZXT-H210-7900XTX-bracket.stl</a></li>\n<li><a href=\"https://ctmlr.dev/content/doc/NZXT-H210-7900XTX-bracket.FCStd\">NZXT-H210-7900XTX-bracket.FCStd</a></li>\n</ul>\n<h2>Parts</h2>\n<ul>\n<li>2x M3x4 Heat-set Inserts</li>\n<li>6x M3x6 Bolts</li>\n<li>6x M3 Washers</li>\n</ul>\n<p><em>Print with 100% infill</em></p>\n<p><picture><source type=\"image/png\" srcset=\"https://ctmlr.dev/img/welsRaqeUk-300.png 300w, https://ctmlr.dev/img/welsRaqeUk-580.png 580w\" sizes=\"100vw\" /><source type=\"image/jpeg\" srcset=\"https://ctmlr.dev/img/welsRaqeUk-300.jpeg 300w, https://ctmlr.dev/img/welsRaqeUk-580.jpeg 580w\" sizes=\"100vw\" /><img alt=\"Case with front panel removed showing the custom bracket bolted to the front of the card and the case\" loading=\"lazy\" decoding=\"async\" src=\"https://ctmlr.dev/img/welsRaqeUk-300.jpeg\" width=\"580\" height=\"278\" /></picture></p>\n",
      "date_published": "2023-09-29T00:00:00Z"
    },{
      "id": "https://ctmlr.dev/posts/discord-pi-audio-capture/",
      "url": "https://ctmlr.dev/posts/discord-pi-audio-capture/",
      "title": "Audio Capture Discord Bot on a Pi",
      "content_html": "<p><picture><source type=\"image/png\" srcset=\"https://ctmlr.dev/img/wEdX6D_IO9-300.png 300w, https://ctmlr.dev/img/wEdX6D_IO9-580.png 580w\" sizes=\"100vw\" /><source type=\"image/jpeg\" srcset=\"https://ctmlr.dev/img/wEdX6D_IO9-300.jpeg 300w, https://ctmlr.dev/img/wEdX6D_IO9-580.jpeg 580w\" sizes=\"100vw\" /><img alt=\"A rasberry pi and a USB audio capture device mounted next to a TV on the wall\" loading=\"lazy\" decoding=\"async\" class=\"icon\" src=\"https://ctmlr.dev/img/wEdX6D_IO9-300.jpeg\" width=\"580\" height=\"334\" /></picture></p>\n<p>In our computer room we have a TV but you can't hear it with headphones on. With a Raspberry Pi and a Griffin iMic USB audio adapter I'm able to capture stereo audio and stream it into Discord.</p>\n<h3>Capture and stream the audio with <a href=\"https://www.npmjs.com/package/mic\">mic</a> and <a href=\"https://www.npmjs.com/package/discord.js\">discord.js</a></h3>\n<pre class=\"language-js\"><code class=\"language-js\"><span class=\"token keyword\">const</span> mic <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'mic'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token keyword\">const</span> Discord <span class=\"token operator\">=</span> <span class=\"token function\">require</span><span class=\"token punctuation\">(</span><span class=\"token string\">'discord.js'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br /><span class=\"token keyword\">const</span> config <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span><br />  <span class=\"token literal-property property\">mic</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br />    <span class=\"token literal-property property\">rate</span><span class=\"token operator\">:</span> <span class=\"token number\">48000</span><span class=\"token punctuation\">,</span><br />    <span class=\"token literal-property property\">channels</span><span class=\"token operator\">:</span> <span class=\"token number\">2</span><span class=\"token punctuation\">,</span><br />    <span class=\"token literal-property property\">device</span><span class=\"token operator\">:</span> <span class=\"token string\">\"plughw:CARD=system,DEV=0\"</span><br />  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">,</span><br />  <span class=\"token literal-property property\">discord</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span><br />    <span class=\"token literal-property property\">token</span><span class=\"token operator\">:</span> <span class=\"token string\">\"&lt;bot-token>\"</span><span class=\"token punctuation\">,</span><br />    <span class=\"token literal-property property\">guild</span><span class=\"token operator\">:</span> <span class=\"token string\">\"&lt;server-name>\"</span><span class=\"token punctuation\">,</span><br />    <span class=\"token literal-property property\">channel</span><span class=\"token operator\">:</span> <span class=\"token string\">\"&lt;channel-name>\"</span><br />  <span class=\"token punctuation\">}</span><br /><span class=\"token punctuation\">}</span><br /><br /><span class=\"token keyword\">const</span> client <span class=\"token operator\">=</span> <span class=\"token keyword\">new</span> <span class=\"token class-name\">Discord<span class=\"token punctuation\">.</span>Client</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />client<span class=\"token punctuation\">.</span><span class=\"token function\">login</span><span class=\"token punctuation\">(</span>config<span class=\"token punctuation\">.</span>discord<span class=\"token punctuation\">.</span>token<span class=\"token punctuation\">)</span><br /><span class=\"token punctuation\">.</span><span class=\"token function\">catch</span><span class=\"token punctuation\">(</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br />  console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Unable to log in with provided token.'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  process<span class=\"token punctuation\">.</span><span class=\"token function\">exit</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br /><span class=\"token comment\">// Start audio capture</span><br /><span class=\"token keyword\">let</span> micInstance <span class=\"token operator\">=</span> <span class=\"token function\">mic</span><span class=\"token punctuation\">(</span>config<span class=\"token punctuation\">.</span>mic<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token keyword\">let</span> audioStream <span class=\"token operator\">=</span> micInstance<span class=\"token punctuation\">.</span><span class=\"token function\">getAudioStream</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br />client<span class=\"token punctuation\">.</span><span class=\"token function\">on</span><span class=\"token punctuation\">(</span><span class=\"token string\">'ready'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br />  <span class=\"token comment\">// Filter channels down to voice channels in the guild</span><br />  <span class=\"token keyword\">let</span> channels <span class=\"token operator\">=</span> client<span class=\"token punctuation\">.</span>channels<span class=\"token punctuation\">.</span><span class=\"token function\">filter</span><span class=\"token punctuation\">(</span> <span class=\"token parameter\">channel</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br />    <span class=\"token keyword\">return</span> channel<span class=\"token punctuation\">.</span>guild<span class=\"token punctuation\">.</span>name <span class=\"token operator\">===</span> config<span class=\"token punctuation\">.</span>discord<span class=\"token punctuation\">.</span>guild <span class=\"token operator\">&amp;&amp;</span> channel<span class=\"token punctuation\">.</span>type <span class=\"token operator\">===</span> <span class=\"token string\">'voice'</span><span class=\"token punctuation\">;</span><br />  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br />  <span class=\"token comment\">// Find channel by name</span><br />  <span class=\"token keyword\">let</span> channel <span class=\"token operator\">=</span> channels<span class=\"token punctuation\">.</span><span class=\"token function\">find</span><span class=\"token punctuation\">(</span><span class=\"token string\">'name'</span><span class=\"token punctuation\">,</span> config<span class=\"token punctuation\">.</span>discord<span class=\"token punctuation\">.</span>channel<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br />  <span class=\"token keyword\">if</span><span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>channel<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span><br />    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token string\">Unable to find voice channel </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>config<span class=\"token punctuation\">.</span>discord<span class=\"token punctuation\">.</span>channel<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> in </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>config<span class=\"token punctuation\">.</span>discord<span class=\"token punctuation\">.</span>guild<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />    process<span class=\"token punctuation\">.</span><span class=\"token function\">exit</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <span class=\"token punctuation\">}</span><br /><br />  <span class=\"token comment\">// Connect to the channel</span><br />  channel<span class=\"token punctuation\">.</span><span class=\"token function\">join</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><br />  <span class=\"token punctuation\">.</span><span class=\"token function\">then</span><span class=\"token punctuation\">(</span> <span class=\"token parameter\">connection</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br />    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Connected...'</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><br />    <span class=\"token comment\">// Start the audio stream</span><br />    connection<span class=\"token punctuation\">.</span><span class=\"token function\">playConvertedStream</span><span class=\"token punctuation\">(</span> audioStream <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />    micInstance<span class=\"token punctuation\">.</span><span class=\"token function\">start</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><br />  <span class=\"token punctuation\">.</span><span class=\"token function\">catch</span><span class=\"token punctuation\">(</span> <span class=\"token parameter\">error</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span><br />    console<span class=\"token punctuation\">.</span><span class=\"token function\">log</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Unable to connect to the voice channel'</span><span class=\"token punctuation\">,</span> error<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />    process<span class=\"token punctuation\">.</span><span class=\"token function\">exit</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br />  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span><br /><span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre>\n",
      "date_published": "2018-04-08T00:00:00Z"
    },{
      "id": "https://ctmlr.dev/posts/junk-bin-antenna-tuner/",
      "url": "https://ctmlr.dev/posts/junk-bin-antenna-tuner/",
      "title": "Junk Bin Antenna Tuner",
      "content_html": "<p>I put a G5RV antenna up to try out my Yeasu FT-900 however I found that the internal tuner didn't have enough range to match this antenna. In a hurry to get on the air, and on a college kid budget, I threw together a junk bin L network antenna tuner to get it going.</p>\n<p><picture><source type=\"image/png\" srcset=\"https://ctmlr.dev/img/bCcQB7yBFw-300.png 300w, https://ctmlr.dev/img/bCcQB7yBFw-580.png 580w\" sizes=\"100vw\" /><source type=\"image/jpeg\" srcset=\"https://ctmlr.dev/img/bCcQB7yBFw-300.jpeg 300w, https://ctmlr.dev/img/bCcQB7yBFw-580.jpeg 580w\" sizes=\"100vw\" /><img alt=\"A makeshift antenna tuner on a breadboard with a variable capacitor and an inductor made from wire wrapped around a cardboard tube\" loading=\"lazy\" decoding=\"async\" src=\"https://ctmlr.dev/img/bCcQB7yBFw-300.jpeg\" width=\"580\" height=\"495\" /></picture></p>\n<p>The variable inductor is wound with solid core 14 gauge wire around a cardboard tube with taps at regular intervals. The inductor value can be tuned by connecting an alegator clip at different points. The variable capacitor was scrapped out of an old tube AM radio and the coax connectors were pulled from some junk CB radios.</p>\n<p>The capacitance range isn't quite enough with the variable capacitor so I added additional capacitors in parallel. With this makeshift tuner I was able to get the SWR down to just under 1.5 on the G5RV antenna using the radio's internal tuner to fine tune the impedance match. I had to keep the transmit power below 50 watts but I was able to make contacts on 80, 40, and 20 meters.</p>\n",
      "date_published": "2012-12-16T00:00:00Z"
    },{
      "id": "https://ctmlr.dev/posts/simple-am-transmitter-receiver/",
      "url": "https://ctmlr.dev/posts/simple-am-transmitter-receiver/",
      "title": "Simple AM Shortwave Transmitter",
      "content_html": "<p><video src=\"https://ctmlr.dev/content/video/shortwave-am-transmitter-receiver.webm\" poster=\"https://ctmlr.dev/content/video/shortwave-am-transmitter-receiver.webm.jpg\" alt=\"Transmitting music to the reciver circuit\" controls=\"\" class=\"video\" loading=\"lazy\"></video></p>\n<p>I was experimenting with RF oscillator circuits and built a simple low power shortwave transmitter and reciver set with minimal parts and complexity.</p>\n<h2>Transmitter</h2>\n<p><a href=\"https://ctmlr.dev/img/shortwave-am-transmitter-circuit.png\" target=\"_blank\" rel=\"noopener\"><picture><source type=\"image/png\" srcset=\"https://ctmlr.dev/img/aRL_nbEL7h-300.png 300w, https://ctmlr.dev/img/aRL_nbEL7h-580.png 580w\" sizes=\"100vw\" /><source type=\"image/jpeg\" srcset=\"https://ctmlr.dev/img/aRL_nbEL7h-300.jpeg 300w, https://ctmlr.dev/img/aRL_nbEL7h-580.jpeg 580w\" sizes=\"100vw\" /><img alt=\"An AM modulated Heartly oscillator circuit\" loading=\"lazy\" decoding=\"async\" class=\"diagram\" src=\"https://ctmlr.dev/img/aRL_nbEL7h-300.jpeg\" width=\"580\" height=\"463\" /></picture></a></p>\n<p>The transmitter is made with a Hartley oscillator. Transistor Q1 provides feedback to sustain the resonant LC tank circuit and Q2 modulates the signal by attenuating the oscillator's output to modulate the amplitude. This is a very simple design with no amplification and does not transmit very far.</p>\n<h2>Receiver</h2>\n<p>The <a href=\"https://www.cxi1.co.uk/Circuits/rf/amrec.htm\">AM receiver</a> is also very simple with only three standard NPN transistors total. In place of the 120k regenerative feedback resistor I used a vairable resistor for fine tuning the gain.</p>\n<h2>Tank Circuit</h2>\n<p>The resonant frequency of the transmitter and receiver is determined by the inductor <strong>L</strong> and the capacitance <strong>C</strong> values in the <a href=\"https://www.allaboutcircuits.com/textbook/alternating-current/chpt-6/parallel-tank-circuit-resonance/\">tank circuit</a>.</p>\n<p>$$ f = \\frac{1}{2\\pi\\sqrt{LC}} $$</p>\n<p>I measured my variable capacitor's max value 290 pF and made coils that are roughly 1.78 µH which makes the tank circuit resonant in the 7 MHz shortwave band.</p>\n<h3>Calculating the Inductance Value</h3>\n<p>The resonant frequency formula can be used to find the inductance <strong>L</strong> value</p>\n<p>$$ L = \\frac{1}{(2\\pi f)^2 C} $$</p>\n<p>Using $ f = 7$ MHz and $C = 290$ pF</p>\n<p>$$ L = \\frac{1}{(2\\pi \\times 7 \\times 10^6)^2 \\times 290 \\times 10^{-12}} $$</p>\n<p>$ L = 1.783$ µH</p>\n<h3>Making an Inductor</h3>\n<p>I made an inductor by wrapping enamel copper wire around a quarter inch diameter soda straw.</p>\n<p>I used this formula to find the value of an air-core inductor</p>\n<p>$$ L = \\frac{d^2 \\cdot n^2}{18d+40l} $$</p>\n<ul>\n<li>$L$ is inductance in uH</li>\n<li>$d$ is coil diameter in inches</li>\n<li>$l$ is coil length in inches</li>\n<li>$n$ is number of turns.</li>\n</ul>\n<p>Experimenting with some values I found these dimensions bring me close to my target inductance.</p>\n<table>\n<thead>\n<tr>\n<th></th>\n<th></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Diameter</td>\n<td>$1/4$&quot;</td>\n</tr>\n<tr>\n<td>Length</td>\n<td>$3/4$&quot;</td>\n</tr>\n<tr>\n<td>Turns</td>\n<td>$31$</td>\n</tr>\n</tbody>\n</table>\n",
      "date_published": "2010-05-09T00:00:00Z"
    },{
      "id": "https://ctmlr.dev/posts/digital-clock/",
      "url": "https://ctmlr.dev/posts/digital-clock/",
      "title": "Digital Clock with TTL Counters",
      "content_html": "<p><picture><source type=\"image/png\" srcset=\"https://ctmlr.dev/img/FrX7GJHZXF-300.png 300w, https://ctmlr.dev/img/FrX7GJHZXF-580.png 580w\" sizes=\"100vw\" /><source type=\"image/jpeg\" srcset=\"https://ctmlr.dev/img/FrX7GJHZXF-300.jpeg 300w, https://ctmlr.dev/img/FrX7GJHZXF-580.jpeg 580w\" sizes=\"100vw\" /><img alt=\"A through hole breadboard digital clock circuit\" loading=\"lazy\" decoding=\"async\" src=\"https://ctmlr.dev/img/FrX7GJHZXF-300.jpeg\" width=\"580\" height=\"482\" /></picture></p>\n<p>I was playing around with some 7490 decade counters and ended up building a digital clock.</p>\n<p>The first trick was getting an accurate 1 second time base. There are a few options here, you can divide the 60 Hz AC line frequency down to 1 Hz or you can build a crystal oscillator and divide that frequency down with more counters. With limited space on this breadboard I ended up taking a 1 Hz oscillator circuit out of an analog quartz clock I found in the junk box.</p>\n<p>There are a few <a href=\"https://web.archive.org/web/20210309185613/http://www.josepino.com/?one_second_timebase\">different ways you can wire these</a> quratz clock circuits. It took some experimentation to find a configuration that worked. With my clock I didn't have to run the outputs through diodes or transistors. Each output is ½ Hz and simply wiring them together worked just fine. I powered this oscillator from the 5 volt supply by wiring a current limiting diode, in this case an LED, across the power connections. This added an unexpected &quot;feature&quot; where the LED blinks off every second.</p>\n<p><a href=\"https://ctmlr.dev/img/digital-clock-schematic.png\" target=\"_blank\" rel=\"noopener\"><picture><source type=\"image/png\" srcset=\"https://ctmlr.dev/img/2zKDwzvq5Y-300.png 300w, https://ctmlr.dev/img/2zKDwzvq5Y-580.png 580w\" sizes=\"100vw\" /><source type=\"image/jpeg\" srcset=\"https://ctmlr.dev/img/2zKDwzvq5Y-300.jpeg 300w, https://ctmlr.dev/img/2zKDwzvq5Y-580.jpeg 580w\" sizes=\"100vw\" /><img alt=\"Circuit diagram for the digital clock\" loading=\"lazy\" decoding=\"async\" class=\"diagram\" src=\"https://ctmlr.dev/img/2zKDwzvq5Y-300.jpeg\" width=\"580\" height=\"286\" /></picture></a></p>\n<p>The time is kept by six 7490 decade counters. The 1 Hz clock goes into a 7490 wired up as a mod 10 counter (for seconds 0-9). The output of the mod 10 counter then goes into a 7490 wired as a mod 6 counter (for seconds 0-5). That circuit is then duplicated for the minutes (0-59). The hours are then counted by two 7490s wired up as a mod 24 counter (0-23).</p>\n<p>The tens of seconds are displayed by 3 LEDs in binary. The 7 segment displays are driven by four 4511 BCD-to-7 segment decoders. I needed thirty-three 100 Ohm resistors in total for all the displays and LEDs.</p>\n",
      "date_published": "2010-04-01T00:00:00Z"
    }
  ]
}
