What a view. . .

What a view. . .

Saturday, December 20, 2014

pyFmRadio - Radio Broadcast Data System (RBDS) & Radio Data System (RDS)

I decided to add one last bit of functionality to my first Software Defined Radio (SDR) project - pyFmRadio.  There happens to be a low bit-rate digital signal hidden away in the FM spectrum known as Radio Broadcast Data System (RBDS) also known as Radio Data System (RDS) outside the United States.  I added a receiver for this signal to pyFmRadio.

The RBDS signal operates at 1187.5bps and if you account for the embedded block error correction code you wind up at a data rate of 730bps (1187.5 * 16/26).  What is neat about this signal is that it carries some metadata about the radio station and the current broadcast (song, artist, DJ, etc).  A handful of car radios display this data.  Apparently it is/was more prevalent in Europe than the US.

I chose to add this functionality because I wanted to learn a little bit about the mechanics of decoding a (albeit primitive) digital signal.  Some highlights of the signal include pulse-shaped BPSK modulation, Manchester coding, and cyclic block error correction coding,

Spectrum Details

Below is a cartoon image of a broadcast FM radio station's demodulated spectrum.  Off to the right, centered at 57KHz, is the RBDS (RDS) signal.  Note, 57KHz happens to be the third harmonic of the pilot tone.  This comes in handy when demodulating the signal.  The bandwidth of the RBDS signal is approximately 4.8KHz.

Cartoon Illustration of FM Spectrum Single Sideband

Below are two images from a real demodulated FM station highlighting the RBDS signal.

FM Station After Demodulation
Zoom in on RBDS Signal From Above Plot

Modulation Details

The carrier frequency of the RBDS signal is locked to the third harmonic of the 19KHz pilot tone at 57KHz.  You can see this in the above plots.  The RBDS signal is centered at 57KHz.  The signal is also phase locked.  According to the RBDS standard, the signal could also be phase locked w/an offset of 90 degrees.

The RBDS spectrum shown above is the product of a pulse-shaped BPSK signal.  The pulse shaping applied to the signal is that of a root raised cosine filter (RRC).  The root raised cosine filter is commonly used in communication systems on both the receive and transmit side.  The filter helps to bandlimit the signal and when combined with a RRC filter in the receiver, creates a raised cosine filter that reduces the inter-symbol interference (ISI) of the communications channel.  Below is a picture of the pulse-shaped BPSK RBDS signal in the time domain.

Magnitude of RBDS Signal in Time Domain

Receiver Details

The first step of an RBDS receiver is to perform the carrier and subcarrier demodulation.  First the carrier is FM demodulated.  Then the pilot tone is tripled and used to down-mix the subcarrier.  Next the resulting signal is low-pass filtered and decimated using an efficient polyphase implementation.  What is left is a baseband modulated signal.  This entire process is detailed in the image below.

Carrier and Subcarrier Demodulation

The next step in the receiver is baseband demodulation.  This step involves matched filtering, symbol synchronization, carrier synchronization, and differential Manchester decoding.  Data bits are the output. The image below illustrates this process.

Baseband Demodulation

First up in baseband demodulation is matched filtering.  The basebanded signal is match filtered using a root raised cosine filter.  Since the transmitted signal was also filtered using a root raised cosine filter, the overall result is that of a raised cosine which helps mitigate inter-symbol interference.  Below are images of the root raised cosine matched filter impulse response, the filter frequency response, and the RBDS signal after matched filtering.
Root Raised Cosine Impulse Response
Root Raised Cosine Frequency Response
Match Filtered RBDS Signal

Next the receiver performs timing recovery also known as symbol synchronization.  The receiver must know where to sample the match filtered signal to recover the symbol bits.  Nominally, an RBDS signal has a symbol rate of 2375 symbols/sec.   At the 25KHz rate of the basebanded signal, this corresponds to ~10.5 samples per symbol.  In the image directly above there are peaks and valleys.  The peaks represent symbol times.

