TONY NIXON 54964 wrote: > > Would anyone have an algorithm to do ArcSin of a value. Here's an 8-bit one that uses a look up table plus first order linear interpolation: ;---------------------------------------------------------- ; ;arcsine ; ; The purpose of this routine is to take the arcsine of an ;8-bit number that ranges from 0 < x < 255/256. In other ;words, the input, x, is an unsigned fraction whose implicit ;divisor is 256. ; The output is in a conveniently awkward format of binary ;radians (brads?). The output corresponds to the range of zero ;to pi/2 for the normal arcsine function. Specifically, this ;algorithm computes: ; ; arcsine(x) = real_arcsine(x/256) * 256 / (pi/2) ; ; where, real_arcsine returns the real arcsine of its argument ;in radians. ; ; The algorithm is a table look-up algorithm plus first order ;linear interpolation. The psuedo code is: ; ;unsigned char arcsine(unigned char x) ;{ ; unsigned char i; ; ; i = x >> 4; ; return(arcsin[i] + ((arcsin[i+1] - arcsin[i]) * (x & 0xf))/16); ;} ; ; ; The accuracy is reasonable for x<150 or so. After that, the ;relatively steep arcsine severly deviates from a straight line ;approximation. The maximum error is around 5. arcsine SWAPF x,W ANDLW 0xf ADDLW 1 MOVWF temp ;Temporarily store the index CALL arc_sine_table ;Get a2=asin( (x>>4) + 1) MOVWF result ;Store temporarily in result DECF temp,W ;Get the saved index CALL arc_sine_table ;Get a1=asin( (x>>4) ) SUBWF result,W ;W=a2-a1, This is always positive. SUBWF result,F ;a1 = a1 - (a1-W) = W CLRF temp ;Clear the product CLRC BTFSC x,0 ADDWF temp,F RRF temp,F CLRC BTFSC x,1 ADDWF temp,F RRF temp,F CLRC BTFSC x,2 ADDWF temp,F RRF temp,F CLRC BTFSC x,3 ADDWF temp,F RRF temp,W ADDWF result,F RETURN arc_sine_table ADDWF PCL,F RETLW 0 RETLW 10 ;asin(1/16) = 3.583deg * 256/90 RETLW 20 RETLW 31 RETLW 41 RETLW 52 RETLW 63 RETLW 74 RETLW 85 RETLW 97 RETLW 110 RETLW 124 RETLW 138 RETLW 154 RETLW 173 RETLW 198 RETLW 240 As the comments say, the error is reasonably small for small values of the input variable (uniquely named 'x'). If you want to correct this, then the easiest thing to do is change the last RETLW into another lookup table (note, what follows has not been tested): change from: RETLW 240 to: BSF result_from_extended_table,0 MOVF x,W ANDLW 0x0f ADDWF PCL,F RETLW 198 ;asin(240/256) * 256/90 RETLW 200 ;asin(241/256) * 256/90 ... RETLW 242 ;asin(255/256) * 256/90 Then add code in the main routine that checks the variable 'result_from_extended_table' to see if the result is from the extended table. If the result was obtained from the extended table, then the linear interpolation doesn't need to be performed. BTW, I've only verified that this routine works without the extended look up table. If your input is negative, then no problem. This is because: y = arcsin(-x) = - arcsin(x) In other words, for negative inputs change the sign of the input variable, call the 'arcsin' routine, and then change the sign of the result. However, be aware that there is not any room in the 8-bit result for the sign bit. This could be fixed many different ways. For example, you could shift the result right one position and copy the sign to the MSB. There are also arcsine identities that are useful for reducing the domain, but they also require multiplication and division. They would be useful as part of a higher order interpolation algorithm. But this is beyond the scope of my time (right now). Scott