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

Re: sine routines

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

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.

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

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

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.

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

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.

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

additions.

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

multiplications and additions. The quadrant (0..90 degrees) is divided

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

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

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.

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

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?

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

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

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.

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.

-----

http://mindspring.com/~benbradley

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

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

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

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

It would have been simpler if you had stated your real

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.

#### Site Timeline

- » Atmel STK500 beginner Flash mem verification problem
- — Next thread in » Embedded Programming

- » is locked 8051 copy protected
- — Previous thread in » Embedded Programming

- » Embedded Ethernet
- — Newest thread in » Embedded Programming

- » Most efficient way to get 1.5 volts from 3.7 volts or less?
- — The site's Newest Thread. Posted in » Hobby Electronics Basics