A magnitude based symbol synchronization technique known as an "Early-Late" algorithm was chosen to perform the synchronization.  Such a method does not require carrier synchronization prior to symbol synchronization. The image below below illustrates a symbol synchronized state where only peaks are selected.  The red circles represent the samples selected for each symbol.  There are approximately 10.5 samples between each of the circles.  The output of this process is 2375 symbols/sec.
Match Filtered RBDS Signal With Symbol Synchronization

Symbol synchronization is followed by carrier synchronization.  While the signal was previously basebanded (nearly basebanded) by triple the pilot tone, there may still exist a small frequency offset and phase offset that prohibits demodulating the BPSK signal.  If the receiver attempted to convert the sampled symbols to data bits prior to carrier synchronization the process would fail.  This is easily observed by looking at a constellation diagram of the signal prior to carrier synchronization.
Unlocked Constellation Diagram

Removing these offsets is accomplished by a variation of a Costas loop.  The loop implementation is shown in the baseband demodulation diagram above.  Once the Costas loop has synchronized to the carrier, the BPSK signal can be properly decoded.  Constellation diagrams after synchronization are given below.  The first diagram shows the behavior of the receiver at the beginning stages of synchronization.  Notice the "swirls" while the loop acquires synchronization.  Once the loop is locked (carrier synchronized), the constellation diagram looks like the second.
Carrier Locking Constellation Diagram
Carrier Locked Constellation Diagram

The last step before data bits can be recovered is to perform differential Manchester decoding.  Differential Manchester encoding has the benefit that during decoding, the process is resilient to signal/phase inversion.  The process uses transitions and not absolute polarity to decode.

Receiver Bitstream Details

Now that the bits are extracted, the receiver must perform block synchronization in order to identify the data encoded by the bits.  The RBDS bitstream is made up of "groups" of 104 bits.  Each group is made up of four blocks.  Each block is made up of 26 bits and of those 26 bits, 16 are information bits and 10 are checkword bits.  Below is a snippet from the RBDS standard document illustrating this structure.

RBDS Standard Block Definition 

The 10 bits that make up the checkword are used for error correction.  However, the checkword is also "stamped" with an offset word prior to transmission.  Each block has a defined offset word applied to it.  The purpose of adding a defined offset word to each checkword is to allow the receiver to synchronize or identify the blocks.

Block Synchronization

Specific information and data is encoded in each block.  Hence it is important to synchronize and identify blocks in the bitstream.  Synchronization and block identification is accomplished by performing a block search routine.  Once synchronized, the receiver can commence decoding.

The block search routine incrementally checks the bits in the bitstream and looks for a particular syndrome.  A syndrome is a special signature that a parity check algorithm produces.  The parity check algorithm is part of the error correction process that is dual-purposed for block synchronization.  If the offset word were not applied to the checkword, the parity check algorithm would produce a predictable '0' at its output if the block contained no errors.  Adding an offset to each checkword purposefully adds an error to the block.  Now when the parity check algorithm is run on the block (now with an intentional error), it produces a non-zero output.  The value of the output (called a syndrome) depends on the error introduced.  Each block has a unique error and hence a unique syndrome.  Once a valid syndrome is found in the search routine, block synchronization is achieved and block decoding can commence.

The parity check algorithm is performed by application of a parity check matrix.  This matrix is specific to the error correction code.  It is a 26x10 matrix.  The 1x26 data vector is multiplied by the parity check matrix (bit addition is accomplished by xoring).  The output of this multiplication is the syndrome.

Error Correction

The error correction routine uses a burst-error-correcting shortened cyclic code.  This is a (26,16) block code that is able to correct burst errors (continuous errors) up to five bits in length.  Prior to running the error correction (and detection) algorithm, the syndrome corresponding to the offset word is removed from the calculated syndrome so that only unintentional errors are present in the syndrome.

One way to implement this error correction algorithm can be done via a look-up-table (LUT).  Syndromes and their corresponding error vectors for all of the possible correctable error vectors can be calculated ahead of time.  This information is stored into a LUT.  At run-time, the receiver calculates the syndrome corresponding to the current 26 bits in a block.  If the syndrome is zero, there is no error (or the error is not detectable).  If the syndrome is non-zero, the LUT is searched for that particular syndrome and if found the error vector also in the LUT is used to correct the block error.  If the syndrome is not present in the LUT, the error was detectable but not correctable.

