# Thread: Sinus calculating !

1. ## Sinus calculating !

HI

I want to make a low frequency sinewave generator, but with low distorsion, with a PIC.Haw can I calculate sin with 10 or 12 bits resolution ?

Thanks for your help

Don Mario

2. Hello Don,

Don>>I want to make a low frequency sinewave generator, but with low distorsion, with a PIC.Haw can I calculate sin with 10 or 12 bits resolution ?<<

Here is a start, using a Ladder system, Modification of this can produce a cleaner wave.

http://www.ke4nyv.com/picprojects.htm

3. Duh... "Low-Distortion Sine" and "Digital Switching" are not happy bedfellows... You cannot create a 'pure' (for 'pure' read 'low-distortion') sinewave from a device that's going to switch digitally (ie on/off). If you create a sinewave from your 10 or 12-bit component, and you magnify the edge, it'll still have little square-shaped teeth marks in it. Those teeth marks will have sharp square edges... and square edges give high frequency harmonics... so your sine-wave (especially ladder network created types) will be as pure as the driven slush.

4. Hello Melanie,

Melanie>>If you create a sinewave from your 10 or 12-bit component, and you magnify the edge, it'll still have little square-shaped teeth marks in it. Those teeth marks will have sharp square edges... and square edges give high frequency harmonics... so your sine-wave (especially ladder network created types) will be as pure as the driven slush.<<

You are correct...But some folks like the el-spike-o sine wave. <g>.

then you have the problem of the negative 5 volts too. Thus your signwave is actually betwen 0 and 5 volts. Oh well. I figured by the time a person wastes creating such a wave, they might as well turn a magnet within a coil of wire <g>.

But I also have to admit, I enjoy building things as such for the experience and practice.

Dwayne

5. >> they might as well turn a magnet within a coil of wire

and if you use a stepper motor to turn the magnet you can have the all-familiar crinkly edges to your waveform...

Despite everything, it's an analogue world, and there's some applications that's just plain daft to put a digital device (like a PIC) to.

6. ## sinus calculating is a big problem ?

I understand and I respect your opinion.I can handle teeth with a low pass filter,but tell me if you know,how can I calculate sinus function with 10 or 12 bits resolution.In PBP exist sin function but with 8 bits.

Thank you very much

Don Mario

7. Hello Don,

Don>>I understand and I respect your opinion.I can handle teeth with a low pass filter,but tell me if you know,how can I calculate sinus function with 10 or 12 bits resolution.In PBP exist sin function but with 8 bits.<<

I gave you a link to a site that uses a Ladder to builid a sin wave on my previous response. Please check it out. If that is not what you want, I apologize for the wrong info.

Dwayne

8. ## 4 bits example !

Dwayne,I thank you but your example is on 4 bits and I'm interested in a calculation routine (if it's possible in basic) for sinewave with resolution of 10 or 12 bits.
I think it's possible to calculate this with math function in PBP.
But I'm not good in math and I need some help.

Thanks again

Don Mario

9. Hello Don,

Don>>Dwayne,I thank you but your example is on 4 bits and I'm interested in a calculation routine (if it's possible in basic) for sinewave with resolution of 10 or 12 bits.
I think it's possible to calculate this with math function in PBP.
But I'm not good in math and I need some help.<<

Then expand the resistors (by doubling them) and use more Pins. the principal is the same. You only add more resistors and pins to whatever resolution you want.

You can have port b represent the first 8 bits, and Part of Port A represent the last 2 to 4 bits..... connect up the resistors in the same ladder configuration, and repeat the pattern for 10 to 12 bits, instead of 4 bits in the example.

If you notice, they are only doing a binary count. And you can do that with the port.

Portb=0;
Porta=0;

Loop:
Portb=portb+1;
if(Portb=0000) then Porta.0=Porta+1
if(Porta>3) then Porta=0;
goto Loop:

This is a simplfied 10 bit code.

Dwayne

10. The problem is that PBP doesn't do floats... it doesn't mean it's not impossible, just tricky to impliment with precision. Here's all the information to get you going... I don't want to do all the work for you... after all, I've got a few programming secrets to guard as well so I'll get you started down the road...

