Author Topic: Code used for sine table  (Read 19791 times)

0 Members and 1 Guest are viewing this topic.

Offline @rtTopic starter

  • Super Contributor
  • ***
  • Posts: 1059
Code used for sine table
« on: January 06, 2017, 10:35:25 am »
Hi Guys :)
I have an explicitly defined sine table in C that I’ve been using for years,
but now with a micro, as program memory gets short, I’d like to know how it could be generated in code if possible
....or pretty close to it.

I assume if I begin with just the empty 91 word array, it would be possible, with the right formula, to generate the
half cycle at run time just once, and continue to use it.
Any ideas appreciated!

Code: [Select]
WORD sin_table[91] ={
    0,   285,   571,   857,  1142,  1427,  1712,  1996,  2280,  2563,
    2845,  3126,  3406,  3685,  3963,  4240,  4516,  4790,  5062,  5334,
    5603,  5871,  6137,  6401,  6663,  6924,  7182,  7438,  7691,  7943,
    8191,  8438,  8682,  8923,  9161,  9397,  9630,  9860, 10086, 10310,
    10531, 10748, 10963, 11173, 11381, 11585, 11785, 11982, 12175, 12365,
    12550, 12732, 12910, 13084, 13254, 13420, 13582, 13740, 13894, 14043,
    14188, 14329, 14466, 14598, 14725, 14848, 14967, 15081, 15190, 15295,
    15395, 15491, 15582, 15668, 15749, 15825, 15897, 15964, 16025, 16082,
    16135, 16182, 16224, 16261, 16294, 16321, 16344, 16361, 16374, 16381,
    16384
};
 

Offline alexanderbrevig

  • Frequent Contributor
  • **
  • Posts: 700
  • Country: no
  • Musician, developer and EE hobbyist
    • alexanderbrevig.com
Re: Code used for sine table
« Reply #1 on: January 06, 2017, 10:38:16 am »
You could maybe move it from program memory to RAM, or more likely from RAM to program memory (guessing by the lack of qualifiers that you use RAM now).
For approximating with code I've had luck with Taylor series.
 

Offline @rtTopic starter

  • Super Contributor
  • ***
  • Posts: 1059
Re: Code used for sine table
« Reply #2 on: January 06, 2017, 10:45:49 am »
If I defined it as constant I presume that would save RAM, but RAM isn’t the issue.... I’m not short on it yet.
Because it’s explicitly defined this way, all 91 values have to first be stored in program memory somewhere before being loaded to RAM.
 

Offline alexanderbrevig

  • Frequent Contributor
  • **
  • Posts: 700
  • Country: no
  • Musician, developer and EE hobbyist
    • alexanderbrevig.com
Re: Code used for sine table
« Reply #3 on: January 06, 2017, 10:48:57 am »
Because it’s explicitly defined this way, all 91 values have to first be stored in program memory somewhere before being loaded to RAM.
:palm: of course you're right. Maybe the Taylor series was useful for you then?
 

Offline @rtTopic starter

  • Super Contributor
  • ***
  • Posts: 1059
Re: Code used for sine table
« Reply #4 on: January 06, 2017, 10:55:36 am »
I’m not familiar with it.. don’t claim to be a math guru of course.

I do have functions I’ve used to generate audio at given sample rates and frequencies which could do it,
but have no idea how to land it near the values I want.

It would look something like looping through this:

Code: [Select]
   const float PI2 = 3.14159265359f * 2;
    double x = PI2 * frequency * rate;
    buffer[index] = sin(x) * amplitude;

I’m thinking maybe run the audio on a big platform with debug,
and maybe play with it and see if I can get a table close.

 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7732
  • Country: ca
Re: Code used for sine table
« Reply #5 on: January 06, 2017, 10:59:58 am »

I assume if I begin with just the empty 91 word array, it would be possible, with the right formula, to generate the
half cycle at run time just once, and continue to use it.
Any ideas appreciated!

Code: [Select]
WORD sin_table[91] ={
    0,   285,   571,   857,  1142,  1427,  1712,  1996,  2280,  2563,
    2845,  3126,  3406,  3685,  3963,  4240,  4516,  4790,  5062,  5334,
    5603,  5871,  6137,  6401,  6663,  6924,  7182,  7438,  7691,  7943,
    8191,  8438,  8682,  8923,  9161,  9397,  9630,  9860, 10086, 10310,
    10531, 10748, 10963, 11173, 11381, 11585, 11785, 11982, 12175, 12365,
    12550, 12732, 12910, 13084, 13254, 13420, 13582, 13740, 13894, 14043,
    14188, 14329, 14466, 14598, 14725, 14848, 14967, 15081, 15190, 15295,
    15395, 15491, 15582, 15668, 15749, 15825, 15897, 15964, 16025, 16082,
    16135, 16182, 16224, 16261, 16294, 16321, 16344, 16361, 16374, 16381,
    16384
};

