My Attempt to Understand the Sine Table
Duane Degn
Posts: 10,588
This has been on my todo list for a while. I've wanted to understand how to use the sine table in the Propeller's ROM for several years but I never had a need for it in any of my projects. I finally took some time to see how it works.
Appendix B of the Propeller Manual explains the table well and gives and example of how to use the table from PASM.
I wanted to make sure I understood how the table worked so I make a Spin program to display the sine values of the angles from zero to ninety degrees.
Here's part of the output:
The first section of each line shows the ROM location being read and the raw 16-bit value at this location.
The final section of each line translates these values to more easily understood numbers. These final values show the angle (between 0 and 90 degrees) represented by the 16-bit location index and the corresponding 16-bit sine with the scale changed from 0 through 65,535 to 0 through 1.
Only integer math was used. The final result was scaled by a factor of 10,000 and displayed with a decimal point inserted in the correct location.
The program displays 32 lines and waits for a keypress to continue. I step the index by 16 so only 1/16 of the table is displayed (it's a big table).
Here's the program:
I'm sure there are many examples of accessing the sine table around and now there is one more.
I tried to keep the program simple. It doesn't do any of the tricks to compute the sine of angles other than 0 to 90 degrees and it doesn't attempt to compute the cosine of angles.
If any of you already familiar with how to use the sine table have a few minutes to spare, I'd appreciate your taking a look at the code to make sure I'm using the correct constants in my calculations. The results appear correct but I think they may also appear correct if I were a bit off (double meaning).
An archived version of the program is available as "MathTestSine" in my CncController GitHub repository.
Edit (September 7, 2015): I attached the archive to this post.
Appendix B of the Propeller Manual explains the table well and gives and example of how to use the table from PASM.
I wanted to make sure I understood how the table worked so I make a Spin program to display the sine values of the angles from zero to ninety degrees.
Here's part of the output:
Press any key to start program. word[$E000][$000] = $000 or word[57_344][0] = 0 | sin( 0.0000) = 0.0000 Press to continue. word[$E000][$010] = $324 or word[57_344][16] = 804 | sin( 0.7031) = 0.0122 word[$E000][$020] = $648 or word[57_344][32] = 1608 | sin( 1.4062) = 0.0245 word[$E000][$030] = $96C or word[57_344][48] = 2412 | sin( 2.1093) = 0.0368 word[$E000][$040] = $C90 or word[57_344][64] = 3216 | sin( 2.8125) = 0.0490 word[$E000][$050] = $FB3 or word[57_344][80] = 4019 | sin( 3.5156) = 0.0613 word[$E000][$060] = $2D5 or word[57_344][96] = 4821 | sin( 4.2187) = 0.0735 word[$E000][$070] = $5F7 or word[57_344][112] = 5623 | sin( 4.9218) = 0.0858 word[$E000][$080] = $918 or word[57_344][128] = 6424 | sin( 5.6250) = 0.0980 word[$E000][$090] = $C37 or word[57_344][144] = 7223 | sin( 6.3281) = 0.1102 word[$E000][$0A0] = $F56 or word[57_344][160] = 8022 | sin( 7.0312) = 0.1224 word[$E000][$0B0] = $274 or word[57_344][176] = 8820 | sin( 7.7343) = 0.1345 word[$E000][$0C0] = $590 or word[57_344][192] = 9616 | sin( 8.4375) = 0.1467 word[$E000][$0D0] = $8AB or word[57_344][208] = 10411 | sin( 9.1406) = 0.1588 word[$E000][$0E0] = $BC4 or word[57_344][224] = 11204 | sin( 9.8437) = 0.1709 word[$E000][$0F0] = $EDC or word[57_344][240] = 11996 | sin(10.5468) = 0.1830 <snip> word[$E000][$270] = $5E5 or word[57_344][624] = 30181 | sin(27.4218) = 0.4605 word[$E000][$280] = $8AD or word[57_344][640] = 30893 | sin(28.1250) = 0.4713 word[$E000][$290] = $B70 or word[57_344][656] = 31600 | sin(28.8281) = 0.4821 word[$E000][$2A0] = $E2E or word[57_344][672] = 32302 | sin(29.5312) = 0.4928 word[$E000][$2B0] = $0E7 or word[57_344][688] = 32999 | sin(30.2343) = 0.5035 word[$E000][$2C0] = $39C or word[57_344][704] = 33692 | sin(30.9375) = 0.5141 word[$E000][$2D0] = $64B or word[57_344][720] = 34379 | sin(31.6406) = 0.5245 word[$E000][$2E0] = $8F5 or word[57_344][736] = 35061 | sin(32.3437) = 0.5349 <snip> word[$E000][$3E0] = $085 or word[57_344][992] = 45189 | sin(43.5937) = 0.6895 word[$E000][$3F0] = $2C8 or word[57_344][1008] = 45768 | sin(44.2968) = 0.6983 word[$E000][$400] = $504 or word[57_344][1024] = 46340 | sin(45.0000) = 0.7071 Press to continue. word[$E000][$410] = $739 or word[57_344][1040] = 46905 | sin(45.7031) = 0.7157 word[$E000][$420] = $968 or word[57_344][1056] = 47464 | sin(46.4062) = 0.7242 <snip> word[$E000][$780] = $EC3 or word[57_344][1920] = 65219 | sin(84.3750) = 0.9951 word[$E000][$790] = $F0D or word[57_344][1936] = 65293 | sin(85.0781) = 0.9963 word[$E000][$7A0] = $F4D or word[57_344][1952] = 65357 | sin(85.7812) = 0.9972 word[$E000][$7B0] = $F84 or word[57_344][1968] = 65412 | sin(86.4843) = 0.9981 word[$E000][$7C0] = $FB0 or word[57_344][1984] = 65456 | sin(87.1875) = 0.9987 word[$E000][$7D0] = $FD3 or word[57_344][2000] = 65491 | sin(87.8906) = 0.9993 word[$E000][$7E0] = $FEB or word[57_344][2016] = 65515 | sin(88.5937) = 0.9996 word[$E000][$7F0] = $FFA or word[57_344][2032] = 65530 | sin(89.2968) = 0.9999 word[$E000][$800] = $FFF or word[57_344][2048] = 65535 | sin(90.0000) = 1.0000
The first section of each line shows the ROM location being read and the raw 16-bit value at this location.
The final section of each line translates these values to more easily understood numbers. These final values show the angle (between 0 and 90 degrees) represented by the 16-bit location index and the corresponding 16-bit sine with the scale changed from 0 through 65,535 to 0 through 1.
Only integer math was used. The final result was scaled by a factor of 10,000 and displayed with a decimal point inserted in the correct location.
The program displays 32 lines and waits for a keypress to continue. I step the index by 16 so only 1/16 of the table is displayed (it's a big table).
Here's the program:
CON _clkmode = xtal1 + pll16x _xinfreq = 5_000_000 SCALED_MULTIPLIER = 10_000 SCALED_DECIMAL_PLACES = 4 SCALED_NINETY_DEGREES = 90 * SCALED_MULTIPLIER SIZE_OF_SINE_TABLE = 2_049 ' From Propeller Manual MAX_TABLE_INDEX = SIZE_OF_SINE_TABLE - 1 ONE_AS_16_BITS = $FFFF ' sin(90) = $FFFF or 1 SINE_TABLE_LOCATION = $E000 OBJ Pst : "Parallax Serial Terminal" Format : "StrFmt" PUB Setup Pst.Start(115_200) repeat result := Pst.RxCount Pst.Str(string(11, 13, "Press any key to start program.")) waitcnt(clkfreq / 2 + cnt) until result Pst.RxFlush TestMath PUB TestMath | sineIndex repeat sineIndex from 0 to MAX_TABLE_INDEX step $10 Pst.Str(string(11, 13, "word[$E000][$")) ' get the raw values in hex and dec Pst.Hex(sineIndex, 3) Pst.Str(string("] = $")) Pst.Hex(word[SINE_TABLE_LOCATION][sineIndex], 3) Pst.Str(string(" or word[57_344][")) Pst.Dec(sineIndex) Pst.Str(string("] = ")) Pst.Dec(word[SINE_TABLE_LOCATION][sineIndex]) '' convert raw values to properly scaled values Pst.Str(string(" | sin(")) DecPoint(sineIndex * SCALED_NINETY_DEGREES / MAX_TABLE_INDEX, SCALED_DECIMAL_PLACES) Pst.Str(string(") = ")) DecPoint(word[SINE_TABLE_LOCATION][sineIndex] * SCALED_MULTIPLIER / ONE_AS_16_BITS, { } SCALED_DECIMAL_PLACES) ifnot sineIndex // $200 PressToContinue repeat ' Keep cog alive PUB PressToContinue Pst.Str(string(11, 13, "Press to continue.")) repeat result := Pst.RxCount until result Pst.RxFlush PUB DecPoint(value, decimalPlaces) | localBuffer[4] result := Format.FDec(@localBuffer, value, decimalPlaces + 3, decimalPlaces) byte[result] := 0 Pst.str(@localBuffer)
I'm sure there are many examples of accessing the sine table around and now there is one more.
I tried to keep the program simple. It doesn't do any of the tricks to compute the sine of angles other than 0 to 90 degrees and it doesn't attempt to compute the cosine of angles.
If any of you already familiar with how to use the sine table have a few minutes to spare, I'd appreciate your taking a look at the code to make sure I'm using the correct constants in my calculations. The results appear correct but I think they may also appear correct if I were a bit off (double meaning).
An archived version of the program is available as "MathTestSine" in my CncController GitHub repository.
Edit (September 7, 2015): I attached the archive to this post.
Comments
0.0 to 1.0
Its like using 0-10 instead of the usual 0-9 because you need entries for both 0 degrees and 90 degrees.
I think I took this into account in my code. With 2049 elements, the table would be indexed from 0 to 2048 right? With the index # 0 corresponding to 0 degrees and index # 2048 corresponding to 90 degrees. Right?
Were you just pointing out a possible "gotcha" to watch out for or were you pointing out an error in my program? I'm figuring it was the former so if I made a mistake please let me know.
Working in degrees:
sin(90) = 1
The table entry below that must be about:
sin(90 - 90 / 2048) = 0.9999997058628822
The difference between those being:
2.9413711777337426e-7
or about:
0.0000003
That difference is below 16 bit resolution of the table entries. So surely the last two entries of the table are the same. We don't need the 2049th entry.
What am I missing here?
Heater: that's true the last few entries are indeed ffff but then your program would need to check for this, so it's more complex and uses more code. Easier to make it 2049 entries being 0..2048.
The rom had space, but it meant the interpreter starts at $F004. There are a few sets spare in the rom, enough for me to split the runner into 3 parts, giving me 1KB of contiguous space for my interpreter 256 * long vector table in the P1V
I suppose it could be argued we don't need the zeroth entry either but IMO, the table as it is makes the most intuitive sense.
After reading this single sentence in the appendix about the sine table, I had a pretty good guess how it worked. I was pleasantly surprised how easy it was to convert between a table index and its corresponding degree value. Converting the 16-bit value to a scaled integer was also simple.
I personally think the sine table is just the way it should be.