gaulandm@tekig7.MAP.TEK.COM (Mike Gauland) (04/12/91)
I'm trying to implement a sine-wave generator using a DSP. Anyone have an especially quick algorithm they'd like to share? Thanks, Mike -- ------------------------------------------------------------------------------ Michael Gauland KG7OS || "No man's life, liberty, or property is safe, (503) 627-5067 || while the legislature is in session." gaulandm@tekig7.map.tek.com ||--unattributed; can't find the source.
hanke@nessie.cs.id.ethz.ch (Norbert Hanke) (04/15/91)
In article <1750@tekig7.MAP.TEK.COM> gaulandm@tekig7.MAP.TEK.COM (Mike Gauland) writes: >I'm trying to implement a sine-wave generator using a DSP. Anyone have >an especially quick algorithm they'd like to share? > >Thanks, >Mike I implemented a sine-wave generator using a DSP56001 using the following algorithm: x(t) = x(t - Ts) * exp (j * w * Ts) where x(t) is a complex value, Ts ist the sampling interval, w ist the desired frequency in radians/s. The algorithm has some constraints regarding the amplitude accuracy: using 24 bit arithmetic, the amplitude changes in a way that it is just visible on an analogue level meter. Doing the calculation with double precision (48 bit) should obtain a stable amplitude for a very long time. using 32 bit on another DSP should be adequate to guarantee an implitude accuracy of fractions of a percent over several minutes. Norbert Hanke Swiss Federal Institute of Technology ETH Zurich, Switzerland
drick@hplvec.LVLD.HP.COM (David Rick) (04/16/91)
I believe most people do this with ROM look-up. Some DSP chips have this table as part of the default ROM, but for high speeds, give up on DSP chips and use a commercial phase-accumulator chip. Sorry, I don't know any part numbers. David L. Rick drick@hplvdo.HP.COM Disclaimer: My employer would rather you bought an HP product.
dandb+@cs.cmu.edu (Dean Rubine) (04/24/91)
In article <1750@tekig7.MAP.TEK.COM> gaulandm@tekig7.MAP.TEK.COM (Mike Gauland) writes: >I'm trying to implement a sine-wave generator using a DSP. Anyone have >an especially quick algorithm they'd like to share? People usually do this sort of thing by table lookup, and so should you if memory's not a problem. I recall some chapters in "Foundations of Computer Music", Roads and Strawn, Eds will tell you in excruciating detail how big the tables have to be to acheive a given S/N ratio if you are truncating or interpolating. Oh, BTW, there's never any benefit in rounding the phase accumulater, contrary to popular belief. The difference between truncating the phase and rounding the phase amounts to half a sample phase shift in the result; therefore, truncation will give the same results as rounding if you compensate for the phase shift either by initializing the phase accumulator to half a sample or by phase shifting the table accordingly. Anyway, what I really wanted to share was this method of generating sine waves without a table; great if you lack memory. Just implement a marginally stable two-pole digital filter. By putting the poles on the unit circle, the filter will naturally oscillate at the frequency of the poles. If we put the poles at exp(j * theta) and exp(-j * theta) (j being sqrt(-1) of course) we get this difference equation: y[n] = x[n] + 2*cos(theta)*y[n-1] - y[n-2] The impulse response of this filter will be a sinusoid. (For sine phase, I think we want the response of an impulse at n=-1 rather that at n=0, but I'll ignore that here.) The unit impulse response produces a sinusoid whose amplitude is 1/sin(theta), so you should start with an impulse whose non-zero value is sin(theta). The simple algorithm is thus: sinewave(theta) double theta; { double c2 = 2 * cos(theta); double y = sin(theta); double y1 = 0; double y2; for(;;) { printf("%g\n", y); y2 = y1; y1 = y; y = c2 * y1 - y2; } } Pretty slick: one multiply, one substract and some assignments for each sample. The drawback is that you need to calulate the sine and cosine of theta before you start the loop, but since it's just once you can use a library routine for that. You can probably vary the frequency smoothly by playing with c2 while the oscillator is running, though I've never tried this. I seem to recall from a standard graphics text that this method is slightly unstable: when used to draw circles it produces spirals. I'm not sure about this, but I seem to remember there was a simple fix, which unfortunately involved another multiply. -- ARPA: Dean.Rubine@CS.CMU.EDU PHONE: 412-268-2613 [ Free if you call from work ] US MAIL: Computer Science Dept / Carnegie Mellon U / Pittsburgh PA 15213 DISCLAIMER: My employer wishes I would stop posting and do some work.
wilf@sce.carleton.ca (Wilf Leblanc) (04/25/91)
dandb+@cs.cmu.edu (Dean Rubine) writes: >In article <1750@tekig7.MAP.TEK.COM> gaulandm@tekig7.MAP.TEK.COM (Mike Gauland) writes: >>I'm trying to implement a sine-wave generator using a DSP. Anyone have >>an especially quick algorithm they'd like to share? >[...] >sinewave(theta) >double theta; >{ > double c2 = 2 * cos(theta); > double y = sin(theta); > double y1 = 0; > double y2; > for(;;) { > printf("%g\n", y); > y2 = y1; > y1 = y; > y = c2 * y1 - y2; > } >} > Pretty slick: one multiply, one substract and some assignments for >each sample. The drawback is that you need to calulate the sine and >cosine of theta before you start the loop, but since it's just once >you can use a library routine for that. > You can probably vary the frequency smoothly by playing with c2 while >the oscillator is running, though I've never tried this. > I seem to recall from a standard graphics text that this method is >slightly unstable: when used to draw circles it produces spirals. >I'm not sure about this, but I seem to remember there was a simple fix, >which unfortunately involved another multiply. Very unstable. Unless you chose theta, such that the values of cos(theta) and sin(theta) can be represented exactly in floating point, the output will eventually spiral in or spiral out. A better algorithm is: complex a,y; a = exp(j*theta) y = 1 + j*0; forever { y *= a; output = imaginary_part(y) normalize(y) } Normalize just makes sure y remains on the unit circle. Can be simple since y is very close (i.e. an iterative algorithm can be used. The algorithm mentioned in the previous post is very similar to this one, except this algorithm has a single pole at exp(j*theta), and not complex conjugate pole pairs, and this algorithm has normalization to ensure that y remains on the unit circle. >-- >ARPA: Dean.Rubine@CS.CMU.EDU >PHONE: 412-268-2613 [ Free if you call from work ] >US MAIL: Computer Science Dept / Carnegie Mellon U / Pittsburgh PA 15213 >DISCLAIMER: My employer wishes I would stop posting and do some work. -- Wilf LeBlanc, Carleton University, Systems & Comp. Eng. Ottawa, Canada, K1S 5B6 Internet: wilf@sce.carleton.ca UUCP: ...!uunet!mitel!cunews!sce!wilf Oh, cruel fate! Why do you mock me so! (H. Simpson)
ge@dbf.kun.nl (Ge' Weijers) (04/25/91)
dandb+@cs.cmu.edu (Dean Rubine) writes: >In article <1750@tekig7.MAP.TEK.COM> gaulandm@tekig7.MAP.TEK.COM (Mike Gauland) writes: >>I'm trying to implement a sine-wave generator using a DSP. Anyone have >>an especially quick algorithm they'd like to share? > I seem to recall from a standard graphics text that this method is >slightly unstable: when used to draw circles it produces spirals. >I'm not sure about this, but I seem to remember there was a simple fix, >which unfortunately involved another multiply. A standard CG trick to generate circle points is the "register saving" technique originating from a programmer's mistake. Rotating a point around the origin can be done by multiplying by a rotation matrix: / cos(phi) -sin(phi) \ [x' y'] = [x y] | | \ sin(phi) cos(phi) / As an approximation for small angles you can use the matrix / 1 -phi \ | | \ phi 1 / A program rotating the point: tmp = x + y * phi y = y - x * phi x = tmp The mistake was: x = x + y * phi y = y - x * phi (saving one scratch register) This corresponds to the matrix / 1 -phi \ | | \ phi 1-phi^2 / which has a determinant equal to 1. This algorithm draws an ellipse very close to a circle. For further information see a CG book like Graphics Gems, by A. Glassner. I don't know whether this algorithm is stable, but you could restart it after one full circle and use the X component as output. Ge' Weijers -- Ge' Weijers Internet/UUCP: ge@sci.kun.nl LCN Foundation Reguliersstraat tel. +3180238130 (UTC+1, 6525 ED Nijmegen, the Netherlands UTC+2 march/september
hqm@ai.mit.edu (Henry Minsky) (04/27/91)
How about this for a sine wave generator ::
x = initial val
y = initial val
epsilon = small number
loop repeat
{ x = x + epsilon*y
y = y - epsilon*x
}
alk@hpspdra.spd.HP.COM (Al Kovalick) (05/04/91)
Several responded with the sine recursion formula method of generating a sine wave. IMHO this is the FASTEST method for generating a sine wave short of the table look up method. Actually, for say 12 bit precision, a chordal fit to a sine wave will yield a faster algorithm at the expense of amplitude resolution and quantization error. In fact with only 2 straight lines fitting from 0 to 90 degrees the max departure error is only about 2.7%. The straight line fit method still needs a look up table but with only 32 or 64 entries for the first quadrant. The other quadrants may be derived thru quadrant logic based on the first. I've always been interested in the tradeoffs made when deriving sine compute algorithms. The speed VS accuracy tradeoff is the most interesting. BTW, the previously mentioned recursion method is used in almost all FFT/IFFT transforms that are worth their salt. Using C and all variables in DOUBLE, I have generated 1 million points with the limit cycle noise less than -100 dB ref 1.0. Also the recursion method is only practical when you need to compute a succession of sine points with equally spaced time increments. For random look up, the chordal fit with small table is best, albeit the amplitude noise may be high. Finally, the recursion method is based on the trig identity SIN(N*a) = 2*SIN((N-1)a)COS(a) - SIN((N-2)a) ! simple, beautiful. Happy generating !! Al Kovalick Hewlett-Packard Stanford Park Division, Palo Alto, Ca.