sine routines

I suspect these weren't in (IEEE) floating point. I would guess that IEEE float multiply would take closer to 300 msec. than 300 usec.

Reply to
Everett M. Greene
Loading thread data ...

No, they used a 16 bit significand normalized with a hidden left bit. The routines operated entirely in registers, for speed and reentrancy. An earlier version of the system was published in DDJ in the late 70's or so. Accuracy was 4.7 decimal digits, and was quite sufficient for my purposes (medical instrumentation). It was actually better for most things than Microsofts Basic fp, which was 32 bits, because I rounded properly and they truncated. IIRC the whole code module, including i/o, fit into 2k, and was an order of magnitude faster than anything then available, except hardware.

At any rate applications such as solving a least square fit of calibration data to a 3rd order polynomial and applying goodness criteria (possibly dropping input points) produced a barely detectable hesitation. Re/Calibration was automatic when the operator fed in a suitable set of standards, controlled by reserved identification numbers.

--
Chuck F (cbfalconer@yahoo.com) (cbfalconer@worldnet.att.net)
   Available for consulting/temporary embedded and systems.
     USE worldnet address!
Reply to
CBFalconer

If your hardware design is not set in stone at this point, add two 27512 64Kx8 EPROMs, and a handful of glue logic. Feed the address pins with two 8-bit latches that can WRITE from the 8051. Use some glue logic to take a pulse from the processor, do a read cycle on the EPROMs, and latch the results into two other 8-bit latches that you can READ from the 8051.

Now burn the EPROMs with sin(address), and you have a dedicated hardware sin(x) lookup table that will be scary fast compared to any algorithm for computing sin(x).

It works something like this:

poke(msb(x), SIN_TABLE_ADDR_MSB); poke(lsb(x), SIN_TABLE_ADDR_LSB); pulse(SIN_TABLE_TRIGGER); sinx = peek(SIN_TABLE_DATA_MSB)

Reply to
John R. Strohm

64Kx8

from

two

sin(x)

computing

Nice idea, but you also need a DA converter. Now go take a look at the AD9833: A full DDS capable of outputting DC to

12.5MHz in 0.1Hz steps, sine, square and triangle. And if you clock it with 'only' 1MHz, you get DC to 500kHz in 0.004Hz resolution. And all this in a 10 pin package for a whopping $9.30 at Digikey....

Meindert

Reply to
Meindert Sprang

Please don't top post.

If I understand you correctly, you just want to generate 1-4 sine waves, of varying frequencies and amplitudes, then add then together and send them out your DAC, right?

To generate a continuous sine wave, just ought to be able to use Bresenham's circle drawing algorithm and output the X (or Y) coordinate as you pop around the circle you're "drawing." Very fast and you can do it all with modest resolution integer math. (The technique is closely related to Bresenham's line drawing algorithm - just Google for either).

Reply to
Robert Wessel

Careful here, you're getting mixed up with the various frequencies involved in this. A sampled signal being played back at a different frequency involves *three* frequencies, or even four, depending on how flexible you want to be:

*) the stored sample's sampling rate : r_in *) the playback sampling rate : r_out *) the frequency you're trying to output: f_out *) the original frequency of the sampled: f_in

For numeric examples, I'll assume

r_in = r_out = 44100 Hz f_in = 1 Hz

From these, the computations go as follows:

N := r_in / f_in

gives the length of the sampling table for one complete cycle of the wave, and thus the table index after which you would wrap around.

dt := 1/r_out

is the time step of the output --- the time between two writes to your DAC. In this time, you've covered a fraction of

dp := f_out * dt = f_out / r_out

or your output wave. Since we know that one complete cycle of that wave is one pass through the table, the step size in the table has to be

di := N * dp = N * f_out / r_out = (r_in * f_out) / (r_out * f_in)

Assuming r_in = r_out, this becomes

di = f_out / f_in

The frequency actually output will not be accurate to more than f_in anyway, so there's no point trying to treat f_out as a fractional number. Using this, all computations are in integers:

N = r_in / f_in; sine_table[N] = { filled by precomputation... } i = 0; assert(f_out * 2 < r_out); // pay respect to Mr. Myquist... forever { to_DAC(sine_table[i]); i = (i + f_out) % N; ... wait until time 1/r_out has passed ... }

