# sine routines

#### Do you have a question? Post it now! No Registration Necessary

Translate This Thread From English to

•  Subject
• Author
• Posted on
does anybody know where to find some FAST sine routines to be run on an
8052? sdcc's math.h is just an empty file... just an #error directive! thank

Re: sine routines
comp.arch.embedded:

There are no FAST routines for calculating sine with the 8051
instruction set, and probably no fast ones either.  How much accuracy
and precision do you need?  The fastest approach would be a look-up
table.

--
Jack Klein
Home: http://JK-Technology.Com
We've slightly trimmed the long signature. Click to see the full one.
Re: sine routines

and what sort of floating point arithmetic has he available, if
any?  Does he have polynomial evaluation routines? etc.  What
input range is required?

--
Chuck F ( snipped-for-privacy@yahoo.com) ( snipped-for-privacy@worldnet.att.net)
Available for consulting/temporary embedded and systems.
We've slightly trimmed the long signature. Click to see the full one.
Re: sine routines
wrote in comp.arch.embedded:

All good questions, but do you know of any fast routines to calculate,
as opposed to look up, sines on an 8051?  Any floating point is
hideously slow on that platform, I know, I've used it a few times.

--
Jack Klein
Home: http://JK-Technology.Com
We've slightly trimmed the long signature. Click to see the full one.
Re: sine routines

I was thinking of some Tchebychev polynomials or ratio of
polynomials I used 25 years ago for 4.5 digit accuracy.  I have
the source somewhere for the 8080 code I developed for them, which
took about 10 millisec on a 2 Mhz 8080, as I recall.  Floating
multiply was in the order of 300 uSec. and divide headed for 1
millisec.

--
Chuck F ( snipped-for-privacy@yahoo.com) ( snipped-for-privacy@worldnet.att.net)
Available for consulting/temporary embedded and systems.
We've slightly trimmed the long signature. Click to see the full one.
Re: 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.

Re: sine routines

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 ( snipped-for-privacy@yahoo.com) ( snipped-for-privacy@worldnet.att.net)
Available for consulting/temporary embedded and systems.
We've slightly trimmed the long signature. Click to see the full one.
Re: sine routines

If only sin/cos is required (and not tan), then why use floating point
numbers in the first place. Use some fixed point format e.g. the
decimal point to the _left_ of the most significant bit or two bits
for the integer part and 30 bits for the decimal part, thus avoiding
any normalisation and denormalisation required by floating point

The fixed point arithmetic can be done with integer hardware, but some
rounding due to discarded low order decimal bits must be done after
multiplication and some shifts with a predetermined number of bits may
be required if the number of integer bits is something else than 0 or
8.

The polynomial method is just an refined table look up with some
into a few ranges and the polynomial coefficients are extracted from
the table. A fourth order polynomial is usually sufficient for single
precision accuracy, while 6-8 order is required for double precision.
By dividing the quadrant into a larger number of ranges, a lower order
polynomial can be used.

Paul

Re: sine routines
what i need to do is to generate a custom-frequency sine wave to be
outputted at CD-quality frequency (44100 samples/second) to a DAC.
If possible i'd prefer working with 16 bit integers since float needs
cpu-time-expensive libraries.
thanks to all of you for your replies.

thank

Re: sine routines

If that is all you have to do, take a look at Analog Device's DDS chips.

Meindert

Re: sine routines
snipped-for-privacy@NOcustomSPAMware.nl "Meindert Sprang" writes:

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).

--
********************************************************************
We've slightly trimmed the long signature. Click to see the full one.
Re: sine routines

Setting aside the recommendable option of replacing the whole kaboodle
you're planning now with a special-purpose chip (a digitally
controlled oscillator), there's still no reason to actually evaluate a
sine function for this.

A table should be perfectly adequate --- subsample it in steps through
the table whose size is governed by the quotient of your target
frequency and the frequency of the tabulated signal.  E.g. if you have
a sine table of (effectively) 44100 samples for a 1 Hz wave, a 1 kHz
wave would use every 1000th sample from that table, and wrap around at
the 45th iteration to 45*1000 - 44100 = 900.  You'll want to handle
non-integer step sizes, too --- either using fixed-point fractional
arithmetic, or by Bresenham's algorithm.

The actual table should of course store only one quadrant of the wave
(0 .. 90 degrees, typically), to keep it short.

--
Hans-Bernhard Broeker ( snipped-for-privacy@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.

Re: sine routines
ok i understood that i have to use a lookup table. before asking some more
question i just want to explain what i am really trying to do.
it will simply be a sort of musical keyboard (a synth). it takes the input
of 24 keys (using 3 of the four raw i/o ports of the 8052) and sends 16 bit
samples to the dac (even if it accepts only 24 bits samples - i simply leave
the LS 8 all low).
what i'm wondering here is how to implement the lookup table (actually the
problem is that the sine function generate variable frequency sine waves)
i mean:

short sine (unsigned short frequency) {
return sin[(counter % frequency) / frequency];
}

(note that long is 4 byte in sdcc) to make sure of having a *decent*
resolution without using long and float (int and short are the same) values
in the calculation what can i do?
i thought of something like
return sin[((counter % frequency) << 10) / frequency];
(at least 10) but i think this will mess up everything. or not?

Re: sine routines

i meant (real world math):

sin(mod(counter, frequency) * pi * 2 / frequency)

counter simply is the sample counter.

bit
leave
values

Re: sine routines

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 -

Re: sine routines

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 ( snipped-for-privacy@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.

Re: sine routines

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.

-----

Re: sine routines
44100 samples / sec = 22,676 microseconds per sample.

Are you sure the 8051 is fast enough to handle that ?

Using a lookup table may help.
Doing 16-bit calculations seems impossible.
Calculating a floating point sine IS impossible.

It depends on the derivative you use.
A standard 8051 will certainly not be able to do the job.

grtnx
/jan

bu634c\$7g9\$ snipped-for-privacy@lacerta.tiscalinet.it...

an

Re: sine routines
On Thu, 15 Jan 2004 15:43:00 +0100, the renowned "Jan Homuth"

That's less than 23 usec, just to make it clear.

A phase accumulator with a LUT ought be able to do it, using a faster
("very" faster..) variant of the 8051 such as the Cygnal parts. Best
to write and simulate the short (assembler!) code now and see how long
it will take to execute, including the interrupt and timer reload
overhead.. at 50 so-called MIPS there are ~1150 cycles between
interrupts. If you can jig the frequency a bit to fit into an integral
number of sample periods you can simplify it and reduce the size of
the LUT.

Best regards,
Spehro Pefhany
--
"it's the network..."                          "The Journey is the reward"
snipped-for-privacy@interlog.com             Info for manufacturers: http://www.trexon.com
We've slightly trimmed the long signature. Click to see the full one.
Re: sine routines

Because it causes confusion.
Why is topposting evil and rude.

requirements originally.  Hans Broeker and Morris Dovey have the
right idea.  You can limit your table to the range 0..45 degrees
and use (1 - sin(90-x)) for 45 to 90.  Similarly -sin(-x) for
-90..0.  Etc.

It is probably easiest if you keep the table as signed integers to
be divided by 32768 for the actual result.  Not 65535 or 32767.

--
Chuck F ( snipped-for-privacy@yahoo.com) ( snipped-for-privacy@worldnet.att.net)
Available for consulting/temporary embedded and systems.
We've slightly trimmed the long signature. Click to see the full one.