2-channel frequency generator to create Lissajous patterns - Page 1
Forum section: electronics / projects

author: edy
author_rank: Super Contributor
timestamp: August 10, 2013, 07:44:32 pm
content: Hi, I wanted to make a simple hardware device to create Lissajous patterns. I have played around with PC software (Tone Generators) that will output to LEFT/RIGHT channels and you can play with the frequency, phase and amplitude, and choose between sine,square and triangle waves. You can even make something in Audacity sound software on left/right channels of difference frequencies and phases to watch the patterns move. But I was wondering if a simple hardware-based version can be made.Here's the basic hardware design (x2... one for each channel):- control pot to adjust frequency range (does not have to be accurate, just some basic range like 100 Hz to 10 kHz)- control pot for amplitude- trim pot to adjust phase or at least delay one channel relative to the otherI have no idea where to begin, but I've been looking into understanding oscillator circuits and using the variable resistor (pot) adjustment to allow for basic frequency adjustment. For amplitude I do not need to amplify, I just want to depress one channel versus another by varying amounts, so I assume a variable resistor in series would reduce voltage. Phase adjustment would have to kick or delay the channel so it is time-shifted. I could have a switch button that would just start oscillating when hit, but I want to be able to fine-adjust the oscillator as it's running.While I continue researching this project, any pointing in the right direction would help.

author: edy
author_rank: Super Contributor
timestamp: August 10, 2013, 07:57:13 pm
content: I was just looking around and it seems using a 555 timer might work, but it will output a square wave and to approximate a sine out of that requires a bunch of filtering steps. Also, there is no guarantee of pure 50% duty cycle. As well, the filters would have to be set for a specific frequency and so once I adjusted my 555 timer frequency, the filters wouldn't be set up to properly convert it to a sine.So I'm back to using a simple oscillator circuit with a transistor, inductor, capacitor and variable resistor to adjust it, although they apparently aren't very clean. Perhaps I'll just have to use a frequency generator on a chip that handles everything. On the other hand, I do have an Arduino laying around and perhaps can use it to generator the sinusoidal output. I believe it is fast enough to handle basic audio-range frequencies.There are enough inputs and outputs on the arduino to allow me to generate 2 independent sine waves, and hopefully enough horsepower to run these low frequencies for lissajous figures.

author: fcb
author_rank: Super Contributor
timestamp: August 10, 2013, 11:53:30 pm
content: If you can get a couple of XR2209's you can do this very easily.You can also build them with LM13700's (a nice IC to work with) - If you've only got some opamps in the parts draw then my favourite of the quick ones is:http://www.bobsdata.com/audio_sine_wave_generator/

author: edy
author_rank: Super Contributor
timestamp: August 11, 2013, 01:28:51 am
content: Thanks, that looks like a fairly straightforward build! I'll have to gather the parts and try it out.Just read the datasheet on XR2209.... looks like it does Triangle, Sawtooth, Pulse, Squarewave. So I would still have to apply some filters to smoothen it out into a sinusoidal shape?

author: edy
author_rank: Super Contributor
timestamp: August 11, 2013, 04:34:01 am
content: I studied the circuit for Bob's Audio Sine Wave generator and also watched this video here:Could I not use the dual op-amp TL082 to make 2 oscillators, and forget the buffer amp? If I'm just pushing it through to my oscilloscope, do I need a buffer amp?I also noted people using the 741 opamp. I'll have to pick some of these up at the local electronics supply shop.Oh, and I found this kit schematic, a bit more complex than I need but good to study (also attached a copy)....http://lib.store.yahoo.net/lib/webtronics/kit23.pdfAnd I also found this primer on op-amp sine generators (with copy attached below)....http://www.ti.com/sc/docs/apps/msp/journal/aug2000/aug_07.pdf

author: Smokey
author_rank: Super Contributor
timestamp: August 11, 2013, 06:39:48 am
content: Not sure if this qualifies as simple, but the AD9958 is a dual channel DDS. It's kind of the anti-analog solution, but it would get the job done. There are some app notes about phase syncing single channel DDS chips as well, so you don't have to use the dual one.I remember seeing some independent dual channel boards on ebay but I'm not finding them now.

