Optimizing an amplitude-shift keying detector
Nothing is more permanent than a temporary solution to an engineering problem. Some time ago I was reverse engineering a proprietary wired network protocol. I ended up quickly throwing together a simple audio-frequency amplitude-shift keying detector just so that I could record some traffic. I needed many packet captures before I could begin to understand what is being sent over the line and just taking screenshots on an oscilloscope was too inconvenient. A few months later and almost the exact schematic I made with a few back-of-the-napkin calculations ended up in an actual product. It seemed to work fine in practice so there didn't appear to be any need for additional design work. A year later however and some problems became apparent with my original design. With a better idea about what kind of sensitivity and selectivity was required I got to revisit my old circuit.
The first detector I made for my experiments just used a passive, RC band pass filter to isolate the carrier. It has a single transistor acting both as a demodulator and an amplifier to produce a 5V digital signal. I made it during lockdown last year on a piece of breadboard from spare components I had lying around. The design that ended up in manufacturing switched to smaller, surface mount components but was basically unmodified in function.
To better understand the performance of this circuit I made a simulation model of the detector and the signal being detected. I used Spice OPUS for this task. Although I've also used ngspice a few times in the past, I keep returning to Spice OPUS. I've used it since my undergrad days and at this point I know most of its quirks. I like to use tools that I understand very well and know when I can and when I can't trust the results they give me.
Since a detector is a non-linear circuit I had to use the transient analysis. The basic Spice analysis types don't allow you to run the transient analysis on a range of input signals automatically. I had to write up a short program in Nutmeg, the Spice scripting language that is included in Spice OPUS. I varied the carrier amplitude and frequency on a logarithmic scale and chose 60 points on each axis. This resulted in 3600 separate simulations being run. I chose this number simply because it still returned a result reasonably fast on my computer.
I could use Spice itself to visualize the results, but the plotting capabilities are limited and I much rather work in Python than Nutmeg. Hence I only wrote out raw Spice vectors into a text file and then used Python and matplotlib to visualize the results:
On this plot the axes are input carrier frequency and amplitude on a logarithmic scale. The color shows demodulated output signal level. The output is in inverted logic, hence if a carrier is detected the output is low. The hatched area shows where the output is not defined according to the 5V CMOS logic levels. Those input ranges are forbidden since in those cases the output of the detector could be interpreted either as low or high by the digital logic after it.
The circuit reliably detects the carrier for a range of frequencies, but the amplitude must be relatively high. At the frequency with best sensitivity, it would only detect signals with amplitudes of around 1 V or more. The two red dots on the plot are my new design requirements. The system uses a frequency multiplex to carry various channels on one line. I wanted to make a new circuit that would still detect the wanted carrier at 150 mV amplitude at 50 kHz. At the same time it should not be sensitive to an unwanted signal at 1 kHz and up to 2 V amplitude. The existing circuit obviously falls short of the former requirement.
Meeting these requirements wasn't simple. Simply increasing sensitivity of the detector wouldn't work. It would not be selective enough and would react to carriers outside of the desired frequency band. I needed to add better filtering as well as increase gain. Since the original circuit was so compact there was very little spare PCB space left for improvements. I considered a few opamp-based approaches as well as pushing demodulation to the digital domain, but in the end those all turned out to be infeasible.
I ended up adding another transistor with which I implemented both a Sallen-Key active second-order filter as well a small gain stage. Having a transistor pair in a SOT-23 doesn't take any more space than the single one in the original design. I also optimized the circuit so that it had many identical-valued resistors. That made it possible to replace four individual 0603 chip resistors with a single 0805 resistor array, saving more board space.
This is how the simulation of the new design looks like:
The plot shows that the new circuit meets both the requirements I was aiming for. It produces a well-defined digital output for weaker signals thanks to the additional gain. The new filter also results in more attenuation outside of the desired frequency band. This means that the stronger, unwanted signal at 1 kHz still does not produce any output.
I was worried that the sensitivity of the detector would depend too much on variations in transistor parameters, so I also did some additional simulations to check that. I varied the transistor model in Spice to include the edge cases for DC gain and base-emitter voltage specified in the datasheet. The results show that even with worst-case transistors the new design should still meet the requirements:
In conclusion, this was an interesting challenge, but also frustrating at times. I kept thinking that I should come up with a more modern design. This kind of discrete-transistor circuit seemed old-fashioned. I felt there should be an off-the-shelf IC that would do what I needed, but I failed to find one. I looked at the LM567 tone detector and a few similar solutions, but I simply couldn't fit any of them on the available PCB space.
I haven't done any such involved discrete design in a while and I had to dig myself into some reference books first and refresh my knowledge of transistor properties. After a few tries and iterations I ended up with a solution that I think is quite elegant and solves the problem I had in front of me. An opamp design would likely have better properties, but in the end a circuit that you can use is better than one that you can't.