Another method of performing error correction (and detection) from a cyclic code is to use the Meggitt algorithm.  This is the particular algorithm that is given in the RBDS Standard.  The Meggitt algorithm is an incremental shift-register based error correction/detection algorithm.  The Meggitt algorithm is the method implemented in the pyRmRadio RBDS receiver.



Code



Good References:

http://www.nrscstandards.org/DocumentArchive/NRSC-4-A%20Standard%202005.pdf

http://www.nrscstandards.org/documentarchive/NRSC-4-A%20Annexes%202005.pdf

The care and feeding of digital, pulse-shaping filters [Local Mirror]

Digital Pulse-Shaping Filter Basics [Local Mirror]
http://www.analog.com/static/imported-files/application_notes/AN-922.pdf

Digital Filtering Part 2: Pulse Shaping [Local Mirror]
http://cmclab.rice.edu/433/slides/4-FilteringPart2.pdf

Matched Filtering and Timing Recoveryin Digital Receivers [Local Mirror]
mobiledevdesign.com/images/archive/0901Litwin32.pdf

Synchronisation in Digital Receivers [Local Mirror]
http://www.cs.tut.fi/kurssit/TLT-5806/Synch.pdf

Symbol Timing Recovery for QPSK Digital Modulations [Local Mirror]
http://www.gaussianwaves.com/2013/11/symbol-timing-recovery-for-qpsk-digital-modulations/

An Introduction to Error Correcting Codes [Local Mirror]
http://circuit.ucsd.edu/~tjavidi/ECE154C/154C/Lecture_Notes_files/ErrorCorrectionI.pdf

Decoding of Cyclic Codes and Intro to BCH Codes [Local Mirror]
http://www.site.uottawa.ca/~damours/courses/ELG_5372/Lecture15.pdf

Cyclic Codes [Local Mirror]
wits.ice.nsysu.edu.tw/course/pdfdownload/95.../CC-04-CyclicCode.pdf



Sunday, November 2, 2014

EngNote - ADCs & Dithering: When adding noise is a good thing

The concept of dithering seems counter-intuitive. In short, you add noise to improve performance. Why does this work, what performance are you getting by adding noise? An example that I commonly deal with is combating quantization noise and its resulting impacts to an ADC's spurious free dynamic range (SFDR).

Quantization Overview

Let's assume we have a 3bit ADC. This ADC only has 8 unique values it can produce. An input signal gets mapped to a uniform grid (in an ideal ADC) of 8 distinct values, which is a non-linear operation. The result of this operation is quantization noise. Below is an illustration.

Quantization Noise Resulting from Sinusoidal Inputs

When an ADC is operating with sinusoidal inputs, the quantization error it produces ends up manifesting itself as spurious content in the spectrum of the digital output.  The spurious content is bad because the spurs themselves cannot be averaged out and can limit dynamic range by masking other weaker signals that may be present.