author: fcb
author_rank: Super Contributor
timestamp: August 11, 2013, 01:07:15 pm
content: Quote from: edy on August 11, 2013, 01:28:51 amSorry, meant XR2206 (discontinued), not the XR2209 which isn't.

author: ejeffrey
author_rank: Super Contributor
timestamp: August 11, 2013, 04:53:06 pm
content: DDS is great for this application because you can make two frequencies that are exact rational multiples: e.g., 2:3, 5:7 or whatever. That means that your lissajous patterns will retrace exactly. If you just want to look at it on a scope, a soft-DDS on a microcontroller with a 4-bit hand-built resistor DAC will do the job.

author: edy
author_rank: Super Contributor
timestamp: August 11, 2013, 07:05:22 pm
content: Thanks, I am looking at the Arduino option as well. The Op-Amp version would be nice but I would have to tune it precisely with the variable resistor pots to try and line things up. My lissajous figures would be rotating around as I will unlikely get exact multiples of frequency and the phase relation will keep changing. I will probably still build the example listed using the oscillator example above with lamp, if I can source the parts easily and cheaply enough around here.Otherwise, I have an Arduino available already. I could use the PWM outputs with an RC filter. I believe for the audio-level frequencies I am looking at probably a 1kHz-5kHz maximum requirement. The PWM is much higher frequency, so the filter will essentially convert the PWM to an analog voltage. If I step through the sine values on an analogWrite, then I should be able to make my output voltage go from 0 to 5V in analog gradients, then back down again to 0V.The arduino would have a sine curve centered around 2.5V with oscillation from 0 to 5V, which is fine. I guess if I wanted to reference the middle, I would have to subtract 2.5V so that the oscillation is -2.5V to 2.5V.

author: ejeffrey
author_rank: Super Contributor
timestamp: August 11, 2013, 07:22:24 pm
content: Quote from: edy on August 11, 2013, 07:05:22 pmThe standard arduino library gives you a PWM frequency only around 1 kHz. You can reprogram the registers by hand to get higher frequency, or you can just make a DAC by using a few (say 4) regular digital outputs with resistors to generate a simple DAC.QuoteJust capacitively couple the output.

author: edy
author_rank: Super Contributor
timestamp: August 12, 2013, 01:44:13 am
content: I think I understand what you mean.... like this:http://hackaday.com/2011/02/17/your-first-digital-to-analog-converter-build/The resistor network sums up the voltages on several pins, so in essence I can just use 4 outputs as a representation of 0000 up to 1111 which gives me 16 levels (2x2x2x2). The problem is that my sine wave is not linear, so I can't simply increase my pinmodes from 0000 to 0001 to 0010 ... etc.... with the same timing.Either I have to change the timing of the changes so I "hit" the actual time that those evenly-spaced voltage levels occur on a sine curve, or keep my time interval the same increment and choose which of the 16 values is closest to the level that the sine curve is at that specific time. 16 levels doesn't provide much resolution.

author: edy
author_rank: Super Contributor
timestamp: August 12, 2013, 02:53:59 am
content: I've attached an Excel file in which I simulated Lissajous calculations for my algorithm as follows:sinetable = 127, 129, 131, etc... (256-long array holding values from 0 to 255 representing sine)loop{for i=0 to order{for x=0 to 255{analogWrite(pinX, sine)analogWrite(pinY, sine[((256*i + x)/(order+1) + phaseshift) mod 256])}}So what is happening is the "x" value just keeps running from 0 to 255. However, the outer loop will set the "order" of the Lissajous... or the ratio of frequencies. If order=0, then i=0 and pinY simply becomes sine[(x + phaseshift) mod 256] so it is essentially same frequency as x just shifted over.If order=1, then "x" cycles from 0 to 255 TWICE while the "y" value cycles just once through.... as it takes 2 passes of the "x" loop (first time i=0 and second time i=1). However, pinY is half as slow as "x" because it is dividing x/2.If order=2, then "x" cycles from 0 to 255 THREE TIMES while "y" value cycles only once through, with i=0, then i=1 then i=2.... the pinY values are divided by 3 so it takes 3 passes of "x" using the "i" loop.... (256 * i + x)/3 gives us the range from 0 to 255 after "i" goes from 0..2.Try the Excel spreadsheet.... See the different tabs, change the "phaseshift" degrees highlighted by yellow, and you will see the Lissajous graph automatically update in the Excel spreadsheet.Now, on the Arduino if the program runs too slowly I can reduce my steps from 256 to 128 or 64 if needed... I will have to experiment and see. I also want to be able to add options to have my phaseshift change automatically so I get nice animations, or tie it to a potentiometer so I can mess around with it externally. As well, I want a button that can toggle through the 3 "orders".

