Humbled by a sine wave oscillator

The old saw goes, “oscillators don’t, amplifiers do”, but that’s an analog saying.  It doesn’t apply to the digital world.  After all, digital is easy, while analog is hard, right?  (Be careful not to answer too quickly!)

For the last few weeks, I’ve spent my tinkering time on adding sine wave sidetone to the Verilog iambic keyer. As you may recall, sidetone is audio feedback for the keying, in other words, audible Morse code.  My thinking was that while this would appear to be a side trip on the way to FPGA-DSP radio nirvana, it would actually be valuable.  My vision for the radio will require sine wave synthesis in a couple of places.  Also, to have sine wave sidetone, I will need a digital-to-analog converter (DAC), so why not put theory into practice and build a delta-sigma DAC?

I looked around a bit to find a good way to synthesize a sine wave.  I didn’t want to do a simple ROM lookup table, because the radio will need memories for storing filter data and coefficients.  Instead, I settled on an algorithm that uses two integrators and a multiplier.  For some ratios of clock to output frequencies, the multiplication by -m can be reduced to a simple right-shift, which is always appealing to a hardware designer because it can be implemented without any gates.  The negation can then be absorbed into the first adder, costing little more than a set of inverters and a carry input.

Two-integrator sine wave oscillator

Then I found this elegant topology in Delta-Sigma Modulators: Modelling, Design, and Applications, by Bourdopoulos et al:

Digital sine wave oscillator with delta-sigma feedback

In this design, the multiplier has been replaced by a delta-sigma modulator and two constants.  This is gorgeous!  First of all, the multiplier is gone, replaced by a few adders and a mux.  Secondly, the delta-sigma bitstream is a built-in output for a DAC. There are a couple of wrinkles. First of all, there needs to be a scaling by 2^{-b} before and 2^b after the delta-sigma modulator. Otherwise, the modulator will see signals outside of its stable range. (Stability is a topic for a future tutorial in the How Delta-Sigma Works series.) Second, I’m not sure about putting the delay of the delta-sigma converter into the loop. It seems to me that the two integrators should be non-delaying. Third, are the two integrators sufficient filtering to remove the delta-sigma’s high-frequency noise, or is there a risk of high-frequency feedback making the loop unstable?

It sounds great, but when I coded it up in Verilog I couldn’t get it to be stable.  I fiddled with constants and bit widths for a while and couldn’t get it going. I also tried two non-delaying integrators in the loop. That didn’t work, either, and I couldn’t figure out why. Rather than do any stability analysis or model it in Octave, I decided to cut my losses and go to a more direct approach.

I took the original sine wave oscillator topology, which I easily got working, and tacked on a delta-sigma modulator to the output.  I decided to increase the clock rate in order to get a better signal-to-noise ratio (SNR) out of the DAC.  The oscillator blew up – unstable again!  After some more fiddling, I realized I was going to have to run with 24 or more bits of precision if I stuck to the design in the first figure.  To reduce the precision I needed to carry, I instead split the scaling between both integrators:

Sine wave oscillator followed by delta-sigma DAC

I fiddled with fewer bits, but with the clock-to-output frequency ratio I was working with (1 MHz clock, 800 Hz output), I needed all 16 bits to see a pretty sine wave in the ModelSim waveform viewer.

It looked great in the waveform viewer, so I burned it onto the FPGA and… noise. There is a brief tone buried in the noise, then it turns to all noise, and a little later, to a high-pitched whine without noise. The sine wave buried in the noise might mean I need better filtering between the FPGA and the audio amp (I didn’t use any, relying solely on the audio amp’s rolloff), but the all-noise and whining stages tell me that the oscillator or modulator is unstable. I probably didn’t run the testbench long enough in simulation to see it.

Meanwhile, at work, I’ve been having a great time introducing Test-Driven Development (TDD) into our firmware development process. The process was tedious at first, but now that I’ve been doing it long enough to see the results, I love it!  My code is better organized, better tested, and more solid than ever before.

That, combined with my frustration with the sine wave project, led me to think about applying Agile software engineering techniques to Verilog development.  I did some Google searches to see if anyone else is applying TDD or full Agile to hardware.  They are!  (agilesoc.com: Why Agile is a good fit for FPGA and ASIC development)

I learned some technical things while working on the sidetone. More importantly, though, I was reminded that methodical, well-tested development is not only better than seat-of-the-pants hacking, it is faster as well. Hobby projects benefit from discipline just as much as professional ones. I am going to set aside the sidetone project for a while and look at some other things.  Meanwhile I am going to think a bit about how to apply TDD and some other Agile concepts to my humble basement tinkering.