Most computers, pocket caluculators use the Taylor method which only involves using add, subtract, divide and multiply which every computer - including PICs - can simply do, and we can do on a piece of paper)...

where x is in radians...

actually sin(x)=x (where x of course is in radians) is pretty good for angles up to about 10 degrees, after which the errors start to creep in siginficatly and we need the rest of the formula to pull us back into shape.

PICBasic integers can only go to just over four and a half significant figures (65535), and that's the tricky bit to ensure you don't spill out of that. You have to scale everything appropriately for maximum precision and use DIV32 to bring-back the result into the realms of integers if you spill out.

Firstly, you don't need to go 'ad-infinitum'... because just two iterrations will give precision beyond five figures anyway, so the formula can be reduced to...

sin(x)=x-(x^3/3!)+(x^5/5!)

Secondly, you never need to go beyond 90 degrees because Sine is a repeating function. All you have to do is remember that from 180-360 degrees the answer is negative.

Execute your code in three simple steps...

1. Determine x
2. Subtract the first correction (x^3/3!)
3. Add-in the second correction (x^5/5!). Now most of this is beyond four decimal places so you might want to consider leaving this step out.

sin(x)=x (working out x) is easy and application of a little bit of calculus (remember math at school? - OK you were the kid that was asleep and I was the kid that brought the apple for the teacher) can reduce this to...

x=angle*2*Pi/360, where angle is in degrees. Now if we wanted degrees equivallent to one decimal place... ie 30.2 degrees, we simply scale up by a factor of ten (ie 302)...

scaling and a bit of math gives us