author: ejeffrey
author_rank: Super Contributor
timestamp: August 12, 2013, 04:40:14 am
content: Quote from: edy on August 12, 2013, 01:44:13 amTrue. The normal way to do this is to have a lookup table. So you have a phase accumulator that might be 16 bits, and you add a certain increment delta-phi to it every cycle. You then use the most-significant several bits to look up in a table of cosine values. For example if you use an 8-bit lookup table and a 4 bit DAC you would need 128 bytes of program memory for the look-up table. By having the accumulator and the lookup table have more bits than your DAC you keep good frequency resolution and minimize distortion, although there is only so much you can do with a 4-bit DAC. You will want to do the same thing regardless of whether you use a crude resistor DAC, PWM, or a higher precision commercial DAC.It is also possible to reprogram the arduino PWM to have a faster frequency. I think you can set the prescalar to 1, and run in 'fast PWM' mode. With 8 bits and a 16 MHz clock this gives you 62 kHz PWM frequency, which should be OK for this application with some filtering. You can also trade resolution away to increase the PWM frequency further.

author: w2aew
author_rank: Super Contributor
timestamp: August 12, 2013, 12:53:54 pm
content: Quote from: ejeffrey on August 11, 2013, 07:22:24 pmIf you want to use the parallel digital outputs and the resistor ladder DAC, you might be interested in learning more about the basics of the R2R DAC:

author: oPossum
author_rank: Super Contributor
timestamp: August 12, 2013, 05:38:30 pm
content: Here is dual sine wave generation using a TI MSP430 launchpad and a Microchip MCP4822 DAC.DDS (direct digital synthesis) is used and the frequency resolution is 0.001 Hz, so you can make the pattern move very slowly if desired.http://forum.43oh.com/topic/1286-simple-dac-using-microchip-mcp48xx/?p=10634