Am I looking at these numbers wrong, this table appears to contain the first 1/4 cycle of a sine wave, not half cycle.

How much lower in resolution is acceptable for this table?
Have you considered storing this table in the processor's flash mem, or external I2C prom, then loading it into ram for use?
Could you get away with an inverted '((x/xscale)^2)/amplitudefactor' 1/4 sine wave approximation?  Note that with 8 bit micros, just the 32 bit integer multiply & divide algorithms introduced by your C compiler may be longer than the 91 words of rom.

Also depending on compiler, defining a constant may eat twice or quadruple as much rom instruction words compared to storing the table as raw data table in free rom space, as long as your MCU can read op-code as data for those MCUs which have the feature.  You will need to create a table-read loop to read the flash rom into ram yourself, but, you will cut the instruction mem size of the table by as much as 4 fold in some cases, + the instructions of the table-read loop to copy that rom space into usable ram.
« Last Edit: January 06, 2017, 11:16:25 am by BrianHG »
 

Online tggzzz

  • Super Contributor
  • ***
  • Posts: 19485
  • Country: gb
  • Numbers, not adjectives
    • Having fun doing more, with less
Re: Code used for sine table
« Reply #6 on: January 06, 2017, 11:24:10 am »
In 1974 a 4-function plus trig functions calculator was implemented in 320 instructions. Total. Including i/o operations.

You might find inspiration by studying how it was done: http://files.righto.com/calculator/sinclair_scientific_simulator.html

Or there's always CORDIC, of course.
There are lies, damned lies, statistics - and ADC/DAC specs.
Glider pilot's aphorism: "there is no substitute for span". Retort: "There is a substitute: skill+imagination. But you can buy span".
Having fun doing more, with less
 
The following users thanked this post: albert22

Offline iaeen

  • Regular Contributor
  • *
  • Posts: 65
  • Country: us
Re: Code used for sine table
« Reply #7 on: January 06, 2017, 11:28:27 am »
Yeah, a half cycle should return to 0 at 180 degrees. This looks like 90 degrees which is a quarter cycle. It's still enough to get the value of sine for any angle though...

I do believe that Taylor expansions are used by modern calculators/computers to get these values, so that is what you should look into. On the other hand, calculators need to be able to return a whole range of functions (all the trig functions, exp, log, etc...), so they can't afford to waste memory on tables. If you don't have that limitation, it might make sense to use a table if your processor can retrieve the value from memory faster than it can do the calculation.
 

Offline @rtTopic starter

  • Super Contributor
  • ***
  • Posts: 1059
Re: Code used for sine table
« Reply #8 on: January 06, 2017, 11:32:54 am »
You could call it a 1/4 wave because it’s all positive, but it’s indexed from 0-90,
and then the indexing reverses direction and reads the array backward,
so in the end, if used for sine text or plasma, etc, you end up with a sine wave.

I presume to originally save memory because it’s many years old.


I’ve sort of had luck with my audio function... kinda :D I think maybe using the wrong variable types.

The micro is dsPic with software FP. All of the trig is already in code, so introducing trig calls shouldn’t consume more memory.
 

Offline GK

  • Super Contributor
  • ***
  • Posts: 2607
  • Country: au
Re: Code used for sine table
« Reply #9 on: January 06, 2017, 11:33:15 am »
Solving these two coupled differential equations will do it.

dsine/dt = cos
dcos/dt = -sine

I'm not a mathematician either and I'm not necessarily saying that this is an efficient solution, and the code example is in BASIC rather than C. This is how I solved the problem on one lazy day just out of idle curiosity on my Beeb. I can't figure an integration algorithm stripped any barer.




« Last Edit: January 06, 2017, 11:36:58 am by GK »
Bzzzzt. No longer care, over this forum shit.........ZZzzzzzzzzzzzzzzz
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7732
  • Country: ca
Re: Code used for sine table
« Reply #10 on: January 06, 2017, 11:36:56 am »
In 1974 a 4-function plus trig functions calculator was implemented in 320 instructions. Total. Including i/o operations.

You might find inspiration by studying how it was done: http://files.righto.com/calculator/sinclair_scientific_simulator.html

Or there's always CORDIC, of course.

Wow... Reminds me of doing everything in early PIC assembly in the 90s.
Today with C programming, I think just an initialize for-loop eats more than that.
Without knowing the CPU being used and which compiler, I cant say doing the math might be the right solution.  As the question was given, with a smaller 8 bit PIC, I would choose a processor with user flash eerom and store the sine table there.  It appears every bit of program rom space is being used up already.  This probably means floating point is out of the question, and maybe even divide.
-------------------------------------------------------------------
Oops, updates were given while I was typing....
-------------------------------------------------------------------
If you are using a dspic, with floats already in use, use GK's solution, If I am reading my basic right...