x=angle(our 302 example)*15707/900 (use DIV32 to achieve the result and pull us back into the world of integers)... which (our 30.2 degree example) is 5270 (that's four degrees of precision representing an actual 0.5270 radians).

That gives us our primary answer for x will always be in the range of 0-15707 now this equates in real-world terms to 0-1.5707. Now if you'll notice 90 degrees is actually 1.5707 radians. wow... four decimal points of precision here converting degrees to radians... - try it on a scientific calculator and see how close our 'simple' integer math is to the real answer...

This already is pretty good, and if your Sine angle is less than ten degrees you can reasonably stop here... but if you angle is between 10 and 90 degrees you need some corrections otherwise you'll be wildly out the larger the angle...

So now you need to subtract-out the first correction... x^3/3!

We've worked out what x is, PICBasics doesn't do Powers but we can cope with that the long-way. Division '/' we've got, and calculus tells us that 3! is 6 (the factorial function of (n*(n-1)*(n-2)*... etc)

which reduces our first correction formula to simply...

x*x*x/6

Just remember the scale factor when subtracting out from the original result... tricky? yes, impossible? No.

Have fun...

11. ## Sinus OK !

Thank you very much,Melanie ! I'll try your method for sinus calculation and I'll tell you the answer !

Don Mario

12. There is another SINE calculation which I will post here for everyone's benefit... it's not quite 'kosher' but has been adjusted by me to give a more harmonised result at the top end... that is the Sine of 90 will equal 1 and the Sine of 89.9 will equal 0.99998 rather than respectively 1.000004 and 1.000002 which it would do if you used 362800 as the classical 4th correction.

Yes, it works 'as is' with floats (try it with GWBASIC or similar), but you can impliment it with PBP math if you're skillful enough to keep track of powers separately from significant figures... again, it uses only the four basic * / + - math operators.

I've deliberately written it as above to simply break-down the individual steps, as one long formula on a single line is a little hard to swallow by those folks that are a bit weak on maths.

All the formula's I've posted are best used for angles 0-90 and since sine is a repeating function, a couple of lines of pre-processing math can determine that angles 90-180 are mirror images of 0-90, and that angles 180-360 are simply negative.

Melanie

13. Hello Melanie,

Ouch, its been 25 years since Calc and Ser/Diff..

Wasn;t this called the Taylor series?

Dwayne

14. ## It's possible ?

Ok DWAYNE,

But is possible to aplly this metode with PBP ?

Thanks

Don Mario

15. >> Wasn;t this called the Taylor series?

That's what I said in my post (2nd paragraph)!

And yes, you can do both methods in PBP if you think about it carefully.

16. I hope that similar math can be done for arcsin function?
Does somebody know Taylor expression?

17. Hi Don,

You say you want to make a "low frequency sinewave generator". Which frequencies are we talking about(highest)? Is it supposed to do anything else than produce this sinewave? How do you intend to control it? Which pic are you planning to use?

I'm asking all theese questions cause i know a way to do this(DDS or NCO), but im not sure it fits your application. I have it woking with 8 bit resolution, i'll see if it can be expanded to 10 or 12 bits. The sin part is a lookuptable, the "DDSengine" is assembler.

/Ingvar

18. ## 100 Hz max !

The maximum frequency is 100Hz and I want to use PIC 16F877.
But I want to use sinus calculating because lookuptable use to much memory for 1024 points (10bits) or 4096 points (12bits).

Don Mario

19. The easiest method for anyone is to save 89 angles (at say 1 degree intervals from 1-89 degrees) into internal EEPROM, and interpolate the intermediate points. Your accuracy will be remarkably close and you can impliment the code in about five minutes.

20. Here we go... third method of getting accurate Sines... no DIV32 statements, accuracy to at least three decimal places and 99% of the time you'll get four decimal places... near instant calculation etc etc... also brews Cappuccino, Late and Expresso on the side...

Yes, with simple PBP we take an ANGLE to TWO DECIMAL PLACES (what? decimal places with integers?) and produce an example of SINE to FOUR DECIMAL PLACES... who need floats when you've got integers?...

Example 1.

Sine of 135.57 Degrees
Result 0.7000
Actual 0.700037341

Example 2.

Sine of 45.25 Degrees
Result 0.7101
Actual 0.710185375

Example 3.

Sine of 186.66 Degrees
Result -0.0638
Actual -0.063836616

Do NOT get worried about the size of this code... the ONLY important bit is the CalculateSine subroutine and the EEPROM statements, the rest is window-dressing to make pretty displays and for easy data-entry.

Code:
```	'	Sine Calculation - Interpolated Method
'	======================================
'	Melanie Newman
'	15/Sept/2004

'	Program demonstrates SINE calculation
'	using a simple interpolative method.
'	Input Angles valid from 0-359.99 degrees
'	Output SINE to four decimal places ie 1.0000

'	Display is on 2-line LCD with 3 buttons
'	Same circuit layout as per 'Olympic Timer' previously posted.

'
'	PIC Defines
'	===========
'
'	Change these defines to suit your chosen PIC
'	Your PIC must have 180 Bytes of EEPROM
'
@ DEVICE pic16F876, XT_OSC
@ DEVICE pic16F876, WDT_ON
@ DEVICE pic16F876, PWRT_ON
@ DEVICE pic16F876, BOD_ON
@ DEVICE pic16F876, LVP_OFF
@ DEVICE pic16F876, CPD_OFF
@ DEVICE pic16F876, PROTECT_OFF
@ DEVICE pic16F876, WRT_OFF

'
'	Hardware Defines
'	================
'
' 	LCD Display
'	-----------
'	Adjust these to suit your chosen LCD pinout
'
Define LCD_DREG PORTC	' Port for LCD Data
Define LCD_DBIT 4	' Use upper 4 bits of Port
Define LCD_RSREG PORTC	' Port for RegisterSelect (RS) bit
Define LCD_RSBIT 0	' Port Pin for RS bit
Define LCD_EREG PORTC	' Port for Enable (E) bit
Define LCD_EBIT 3	' Port Pin for E bit
Define LCB_BITS 4	' Using 4-bit bus
Define LCD_LINES 2	' Using 2 line Display
Define LCD_COMMANDUS 2000
' Command Delay (uS)
Define LCD_DATAUS 50	' Data Delay (uS)

'
'	Control Buttons/Lines
'	---------------------
ButtonUp var PortB.0		' Take this pin low momentarily to INCREMENT
ButtonDown var PortB.1		' Take this pin low momentarily to DECREMENT
ButtonSet var PortB.2		' Take this pin low momentarily to SET

'
'	Software Defines
'	----------------
Angle var WORD			' Input angle 0-36000 representing 0.00-360.00 degrees
CounterA var BYTE
KeyBut var BYTE			' Keyboard Button Code
Sine var WORD			' Sine value 0-10000 representing 0-1.0000
SineMax var WORD		' High-end of Lookup
SineMin var WORD		' Low-end of Lookup
SineNeg var BIT			' Flag indicating Negative answer
TempA var WORD
TempB var BYTE
UserData var BYTE[5]		' User-Entry Edit Field
UserMax var BYTE		' Variable to keep numeric entry within integer limitations
UserPos var BYTE		' User Entry Field Position

'
'	EEPROM Presets
'	--------------
Data @0,\$00,\$AF			'   1 =  175 (Sine of 1 Degree = 0.0175)
Data \$01,\$5D			'   2 =  349 (Sine of 2 Degrees - 0.0349)
Data \$02,\$0B			'   etc, etc
Data \$02,\$BA
Data \$03,\$68
Data \$04,\$15
Data \$04,\$C3
Data \$05,\$70
Data \$06,\$1C
Data \$06,\$C8
Data \$07,\$74
Data \$08,\$1F
Data \$08,\$CA
Data \$09,\$73
Data \$0A,\$1C
Data \$0A,\$C4
Data \$0B,\$6C
Data \$0C,\$12
Data \$0C,\$B8
Data \$0D,\$5C
Data \$0E,\$00
Data \$0E,\$A2
Data \$0F,\$43
Data \$0F,\$E3
Data \$10,\$82
Data \$11,\$20
Data \$11,\$BC
Data \$12,\$57
Data \$12,\$F0
Data \$13,\$88
Data \$14,\$1E
Data \$14,\$B3
Data \$15,\$46
Data \$15,\$D8
Data \$16,\$68
Data \$16,\$F6
Data \$17,\$82
Data \$18,\$0D
Data \$18,\$95
Data \$19,\$1C
Data \$19,\$A1
Data \$1A,\$23
Data \$1A,\$A4
Data \$1B,\$23
Data \$1B,\$9F
Data \$1C,\$19
Data \$1C,\$92
Data \$1D,\$07
Data \$1D,\$7B
Data \$1D,\$EC
Data \$1E,\$5B
Data \$1E,\$C8
Data \$1F,\$32
Data \$1F,\$9A
Data \$20,\$00
Data \$20,\$62
Data \$20,\$C3
Data \$21,\$20
Data \$21,\$7C
Data \$21,\$D4
Data \$22,\$2A
Data \$22,\$7D
Data \$22,\$CE
Data \$23,\$1C
Data \$23,\$67
Data \$23,\$AF
Data \$23,\$F5
Data \$24,\$38
Data \$24,\$78
Data \$24,\$B5
Data \$24,\$EF
Data \$25,\$27
Data \$25,\$5B
Data \$25,\$8D
Data \$25,\$BB
Data \$25,\$E7
Data \$26,\$10
Data \$26,\$35
Data \$26,\$58
Data \$26,\$78
Data \$26,\$95
Data \$26,\$AF
Data \$26,\$C5
Data \$26,\$D9
Data \$26,\$EA
Data \$26,\$F8
Data \$27,\$02
Data \$27,\$09
Data \$27,\$0E

'
'	Start Program
'	=============

'
'	Initialise Processor
'	--------------------
TRISA=%00000001
TRISB=%11111111
TRISC=%00000000
OPTION_REG.7=0			' Enable Pull-Up's
Pause 1000
Angle=0
'
'	Enter Data
'	----------
'	This section gets variable ANGLE
'	ANGLE is a value 0-36000 where 36000 represents 360.00 Degrees.
'	Press UP/DOWN Buttons to set the Angle 0-360, then Press SET to Accept the value
'
Loop:
LCDOut \$FE,\$01,\$FE,\$0E,"Angle "
Gosub DisplayAngle
LCDOut " Deg"
UserPos=0
Gosub UserEntry
If Angle>35999 then
LCDOut \$FE,1,"Angle must be",\$FE,\$C0,"less than 360.00"
Pause 1000
goto Loop
endif

'
'	Calculate & Display SINE
'	------------------------
' 	This section gets and Displays the resultant variable SINE
'
Gosub CalculateSine
LCDout \$FE,\$C0,"Sine "
If SineNeg=1 then LCDOut "-"
LCDOut #SINE DIG 4,".",#SINE DIG 3,#SINE DIG 2,#SINE DIG 1,#SINE DIG 0
'
'	Loop around again (Press SET to Continue)
'	-----------------------------------------
While KeyBut<>3:Gosub GetKey:Wend
LCDOut \$FE,1
While KeyBut<>7:Gosub GetKey:Wend
Goto Loop

'
'	Subroutine Calculates Sine
'	--------------------------
CalculateSine:
SineNeg=0
If ANGLE>18000 then SineNeg=1	' Determine if negative Result
TempA=Angle			' Reduce angle to 1st Quadrant (0-90 degrees only)
If TempA>17999 then TempA=TempA-18000
If TempA>9000 then TempA=9000-(TempA-9000)
'
'	Load Low-End of Lookup
'	----------------------
CounterA=TempA/100
If CounterA=0 then
SineMin=0
else
If CounterA=90 then
SineMin=10000
else
endif
endif
'
'	Load High-End of Lookup
'	-----------------------
CounterA=CounterA+1
If CounterA=>90 then
SineMax=10000
else
endif
'
'	Determine the Decimal Fraction (Interpolation) Bit
'	--------------------------------------------------
TempB=TempA-((TempA/100)*100)
Sine=SineMin+(((SineMax-SineMin)*TempB)/100)
Return

'
'	Subroutine Reassembles User-Entered Angle
'	-----------------------------------------
ReassembleAngle:
Angle=UserData(0)*10000
Angle=Angle+(UserData(1)*1000)
Angle=Angle+(UserData(2)*100)
Angle=Angle+(UserData(3)*10)
Angle=Angle+UserData(4)
'
'	subroutine Displays Angle
'	-------------------------
DisplayAngle:
LCDOut \$FE,\$86,\$FE,\$0C
If Angle>9999 then
LCDOut #ANGLE DIG 4
else
LCDOut " "
endif
If Angle>999 then
LCDOut #ANGLE DIG 3
else
LCDOut " "
endif
LCDOut #ANGLE DIG 2,".",#ANGLE DIG 1,#ANGLE DIG 0
Return

'
'	Subroutine Scans Buttons
'	------------------------
' KeyBut - 0 = Invalid (SET+UP+DOWN Pressed)
'	 - 1 = Invalid (SET+UP Pressed)
'	 - 2 = Invalid (SET+DOWN Pressed)
'	 - 3 = SET Pressed
'	 - 4 = Invalid (UP+DOWN Pressed)
'	 - 5 = UP Pressed
'	 - 6 = DOWN Pressed
'	 - 7 = No Buttons Pressed
GetKey:
KeyBut=0			' Zero any previous Result First
KeyBut.0=ButtonDown		' Read Input Buttons
KeyBut.1=ButtonUp
KeyBut.2=ButtonSet
Pause 100			' Allows for 10cps auto-repeat
Return

'
'	Subroutine performs User Numeric Field Entry
'	--------------------------------------------
UserEntry:
For CounterA=0 to 4
UserData(CounterA)=Angle DIG (4-CounterA)
Next CounterA
UserEntryLoop:
CounterA=\$86+UserPos
If UserPos>2 then CounterA=CounterA+1
LCDOut \$FE,CounterA,\$FE,\$0E
UserEntryLoopSkip:
Gosub GetKey
UserMax=9
If UserPos=0 then UserMAX=3
If KeyBut=5 then
UserData(UserPos)=UserData(UserPos)+1
If UserData(UserPos)>UserMAX then UserData(UserPos)=0
gosub ReassembleAngle
goto UserEntryLoop
endif
If KeyBut=6 then
If UserData(UserPos)=0 then
UserData(UserPos)=UserMAX
else
UserData(UserPos)=UserData(UserPos)-1
endif
gosub ReassembleAngle
goto UserEntryLoop
endif
If KeyBut<>3 then goto UserEntryLoopSkip
While KeyBut<>7:Gosub GetKey:Wend
UserPos=UserPos+1
If UserPos<5 then goto UserEntry
Return

End```
There you go... with only 178 EEPROM statements you've got 36,000 points on your Sine graph.

Have fun...

Melanie

21. ## Splendid !

I'll try ! I'll like it ! It's great Melanie !
I think it's a very good solution.

Thank you very much

Don Mario

22. There was a small typo and some redundent code (in my haste to get it all done this lunchtime) which has now been corrected, so if anyone copied it before the time & date on this message, please copy it again.

23. Hello Melanie,

Melanie>>Here we go... third method of getting accurate Sines... no DIV32 statements, accuracy to at least three decimal places and 99% of the time you'll get four decimal places... near instant calculation etc etc... also brews Cappuccino, Late and Expresso on the side...<<

I wanted it accurate to 32 places....<chuckle>. I am here at work, 200 miles away from home, for 4 days working on computers, and when I read this, I just broke up laughing. When its 2 in the morning, splicing together a computer network and related programs in a LAN / WAN system, and to come across this code just made my day/night.

Dwayne

24. If you want a giggle...go onto the MeLabs website, search the PICBasic forum there using +Coin +Jog as the search criteria... and read my reply to that thread...

25. ## Sin, Cos, Tan, etc.

Just thought I'd add to what Melanie, Dwayne and the other smart folks who always give so much of their time and experience to us here have added...

Melanie gave the series formula for calculating sin(x)...here are a few others...(remember, x is in radians)

sin (x)= x - (x^3/3!) + (x^5/5!) - (x^7/7!) + (x^9/9!) ...

cos (x)= 1 - (x^2/2!) + (x^4/4!) - (x^6/6!) + (x^8/8!) ...

tan (x) = x + (x^3/3) + (2x^5/15) + (17x^7/315) ...

sinh (x)= x + (x^3/3!) + (x^5/5!) + (x^7/7!) + (x^9/9!) ...

cosh (x)= 1 + (x^2/2!) + (x^4/4!) + (x^6/6!) + (x^8/8!) ...

e^x = 1 + x + (x^2/2!) + (x^3/3!) + (x^4/4!) + ...

log (x) = 2[((x-1)/x+1)) + 1/3((x-1|)/(x+1))^3 + 1/5((x-1)/(x+1))^5+...]