author: edy
author_rank: Super Contributor
timestamp: August 12, 2013, 05:48:49 pm
content: Thanks for the link. I remember seeing videos from that gentleman "w2aew" before, they're chock full of tips!So I will try both methods.... one where I go through my PWM analogWrite method and convert it to an analog voltage using a filter (and that's another question entirely... what R/C combo would work best for the Arduino's PWM function to get a smooth output and what kind of attenuation will result).And the other is using this R-2R ladder network and bit-writing the outputs.I have 14 digital output pins available on the Arduino....so if I use 7 for X and another 7 for Y, then I have 128 levels (2^7) values per channel X or Y to write my binary words. That would give me quite a good resolution to get varying voltage outputs. Then I would compute a "sine table" which would basically just be the values of the sine-wave at equally spaced times converted to 7-bit values.... with my "-1" of the sine being 000,0000 (0 decimal) and my "0" level sine being 100,0000 (64) and my "+1" sine being 111,1111 (127).As far as horizontal time-spacing, my array could be as short or long as I want. If I make my array of values 240-length (1 complete wave) then I could easily divide this into 2, 3, 4, 5, and 6 to get my various frequency ratios.Given enough memory on the Arduino, I could represent a sinewave in an array of length 960..... one complete wave. Then if I have say my 1st channel running through every element of the array....all 960 levels..... while I have the 2nd channel skipping every other value in the array.... so it is "TWICE" the frequency of the 1st channel. When it gets to the end it loops back. Or if I want a 1:3 ratio for Lissajous curve formation, once again I have my first channel go through all 960 elements, while my 2nd channel jumps to every 3rd element per cycle.... my 2nd channel would run 3x faster than my 1st channel.Each channel's 7 pins would then run through a R-2R DAC and display.Code could look like this:sinetable = { ...... }loop(){for (time=0; time<960; time++) // cycle through array{value = sinetable; // get value of sinefor(bit=0; bit<7; b++) // shift through each bit and display{digitalWrite(pin, bitread(value,bit))}}}So the above would essentially look up a 7-bit value for the sine wave in the array for each step in time, and write it out to the 7 pins. Now if I wanted to do the same except with 2 channels I would have to do the following:sinetable = { ...... }loop(){for (time=0; time<960; time++) // cycle through array{value1 = sinetable; // get value of sine for channel 1value2 = sinetable[time*2 modulus 960]; // get value of sine for channel 2 at twice frequencyfor(bit=0; bit<7; b++) // shift through each bit and display{digitalWrite(pin, bitread(value1,bit)); // output binary word for channel 1 pinsdigitalWrite(pin[bit+7],bitread(value2,bit)); // output binary word for channel 2 pins}}}Anyways, that's the rough code. I need to think about how to optimize it. Not sure what types of functions take more cycles (like "if" statements, versus "multiplier/division/modulus" and so on. Also wondering if perhaps this is not overkill on the resolution as it will slow things down having 128 voltage levels and 960 time steps. I'll know once I actually sit down and build myself the array and try it out.I found this, might be handy....http://fritzing.org/projects/arduino-simple-signal-generatorLooks like we are using 10k and 20k resistors? If I am not loading this at all, and we are just measuring on a scope, with these resistors I shouldn't be worried about drawing too much current from the Arduino I presume.I also came across this, which will come in handy when I select a filter for my PWM to Analog version:http://digital-diy.com/swordfish-example/314-digital-to-analogue-conversion-dac-via-pwm.html

author: w2aew
author_rank: Super Contributor
timestamp: August 12, 2013, 06:12:52 pm
content: Here is a code snippet for the Arduino that I picked up from a friend of mine to speed up the PWM frequency:// The following sets the PWM clock to maximum on the Arduino(no CPU clock division)// DO NOT CHANGE THESE UNLESS YOU KNOW WHAT YOU ARE DOING!TCCR0A = ( 1<<COM0A1 | 0<<COM0A0 | // clear OC0A on compare match (hi-lo PWM)1<<COM0B1 | 0<<COM0B0 | // clear OC0B on compare match (hi-lo PWM)1<<WGM01 | 1<<WGM00); // set PWM lines at 0xFFTCCR0B = ( 0<<FOC0A | 0<<FOC0B | // no force compare match0<<WGM02 | // set PWM lines at 0xFF0<<CS02 | 0<<CS01 | // use system clock (no divider)1<<CS00 );TIMSK0 = ( 0<<OCIE0B | 0<<TOIE0 |0<<OCIE0A );More details and context is found here, in his blog post:http://www.johngineer.com/blog/?p=648

author: edy
author_rank: Super Contributor
timestamp: August 12, 2013, 07:20:10 pm
content: Thanks so much! Nice videos by the way! I assume I just drop that code into the beginning of my sketch. That would come in handy if I am using my PWM output with the sine-table 256-length array method holding all the pre-calculated levels for the analogWrite.I was looking at RC filtering that PWM signal to get a smooth analog voltage and noted people using a 1k resistor with a 4.7 uF cap, or designing at as twopole linking 2 filters with 2x 1k resistors and 2x 1uF caps. I'm not sure if those are appropriate for the fast PWM signal or regular PWM of the arduino. If I get a variety of caps/resistors I can try a few combinations and see how a 50% duty cycle PWM would look like.My sketch, after all the setup commands, would basically be:loop(){analogWrite(pin, 128); // 50% duty cycle on pindelay(1000); // wait}I found a nice tutorial here on PWM to analog using RC filter:http://dev.emcelettronica.com/how-to-use-pwm-to-generate-analog-or-analogue-voltage-digital-circuits-part-2I will have to time the PWM signal and then choose R and C according to page above which suggests making the time constant 100x the PWM time interval.