« Last Edit: January 06, 2017, 11:43:35 am by BrianHG »
 

Offline @rtTopic starter

  • Super Contributor
  • ***
  • Posts: 1059
Re: Code used for sine table
« Reply #11 on: January 06, 2017, 11:42:26 am »
What’s the display resolution?

You probably wouldn’t believe I wrote this from scratch by scaling the audio generator.
If I can dig up any of that I’m set.

 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7732
  • Country: ca
Re: Code used for sine table
« Reply #12 on: January 06, 2017, 11:47:11 am »
Looking at GK's code, changing the CONST value will scale the amplitude and definition of the sine wave.  Also, the range on the 'for x' will change as well.
 

Offline GK

  • Super Contributor
  • ***
  • Posts: 2607
  • Country: au
Re: Code used for sine table
« Reply #13 on: January 06, 2017, 11:52:13 am »
Yes, the smaller the CONST variable, the finer the effective integration step. Good luck implementing this in code that takes up less room than a pi/2 look-up table though.
 
Bzzzzt. No longer care, over this forum shit.........ZZzzzzzzzzzzzzzzz
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7732
  • Country: ca
Re: Code used for sine table
« Reply #14 on: January 06, 2017, 11:55:18 am »
To get the resolution of the video, with such a low res fixed sine table, you will need to interpolate/up sample the fixed table.
GKs basic code should be able to synth a really high res table, but, since it is progressively computed, if you want rapid random point access, you will need to render and store at least the first 1/4 of the sine in a ram table.
Summing up sine waves from different points in the table to synth a complex waveform with multiple frequencies and amplitudes becomes easy from that point on.
« Last Edit: January 06, 2017, 12:01:58 pm by BrianHG »
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7732
  • Country: ca
Re: Code used for sine table
« Reply #15 on: January 06, 2017, 11:59:30 am »
Which DSPic will you be using?  Many have user eeproms for efficiently storing your table.  In fact, you can make a huge table with the 1k or 2k devices which can be read directly as needed, instead of eating up CPU ram.

« Last Edit: January 06, 2017, 12:03:28 pm by BrianHG »
 

Offline @rtTopic starter

  • Super Contributor
  • ***
  • Posts: 1059
Re: Code used for sine table
« Reply #16 on: January 06, 2017, 12:04:24 pm »
No eeprom, but a thought occurred to me.

I have already implemented a function that rotates a point (at angle) about an origin.
If I define a point 16384 pixels below an origin, I should only have to step through a loop of 90 steps for each angle integer,
and read only the y coordinate of the point into the sine array.

Other than the loop, that would be free since the point rotation function already exists.

Finding the code for the video above, that’s how I generated the waves, not with an audio function.

« Last Edit: January 06, 2017, 12:06:04 pm by @rt »
 

Offline @rtTopic starter

  • Super Contributor
  • ***
  • Posts: 1059
Re: Code used for sine table
« Reply #17 on: January 06, 2017, 12:48:32 pm »
and done yay :)

It’s the function pixel_rotation that already existed. Normally for rotating a point on display, but I don’t need to draw this.
In the added code, the variables that are cleared are already clear, so those can probably go too.


Code: [Select]
// generate sine table
n = 0;
rotation = 0;
while (n < 91) {
ox = 0; oy = 0;
x = 16384; y = 0;
pixelrotation();
sin_table[n] = y;
rotation++;
n++;
}


void pixelrotation() {
theta = rotation; // pre calculation
thetab = 360 - theta;
thetab = d2r * theta;
xx = x; yy = y;
rx = xx - ox; ry = yy - oy;
xnew = cos(thetab)*rx - sin(thetab)*ry;
ynew = sin(thetab)*rx + cos(thetab)*ry;
xnew = xnew + ox; ynew = ynew + oy;
x = xnew; y = ynew;
}


 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7732
  • Country: ca
Re: Code used for sine table
« Reply #18 on: January 06, 2017, 01:04:41 pm »
Hold on a sec, you wanted a part of a sine table and you were willing to use the 'sin()' command?  In this case, you've over engineered your code.
Or, did you just add additional functionality to your code?

sin_table[n] = sin(pi*(n/90)/2) * 16384;

I hope I got my #s right...
« Last Edit: January 06, 2017, 01:50:05 pm by BrianHG »
 

Offline rs20

  • Super Contributor
  • ***
  • Posts: 2318
  • Country: au
Re: Code used for sine table
« Reply #19 on: January 06, 2017, 01:08:03 pm »
I guess we all forgot to answer the OPs question by suggesting to use sin() :-)

sin_table[n] = sin(pi*(n/91)/4) * 16384;

I suspect you need to cast to a float in there somewhere, or else 90/91 will evaluate to integer 0 (and also please, use "i" as your iteration variable, "n" almost always means the total count...)
« Last Edit: January 06, 2017, 01:09:56 pm by rs20 »
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7732
  • Country: ca