Well, good luck...

Carl

26. Luck doesn't come into it.

You can easily impliment 'pseudo-floats' using PICBasics integers. You just need to fiddle around a bit. In it's simplest form you use a WORD for the significant digits, and a BYTE for the fiddly stuff. Six BITs of that BYTE to keep track of powers/scale, one BIT to flag if your scale is negative or positive, and one to indicate if the entire value is negative or positive. So, with 24 bits to play with, you can have positive or negative values from 9.999 x 10^63 right down to as small as 9.999 x 10^-63.

Why not impliment proper floats yourself... go here and download standard IEEE754.

http://shop.ieee.org/ieeestore/

Education Costs! Don't want to spend the money, but you've got a bit of time? Then follow the links here and get some education in floats for free...

http://www.abdn.ac.uk/~eng030/eg2060/eg2060.htm

Ultimately those of us that have implimented float solutions in PBP have invested a great deal of time and effort (and ultimately money) in doing so, and some like Al Williams (who by the way also uses PBP)...

http://www.al-williams.com/pak1.htm

... scrape their living from selling solutions to those that are unable or unwilling to do it for themselves. It would be unfair to people like Al to post ready canned routines, as it would kill their business overnight.

Melanie

27. Hello Don,

Don>>Ok DWAYNE,

But is possible to aplly this metode with PBP ?<<

I just saw this Don, the answer is yes....

Dwayne

28. ## Floating Point

Melanie:
I need impliment 'pseudo-floats' using PICBasics integers. Can You help me ?. Please, send me any routine in PicBasic.

29. can you use a pwm signal and a dual opamp to create a sinwave?
Last edited by scorpion; - 26th November 2004 at 21:40.

30. for sure... using two integrator circuits...that's the method

be sure to have 50% duty cycle for lower distorsion

#### Members who have read this thread : 3

You do not have permission to view the list of names.

#### Posting Permissions

• You may not post new threads
• You may not post replies
• You may not post attachments
• You may not edit your posts