Quantization noise impacts depend on the input frequency.  There are some interesting things that result from this dependence.  As an example, consider an input frequency of fs/4 (the ADC's sampling rate divided by four).  The quantization noise creates spurious content at a single frequency which happens to be at exactly that of the input signal, fs/4.  Note the amplitude of the spur is also dependent on the phase of the signal relative to the ADC sampling points.  To see this behavior and phase dependence, try an example with a signal that is in-phase with the ADC sampling points and then again with a signal that has a phase offset.


# Fs/4 Example - 0deg phase
fs = 100;
ts = 1/fs;
endTime = 100;
time = np.linspace(0,endTime-ts,endTime*fs);
freq = fs/4;
numBits = 8;
# Generate signals
sig = np.sin(2*np.pi*freq*time);
quantSig = np.round(sig*2**(numBits-1))/2**(numBits-1);
# Fs/4 Example - 45deg phase
fs = 100;
ts = 1/fs;
endTime = 100;
time = np.linspace(0,endTime-ts,endTime*fs);
freq = fs/4;
numBits = 8;
# Generate signals
sig = np.sin(2*np.pi*freq*time+np.pi/4);
quantSig = np.round(sig*2**(numBits-1))/2**(numBits-1);

A more common situation is when the sinusoidal input is not an integer division of the sampling frequency.  In this case, spurs are spread across the spectrum.  There is a pattern to this whole madness but I don't have the specifics worked out yet.

The commonly used Signal to Quantization Noise Ratio Equation makes an assumption about the spectrum of the quantization noise.  The assumption is that the quantization error can be approximated by an uncorrelated saw-tooth waveform.  When dealing with sinusoidal inputs at specific frequency/phase combinations such as the example above, those assumptions do not hold.

$ SQNR_{dB}=6.02*numBits+1.76 $
Commonly Used Signal to Quantization Noise Ratio Equation

How Dithering Helps

So how does dithering, the act of adding random noise, help?  Often times to find signals below the noise floor of an ADC, "to dig really low", we integrate over many ADC samples to obtain processing gain.  However, if there are quantization spurs generated by another higher power signal going into the ADC, the low power signal being looked for may be corrupted or overlooked because of the quantization noise spurs that cannot be averaged out.  The act of dithering helps this process by decorrelating the quantization noise.

Consider a simple example where a constant (not sinusoidal) signal is sent into a 1bit ADC.  If the signal is at 0.75 (ignore units) and the ADC can, depending on its input, either output a 0.0 or 1.0, the signal will be reported as a 1.0 till the cows come him.  If multiple measurements of the ADC are integrated together, the answer will always be the same, 1.0.

ADC Equation
$ \begin{matrix} ADC\left ( x \right ) = 0.0, & x < 0.5\\ ADC\left ( x \right ) = 1.0, & x \geq 0.5 \end{matrix} $ 
ADC Integration
$ \frac{1}{N}\sum_{n=0}^{N-1}ADC\left (x_{n} \right ) = \frac{1}{N}\sum_{n=0}^{N-1}ADC\left (0.75 \right ) = \frac{1}{N}\sum_{n=0}^{N-1}1.0 = 1.0 $

If Guassian random noise is added to the input, a form of dithering, the input to the ADC will vary.  With the right amount of noise, the signal will occasionally be below the 0.5 threshold and other times above.  If averaging is employed on this signal, the result of the averaging can be much closer to the true value of the signal attempting to be measured.

ADC Equation
$ \begin{matrix} ADC\left ( x \right ) = 0.0, & x < 0.5\\ ADC\left ( x \right ) = 1.0, & x \geq 0.5 \end{matrix} $ 
ADC Integration
$ \frac{1}{N}\sum_{n=0}^{N-1}ADC\left (0.75 + N\left ( 0,1 \right ) \right ) = \frac{1}{N}\sum_{n=0}^{N-1}ADC\left (N\left ( 0.75,1 \right ) \right ) $
$ \lim\limits_{N\rightarrow\infty} \frac{1}{N}\sum_{n=0}^{N-1}ADC\left (N\left ( 0.75,1 \right ) \right ) \approx 0.75 $

The reason for the approximation above is because the amount of decorrelation (reduction in spurs) depends on the amplitude of the noise added.  If the Guassian noise added is much smaller than the quantization error, there will be little benefit.  In the extreme case, if the added noise is zero then the results are back to where they started where averaging has no benefit.  In the other extreme case, if the Guassian noise is extremely large, a large amount of averaging is required to obtain an accurate measurement due to the error in the noise itself.  A rule of thumb used to obtain a balance between these two extremes is to try to ensure that the Guassian noise is ~6dB larger than that of the quantization noise.  Depending on application, this should be treated on a case-by-case basis. 

Wrap Up

Putting everything together, below is an illustration of how dithering can help.  Note that the spurs are reduced (below the noise floor introduced by the Guassian noise) and averaging is accomplished via the size of the FFT employed to create the spectrum.
# --------------------------------------------------------------------------------------
# Complex Dither Example
# --------------------------------------------------------------------------------------
fs = 100;
ts = 1/fs;
endTime = 1000;
time = np.linspace(0,endTime-ts,endTime*fs);
freq = fs/8.1;
freqVect = np.linspace(-1,1,len(time))*fs/2;
numBits = 8;
win = np.hamming(len(time));
signal = np.sin(2*np.pi*freq*time+np.pi/4);

sigPlusNoise = signal + np.random.randn(len(signal)) / 2**numBits;
quantSig = np.round(signal*2**(numBits-1))/2**(numBits-1);
quantSigPlusNoise = np.round(sigPlusNoise*2**(numBits-1))/2**(numBits-1);

sigSpect = np.fft.fft(win*signal);
sigSpect = np.fft.fftshift(sigSpect);
spurSpect = np.fft.fft(win*(signal-quantSig));
spurSpect = np.fft.fftshift(spurSpect);
noiseSpect = np.fft.fft(win*(quantSigPlusNoise-signal));
noiseSpect = np.fft.fftshift(noiseSpect);
plot.figure();
plot.plot(freqVect,20*np.log10(abs(sigSpect)),linewidth=2.0);
plot.plot(freqVect,20*np.log10(abs(spurSpect)),linewidth=2.0);
plot.plot(freqVect,20*np.log10(abs(noiseSpect)),linewidth=2.0);
plot.xlim(-fs/2,fs/2);
plot.ylim(0,100);
plot.title('Quantization Noise Dither Example');
plot.xlabel('Frequency (Hz)');
plot.ylabel('Amplitude (dBx)');
plot.legend(['True Signal','Quantization Noise','Dithered Quantization Noise']);
plot.grid();
plot.show();


Good References

http://www.utdallas.edu/~cpb021000/EE%204361/Great%20DSP%20Papers/Harris%20on%20Windows.pdf
http://www.analog.com/static/imported-files/tutorials/MT-001.pdf
Analog Devices Application Note [local mirror]
http://www.analog.com/static/imported-files/tutorials/MT-003.pdf

Thursday, October 9, 2014

pyFmRadio - A Stereo FM Receiver For Your PC



My first software defined radio (SDR) project is a stereo FM receiver.  The project uses a rtl-sdr receiver and python under Linux.  It probably works on Win/Mac but I haven't verified that it does.  Design details are given below along with some nice supporting plots.  Skip to the bottom for the code.  Oh and this was my first time using python.  Have mercy.  ;)


Basics of FM Modulation

First things first.  Lets discuss how FM radio works.  Audio (voice, music, etc) is encoded onto a higher frequency signal (carrier) by varying the frequency of the carrier based on the amplitude of the audio signal.


Initial Signals
$Audio = A(t)$
$Carrier = \sin(2\pi f_ct )$

Frequency Modulated Signal
$Inst. Frequency = f_c + kA(t)$
$Phase = 2\pi\int\limits_0^tf_c + kA(t)\mathrm{d}t$
$Signal=\sin(2\pi f_ct + 2\pi k\int\limits_0^tA(t)\mathrm{d}t)$


A couple of things to remember in the above equations.
  • The audio signal is in units of amplitude.  Volts, quanta, etc.
  • The variable 'k' is a scaling term that controls the allowable frequency swing or bandwidth of the modulated signal.  It has units of $^{Hz}\!/\!_{Amp}$.
  • The frequency of the modulated signal is directly related to the amplitude of the audio signal.  If the amplitude is zero, the frequency of the modulated signal is equal to the carrier frequency.
  • Since $Frequency=\,^{\mathrm{d}phase}\!\!/\!_{\mathrm{d}t}$, the phase of the modulated signal is the integral of the frequency.  Since the carrier's frequency is unchanging, its integral is straight forward.  The integral of $A(t)$ generally cannot be simplified since it depends on a dynamic changing signal.  #RealWorldCalculus

Python code to create plot:
# Import the plotting library
from matplotlib import pyplot as plot

# Define the setup
fCarrier = 10;
fAudio = 1;
fs = 1000;
timeEnd = 1;
time = np.linspace(0,2,fs*timeEnd);

# Create the signals
carrier = np.sin(2*np.pi*fCarrier*time);
audio = np.sin(2*np.pi*fAudio*time);
audioInt = -np.cos(2*np.pi*fAudio*time);
freqMod = np.sin(2*np.pi*fCarrier*time + 2*np.pi*1*audioInt);

# Plot the signals
plot.plot(time,audio+3);
plot.plot(time,carrier);
plot.plot(time,freqMod-3);

# Add some description
plot.text(0.75,4.2,'Audio Signal');
plot.text(0.75,1.2,'Carrier Signal');
plot.text(0.75,-1.8,'FM Signal');

# Label and cleanup the axes
ax = plot.gca();
plot.xlabel('Time (sec)'); plot.ylim(-4.5,5); plot.title('Frequency Modulation Illustration');
ax.get_yaxis().set_ticks([]);



FM Broadcast Radio

Before diving into the design details of the FM receiver, I'll briefly discuss broadcast FM radio in the United States.  Some quick notes are immediately below and supporting illustrations follow. 
  • Each station is allowed to occupy 200KHz (Double-Side-Band) of bandwidth
  • Once demodulated, two audio signals are present, the Left+Right (mono) signal and the Left-Right (diff) signal
    • A handful of other signals are present but I am ignoring them for this project
  • The two audio signals allow for mono or stereo functionality
    • Stereo is formed by simple arithmetic: $Left =  mono+diff$, $Right=mono-diff$
  • The audio signals occupy 15KHz of bandwidth (Single-Side-Band)
  • The mono signal is at baseband while the diff signal is a Dual-Side-Band-Suppressed-Carrier (DSB-SC) 38KHz above
  • A pilot tone at 19KHz exists which can be used (after doubling) to baseband the difference signal.
FM Station Received via RTLSDR Receiver (still FM modulated)
Same FM Station As Above After Demodulation (and carrier frequency removed)
Cartoon Representation of Demodulated FM Signal (single-side-band)


Receiver Block Diagram

Having discussed FM and FM Broadcast Radio its time to jump right into the receiver design.  Below is a block diagram of pyFmRadio.

FM Demodulation and Audio Processing Block Diagram
Play-By-Play:
  • The RTLSDR receiver is set to a sample rate of 250Ksps.  It generates complex, 8bit IQ samples.
  • The receiver is centered on the carrier frequency of the signal.  This means the carrier frequency is no longer present in the FM signal equation:
$FM\,Signal=\sin(2\pi f_ct + 2\pi k\int\limits_0^tA(t)\mathrm{d}t)$ goes to $FM\,Signal=\sin(2\pi k\int\limits_0^tA(t)\mathrm{d}t)$ 
  • The "basebanded" FM signal is immediately demodulated.  The difference between consecutive samples is calculated via a delay discriminator and the arc-tangent function is used to calculate the angle of the differences.  This is approximately equal to differentiating the FM signal's phase or finding the instantaneous frequency.  You can see from the equation above that the instantaneous frequency of the basebanded signal is equal to the audio signal.
  • The Left+Right signal is singled out from the rest of the audio signals via filtering and its sampling rate is reduced to an audio sample rate.  This process is implemented as a polyphase decimation operation by making use of a nobel identity.  This implementation saves a considerable amount of processing time compared to a non-polyphase implementation where filtering is done first and then decimation if performed.
  • Using a high-q peaking filter, the 19KHz pilot tone is singled out from the demodulated signal.
  • The real-valued pilot signal is converted to an analytic signal via the Hilbert transform.
  • The frequency of the analytic pilot signal is easily doubled by computing the square of the signal.
  • The frequency-doubled pilot signal now serves as a frequency and phase coherent carrier (reconstructed carrier) that can be used to demodulate the Dual-Sideband-Suppressed-Carrier (DSB-SC) Left-Right signal.
  • The Left-Right signal is mixed down to baseband using the frequency-doubled pilot and it then undergoes the same polyphase decimation as the Left+Right signal did.
  • The two signals are scaled and DC filtered.
  • Next the two signals are passed through a de-emphasis filter.  The act of FM demodulation (specifically the derivative operation) amplifies high-frequency noise which degrades the SNR of higher frequency audio content.  To help with this, broadcasters apply a pre-emphasis filter that amplifies high frequencies relative to low frequencies.  On the receive side, the reciprocal operation (de-emphasis) is performed to flatten the signal's frequency response to its original state.  This process improves the Signal-to-Noise-Ratio (SNR) of the FM signal by reducing high-frequency noise.
  • Using addition and subtraction, the two signals (Left+Right and Left-Right) are converted into stereo signals (Left and Right).
  • That is it, now you have audio!
Viola! Audio!


Code




Copyright 2014 David Swiston

Tuesday, September 30, 2014

Kenwood KA-3500 Volume Control

I really like the vintage Kenwood KA-3500 amplifier I use as my home stereo.  It sounds great and the brushed aluminum front has a sweet retro style.  However, whenever watching movies or listening to music, I'd always find myself loath to get up to adjust the volume.  The solution?  Replace the volume circuit of the original amplifier with a digital volume control circuit that could be controlled via a remote control or a rotary encoder.

The Arduino Micro is the computing brains of the operation.  It handles decoding/interrupts from a rotary encoder and an IR sensor.  It also interfaces with the audiophile grade Burr-Brown OP2311 digital volume control driver and the LED volume display board.  Writing the embedded C and worrying about Gray Codes, interrupts, code efficiency, and low-level bit handling was an interesting diversion from what I normally think about at work.

I also designed my own PCBs using CadSoft Eagle.  For someone with little experience in board design (this guy) this was a tedious but rewarding task.  I paid special attention to the board layout, followed data sheet suggestions, and made sure to keep the digital signals away from the line-level audio signals.  The effort paid off as the circuit is dead quiet.  Next up?  Wideband RF circuit designs (yeah right)!


Finished Product

Front of Amplifier With New LED Volume Indicator
Inside of Amplifier
Volume control circuit is mounted to the heatsink on the bottom left
Volume Control Circuit (1)
Volume Control Circuit (2)


Code




Artwork


Volume Control Board

LED Volume Board

Top Board Masks



Board CAD (Eagle) Files



Bill Of Materials (BOM)




Sunday, September 28, 2014

The Awesome Radio Spectrum

I am always awestruck at the amount of invisible EM waves whipping around us at the speed of light.  Gigabits of information are bombarding us every second via these waves.  A lot of it is critical information like the ILS that guides planes when landing or the TV station that broadcasts the Bears game.  Some of it comes from the ground - FM radio, TV, and cellular.  Some of it comes from 13,000 miles away in space from things like GPS.

While flying to Chicago I decided to check out what the radio spectrum looks like 2,000ft above Chicagoland.  Using my trusty RTL-SDR and a rather lackluster antenna I was able to capture some spectrum plots amidst two skeptical row-mates who were baffled by the weirdo next to them.

It's always fascinating to be able to visualize these invisible sources of information and entertainment.  Below are three captures at different frequency bands.

A Lot of HDTV Stations

More HDTV Stations and the 700MHz Cell Band - 4G LTE anyone?

850MHz Cellular

For my own future reference and for anyone who cares to read this, below is a link to the US frequency allocations.  It really is crowded!

US Radio Frequency Allocations


Friday, September 26, 2014

Make Your Own PCB Boards

A few years ago I embarked on a project to add remote control functionality to a vintage amplifier of mine (a Kenwood KA-3500).  Sarah and I had gotten tired of having to get up during a movie to turn the volume up or down but my appreciation for vintage audio gear wouldn't let me replace the amplifier.

While working on this project I discovered an easy to use and inexpensive place to get PCB boards made.  It's known as OSH Park and is run by a fellow who lives out on the US west coast (Portland I believe).  He collects individuals' orders (CAD artwork), groups them onto larger panels, and then ships them out to a fab house.  The panels ship back to him, he breaks them down into individual boards, and then ships them back to you.  The boards look fantastic!

I've attached a picture of one of the boards I made using OSH Park's service.

Volume Control Board (2.5" x 2")

OSH Park
https://oshpark.com/