**Most natural observations are exponentational/logarithmic in nature.**

I often do simple hardware using Microchip PIC processors (usually 12F or 16F families). Hardware doing some business in the home.

One such example is my Christmas-tree-lightning-controller. Basically it only turns my electric Christmas-tree-lights on when I want to see them on…

GPC

In order to do this, it needs to measure the out-door light. It uses an accumulation cell (of 8 samples) and a moving average register with 8 cells: Light or darkness is determined from 8 accumulated samples of “10-bits light” averaged through the latest 8×8 samples…

8×8 samples of 10-bits equals 6 bits of 10bits equals 16 bits…

So the output of the moving average register is at most 16 bits wide and should pose no problems on a modern microcontroller.

Unfortunately, the small PIC micros are not very good at “multi-byte” calculations why the 16-bit result is a bit awkward to deal with. And my simple experiments indicates that light-level comparisons should be measured on a “percentage change” basis and not as an absolute comparison.

If I could just do a simple 8-bit logarithm function of the 16-bit absolute result, I would be able to do simple percentage comparisons of different light level measurements by simple subtraction of 8-bit values. Even the simples PIC’s can do subtraction of 8-bit values without special engineered software subroutines 🙂

Being inspired by the µLaw compression schemes used in Telephony, I wrote this little routine, that basically calculates 16×log_{2}(x), where x is some 16-bit value and the result is an 8-bit value. Simulating the calculations in software gives a maximum error of 1-bit on the result.

; NOTE: Variables wi, r0 and r1 are
; defined elsewhere in on-chip RAM
;
; log2: calcuate r0 = approx 16*log2(r1:r0).
; wi, r1 destroyed
;
log2:
movlw 16
movwf wi
; loop
log2_loop:
bcf STATUS,C
rlf r0,f
rlf r1,f ; C affected
decfsz wi,f ; Z affected
btfsc STATUS,C
goto log2_done
goto log2_loop
; done
log2_done:
movlw 0xf0
andwf r1,w
iorwf wi,w
movwf r0
swapf r0,f
return |

; NOTE: Variables wi, r0 and r1 are
; defined elsewhere in on-chip RAM
;
; log2: calcuate r0 = approx 16*log2(r1:r0).
; wi, r1 destroyed
;
log2:
movlw 16
movwf wi
; loop
log2_loop:
bcf STATUS,C
rlf r0,f
rlf r1,f ; C affected
decfsz wi,f ; Z affected
btfsc STATUS,C
goto log2_done
goto log2_loop
; done
log2_done:
movlw 0xf0
andwf r1,w
iorwf wi,w
movwf r0
swapf r0,f
return

The simpe logarithm shown above I’ve used lots of different places. If You want to know how or why it works, don’t hesistate to put a comment below.

Unfortunately, my Christmas-tree-lights-controller is not (yet) perfect, as sudden, heavy light seems to overflow the moving averager. In other words, when the terrorist children living next-door are having fun with fireworks, the lights on my outdoor Christmas tree blinks in its own secret manner 🙂