If you need frequency accuracy better than 1 Hz, you must use a smaller f_in, but that will obviously make your table larger. If you try to use non-integer multiples of f_in as f_out, you'll get noisy output, i.e. more than one harmonic on output.

--
Hans-Bernhard Broeker (broeker@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.
Reply to
Hans-Bernhard Broeker

The original poster already has a DAC.

If all you want is sine/square/triangle waves, that chip will do it. If you want to do more interesting things, it won't.

But I think I'm going to take a longer look at it, for some radio projects I have in mind.

Reply to
John R. Strohm

This Is Not A Problem.

Use a phase accumulator running at 44.1kHz. Here's some scratch code:

unsigned_int_24_bits phase; // yes, three bytes for each. unsigned_int_24_bits frequency; unsigned_int_24_bits freq_lookup [24] = { 123445, // (SWAG approximate values) 126999, // These should each be the frequency for 131111, // the corresponding key. ... };

int sin_lookup [256]; // this table is 256 points along a complete sine wave of 360 degrees.

phase = 0; // init phase (not even neccesary) frequency = freq_lookup [note]; // set output frequency based on note

interrrupt isr_for_44100Hz_interrupt (void); { phase += frequency; output_sample_to_DAC = sin_lookup [phase >> 16]; } // end ISR routine

This routine is just about that simple. When the frequency variable is half its maximum value, the output will be (if the phase doesn't start out at zero, but we can ignore that for this calculation) two points at 22,050Hz. Thus the ratio between Hertz and the number in the frequency variable (or specifically freq_lookup) is:

22050 / 2^23 = 0.0026285648345947265625

Thus, if you put a 1 in the frequnecy variable, you will get a sine wave with 0.0026 Hz output. Let's take the reciprocal of that for easier conversion the other way:

380.435736961451247165532879818594 Let's call it 380.436. To generate an "A" at 440Hz, use the number: 380.436 * 440 = 167391.84 or just round it to 167392. The next note up is A# at 2^(1/12)*440 or 466.16Hz. 380.436 * 466.16 = 177344.04576 which when rounded becomes 177344.

If you follow the code carefully you may notice that at frequencies below 44100/256 or 172Hz, some samples will have sine table entries repeated, and at higher frequencies some entries in the sine table will be skipped. Again, this is not a problem, unless you're making a "real" music synthesizer for use by "real" musicians, or you're using this for a lab instrument that needs a pure-as-possible sine wave at arbitrary frequencies.

Another neat thing about using a lookup table in this manner is that you can change the waveshape just by putting it into the lookup table. Square, triangle and sawtooth immediately come to mind, and again, skipping or repeating samples at different frequencies isn't a problem except in truly critical applications.

-----

formatting link

Reply to
Ben Bradley

thank

I am sorry, terribly busy, but you can get there from here (I had to)

circles ( and sines, fit for your purpose) using only add and subtract

X = 100: y = 0

FOR i = 1 TO 1000

PRINT X, y

X = X - y / 256 y = y + X / 256

NEXT

If you cannot do it I will dig out the Scamp (INS8060) code, eventually.

David F. Cox

Reply to
David F. Cox

hi, this is the simplification of the compound angle formulas, it works very well and can be quite quick but not as fast as a lookup table.

Reply to
CBarn24050

very

in context: I had to drive a stepper motor around 1 metre diameter circles with an accuracy of 0.1 mm using a 2K EPROM

======== original post: I am sorry, terribly busy, but you can get there from here (I had to)

circles ( and sines, fit for your purpose) using only add and subtract

X = 100: y = 0

FOR i = 1 TO 1000

PRINT X, y

X = X - y / 256 y = y + X / 256

NEXT

If you cannot do it I will dig out the Scamp (INS8060) code, eventually.

David F. Cox ======

Reply to
David F. Cox

He could also do a search on DDA routines. These are simple add and shift routines that can often be done in a few machine cycles. John Matthews book has an example in for this (Engineering Applications in Forth).

--
********************************************************************
Paul E. Bennett ....................
Forth based HIDECS Consultancy .....
Mob: +44 (0)7811-639972 .........NOW AVAILABLE:- HIDECS COURSE......
Tel: +44 (0)1235-811095 .... see http://www.feabhas.com for details.
Going Forth Safely ..... EBA. www.electric-boat-association.org.uk..
********************************************************************
Reply to
Paul E. Bennett

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.