Re: Code used for sine table
« Reply #20 on: January 06, 2017, 01:36:41 pm »
In the math line using the Pic XC32/16 compiler, thanks to the sin() function, it should evaluate everything as a float until it is converted into an integer for the table word.  This code is so simple, it is easy to test in M-Chip's compiler and view your table's memory contents.

Here is my test code in basic:
Code: [Select]
const pi = atn(1) * 4
dim as integer n,sin_t

 for n=0 to 90
  sin_t = sin(pi*(n/90)/2) * 16384
  Print sin_t;",";
 next n

END

Here is the output:
Code: [Select]
0, 286, 572, 857, 1143, 1428, 1713, 1997, 2280, 2563,
2845, 3126, 3406, 3686, 3964, 4240, 4516, 4790, 5063, 5334,
5604, 5872, 6138, 6402, 6664, 6924, 7182, 7438, 7692, 7943,
8192, 8438, 8682, 8923, 9162, 9397, 9630, 9860, 10087, 10311,
10531, 10749, 10963, 11174, 11381, 11585, 11786, 11982, 12176, 12365,
12551, 12733, 12911, 13085, 13255, 13421, 13583, 13741, 13894, 14044,
14189, 14330, 14466, 14598, 14726, 14849, 14968, 15082, 15191, 15296,
15396, 15491, 15582, 15668, 15749, 15826, 15897, 15964, 16026, 16083,
16135, 16182, 16225, 16262, 16294, 16322, 16344, 16362, 16374, 16382,
16384,

There is a slight rounding error of 1 compared to the original table, but, This is the targeted 1/4 sine wave.
« Last Edit: January 06, 2017, 02:03:05 pm by BrianHG »
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7732
  • Country: ca
Re: Code used for sine table
« Reply #21 on: January 06, 2017, 01:57:00 pm »
Now, for my code, if you want to quickly use the 1/4 sine wave with 4 quadrants, if it were me, I would change the 90s to 127 making the table a little wider and when reading a full sine, I would expect a range from 0 to 511, using bits 8 and 9 in the pointer to quickly flip and mirror the read table read position of 0-127 giving you a full sine wave.  It also makes ignoring higher bits in the pointer address if you are synthesizing variable frequency sine waves from this one reference table by adding a fixed number to an integer, or float, then converting it to an integer.

Remember, everything I've recommended up until now has been in effort to minimize compute time when in use and minimal memory.  If you have the computing processing time, I would just use the sin() command all the time and forget about the table all together.
« Last Edit: January 06, 2017, 02:01:16 pm by BrianHG »
 

Offline snarkysparky

  • Frequent Contributor
  • **
  • Posts: 414
  • Country: us
Re: Code used for sine table
« Reply #22 on: January 06, 2017, 02:08:16 pm »

Page 4 of this paper gives some polynomial approximations to the sin function.  You can use them to build your table.

http://krisgarrett.net/papers/l2approx.pdf

A.1 Sine on [??, ?]
+ 3.03963550927013314332e-01x
Pointwise Error Estimate: 9.54929658551371892153e-01

- 9.33876972831853619134e-02x^3 + 8.56983327795249506462e-01x
Pointwise Error Estimate: 2.03312253648039771447e-01

+ 5.64311797634681035370e-03x^5 - 1.55271410633428644799e-01x^3
+ 9.87862135574673806965e-01x
Pointwise Error Estimate: 1.59772935681895954411e-02

- 1.47740880797318521837e-04x^7 + 7.99858143743132551201e-03x^5
- 1.65838452698030873892e-01x^3 + 9.99450193893262089505e-01x
Pointwise Error Estimate: 6.64973349774765786287e-04

+ 2.17326217498596729611e-06x^9 - 1.93162796407356830500e-04x^7
+ 8.31238887417884598346e-03x^5 - 1.66632595072086745320e-01x^3
+ 9.99984594193494365437e-01x

Pointwise Error Estimate: 1.72333528683927437958e-05
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7732
  • Country: ca
Re: Code used for sine table
« Reply #23 on: January 06, 2017, 02:15:27 pm »
One last thing about positive and negative sine quadrants, you have 16384 as the sines peak. Since you are using words, I assume you might want to change it to a gain of 32767, making a sine from -32767 to +32767.  Don't use 32768, since that number is actually -1 as a signed word.
 

Offline @rtTopic starter

  • Super Contributor
  • ***
  • Posts: 1059
Re: Code used for sine table
« Reply #24 on: January 06, 2017, 02:15:52 pm »
Yes I didn't say I wasn't willing to use the trig.
It still has to generate the table so that can be used fast.

The function Pixel_rotation was already in my graphics code.
The top part just has to be a worthwhile trade off for the values being defined.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf