Fuzzy logic engine for the 68HC11
Submitted By:
WEBMASTER
Rating:
Not rated (
Rate It)
* Fuzzy Logic Inferrence Engine
*
** This is the third variation of this fuzzy engine. The first used
* a macro and conditional assembly for entry of rules and MFs. It
* also combined fuzzification with rule evaluation. The 2nd version
* was more efficient because fuzzy ins are only calculated once.
* Also a c program was written to simplify rule and MF entry rather
* than a macro and conditional assembly which were not very
* portable from one assembler to another. The 2nd version used fixed
* data structures for 4 ins and 2 outs. This, the third version, is
* identical to the 2nd version, except that the input and output size
* is variable. The number of Inputs and Outputs is set by the Knowledge
* Base Generator (kbg_11b1.exe). KBG_11B1 counts the actual number of
* Inputs and Outputs that you defined and generates an assembly language
* define statement for this Inference Engine to use.
*
*** Data structures and variables
*
ORG $0000 ;Beginning of HC11 RAM
CURRENT_INS RMB 4 ;Storage for 4 8-bit inputs
FUZ_INS RMB (8*NUMINP) ;Storage for fuzzy inputs
FUZ_OUTS RMB (8*NUMOUT) ;Storage for fuzzy outputs
COG_OUTS RMB NUMOUT ;Defuzzified outputs
SUM_OF_FUZ RMB 2 ;11-bit sum of fuzzy outs
SUM_OF_PROD RMB 3 ;19-bit sum of products
COGDEX RMB 1 ;Current out # for COG loop
LP_COUNT RMB 1 ;Index for fuz loop
SUMDEX RMB 1 ;Index for sum loop
ORG $B600 ;Beginning of HC11 EEPROM
* Add the output from KBG_11C.exe here.....
***** Fuzzy Inferrence Engine Starts Here
*
FUZZIFY LDY #FUZ_INS ;Point at fuzzy input table
LDX #CURRENT_INS ;Point at current input values
LDD 2,X ;Put input values on stack
PSHB
PSHA
LDD 0,X
PSHB
PSHA
LDX #INPUT_MFS ;Point at input MF specs
NXTIN_LP PULA ;Get next current input value
LDAB #7 ;For 8 loop passes
STAB LP_COUNT ;Initialize loop counter
GRAD_LOOP EQU * ;Get grade for 1 label of 1 input
*******************************************************************
* GET_GRADE - Routine to project a discrete input value onto *
* the associated input membership function (fuzzification). *
* Enter with Input value in A register and X pointing at the *
* points and slopes defining the membership function. *
* Finishes with grade in B, X points at next MF spec (X+4) *
* and A is unchanged. *
*******************************************************************
GET_GRADE PSHA ;Save input value of A
CLRB ;In case grade = 0
SUBA 2,X ;Input value D pt2 -> A
BLS NOT_SEG2 ;If input < pt2
LDAB 3,X ;Slope 2
BEQ HAV_GRAD ;Skip if vert slope
MUL ;(In D pt1) * slp2 -> A:B
TSTA ;Check for > $FF
BEQ NO_FIX ;If upper 8 = 0
CLRB ;Limit grade to 0
BRA HAV_GRAD ;In limit region of seg 2
NO_FIX SUBB #$FF ;B D $FF
NEGB ;$FF D B
BRA HAV_GRAD ;($FF D((In D pt2) * slp2))
NOT_SEG2 ADDA 2,X ;Restore input value
SUBA 0,X ;Input value D pt1 -> A
BLO HAV_GRAD ;In < pt1 so grade = 0
LDAB 1,X ;Slope 1
BEQ VERT_SLP ;Skip if vert slope
MUL ;(In D pt1) * slp1 -> A:B
TSTA ;Check for > $FF
BEQ HAV_GRAD ;Result OK in B
VERT_SLP LDAB #$FF ;Limit region or vert slope
HAV_GRAD INX ;Point at next MF spec
INX
INX
INX
PULA ;Restore A register
STAB 0,Y ;Save @ fuzzy input
INY ;Point at next
DEC LP_COUNT ;
BPL GRAD_LOOP ;For 8 labels of 1 input
CMPY #FUZ_INS+(8*NUMINP) ;Done with all fuzzy ins?
BNE NXTIN_LP ;If not, process next input
* Done with fuzzification, evaluate rules next
LDX #FUZ_OUTS ;Point at first fuzzy output
LDAA #(8*NUMOUT) ;Number of fuzzy outputs
CLR_OUTS CLR 0,X ;Clear a fuzzy output
INX ;Point at next
DECA ;Loop index
BNE CLR_OUTS ;Continue till all fuzzy outs 0
LDY #RULE_START ;Point to start of 1st rule
RULE_TOP LDAA #$FF ;Begin processing a rule string
* A will hold grade of smallest (min) if part
IF_LOOP LDAB 0,Y ;Get rule byte 000X XAAA; If X is A
BMI THEN_LOOP ;If MSB=1, exit to then loop
INY ;Point at next rule byte
LDX #FUZ_INS ;Point at fuzzy inputs
ABX ;Point to specific fuzzy input
CMPA 0,X ;Is this fuzzy input lower?
BHS IF_LOOP ;If not don't replace lowest
LDAA 0,X ;Replace lowest if
BNE IF_LOOP ;Unless zero, do next rule byte
* A zero value fuzzy input makes rule completely not true
* so skip rest of if parts and all then parts to start of next rule
FIND_THEN LDAB 0,Y ;Get next rule byte
BMI FIND_IF ;MSB set means its a then part
INY ;Point at next rule byte
BRA FIND_THEN ;Loop till pointing at a then part
FIND_IF INY ;Adv rule pointer to if part
LDAB 0,Y ;Get next rule byte
BPL RULE_TOP ;MSB clear means its an if part
CMPB #$FF ;$FF is no more rules marker
BNE FIND_IF ;Continue looking for if or $FF
BRA DEFUZ ;When all rules done, go defuzzify
THEN_LOOP LDX #FUZ_OUTS ;Point at fuzzy outputs
ANDB #$0F ;Save 8 times out # + label #
ABX ;X points at fuzzy output
* Grade of membership for rule is in A accumulator
CMPA 0,X ;Compare to fuzzy output
BLO NOT_HIER ;Branch if not higher
STAA 0,X ;Grade is higher so update
NOT_HIER INY ;Adv rule pointer to next byte
LDAB 0,Y ;Get rule byte
BPL RULE_TOP ;If MSB=0 its a new rule
CHK_END CMPB #$FF ;Check for end of rules flag
BNE THEN_LOOP ;If not $FF, must be a then part
* All rules evaluated. Now defuzzify fuzzy outputs
DEFUZ LDY #SGLTN_POS ;Point at 1st output singleton
LDX #FUZ_OUTS ;Point at 1st fuzzy output
CLR COGDEX ;Loop index will run from 0->1
COG_LOOP LDAB #8 ;8 fuzzy outs per COG output
STAB SUMDEX ;Inner loop runs 8->0
LDD #$0000 ;Used for quicker clears
STD SUM_OF_FUZ ;Sum of fuzzy outputs
STD SUM_OF_PROD+1 ;Low 16-bits of sum of products
STAA SUM_OF_PROD ;Upper 8-bits
SUM_LOOP LDAB 0,X ;Get a fuzzy output
CLRA ;Clear upper 8-bits
ADDD SUM_OF_FUZ ;Add to sum of fuzzy outputs
STD SUM_OF_FUZ ;Update RAM variable
LDAA 0,X ;Get fuzzy output again
LDAB 0,Y ;Get Output singleton position
MUL ;Position times weight
ADDD SUM_OF_PROD+1 ;Low 16-bits of sum of products
STD SUM_OF_PROD+1 ;Update low 16-bits
LDAA SUM_OF_PROD ;Upper 8-bits
ADCA #0 ;Add carry from 16-bit add
STAA SUM_OF_PROD ;Upper 8-bits of 24-bit sum
INY ;Point at next singleton pos.
INX ;Point at next fuzzy output
DEC SUMDEX ;Inner loop index
BNE SUM_LOOP ;For all labels this output
PSHX ;Save index for now
CLRA ;In case divide by zero
LDX SUM_OF_FUZ ;Demominator for divide
BEQ SAV_OUT ;Branch if denominator is 0
TST SUM_OF_PROD ;See if more than 16-bit
BNE NUM_BIG ;If not zero, # is > 16-bits
LDD SUM_OF_PROD+1 ;Numerator for divide
IDIV ;Result in low 8-bits of X
XGDX ;Result now in B
TBA ;Move result to A
BRA SAV_OUT ;Go save output
NUM_BIG LDD SUM_OF_PROD ;Numerator upper 16 of 24-bit
TST SUM_OF_PROD+2 ;Check for rounding error
BPL NO_ROUND ;If MSB clear, don't round
ADDD #1 ;Round numerator up 1
NO_ROUND FDIV ;D/X -> X, use upper 8 of 16
XGDX ;Result now in A
SAV_OUT LDX #COG_OUTS ;Point to 1st defuz output
LDAB COGDEX ;Curent output number
ABX ;Point to correct output
STAA 0,X ;Update defuzzified output
PULX ;Recover index
INCB ;Increment loop index
STAB COGDEX ;Update
CMPB #NUMOUT ;Done with outputs?
BNE COG_LOOP ;If not, continue loop
*****
* Inference engine has completed one pass of all rules.
*****