Shelving Filters

Post Reply
PhilHaw
Posts: 65
Joined: Thu Mar 07, 2019 5:37 pm

Shelving Filters

Post by PhilHaw »

An example code for a fixed high shelf filter. The filter frequency and shelf gain can be set and are stored in two MREGs.

Code: Select all

; High shelf with fixed fc and ks
; fc is set by mreg 14 (kf1)
; Shelf level (ks1) set by mreg 15
; 

.equ fs 32000		; Sample rate

; Registers, may need to change so they do not conflict with other items 
.rn lp r9 
.rn shelf r5
.rn temp r8 
.rn temp2 r4

; User settings 
.equ fc 500		; The desired fc frequency in Hz
.mreg kf1 kfc		; Put the value of the fc coefficient in mreg so it's there on startup
.mreg ks1 0.5		; Put the value of the shelf coefficient in mreg

.rn kf1 mr14		; Frequency coefficient for fc
.rn ks1 mr15		; ks = shelving coefficient (controls boost/cut)
.rn lpsaveLS2 mr11	; Location to save the lp value between iterations



; Constants and equations 
.equ e 2.71828183 
.equ pi 3.14159265359 

; Calculate the fc coefficient
.equ kfc 1-e^(-2*pi*fc/fs)


; The filters: intended as a 'subroutine'
; Input Signal should be in acc32
; Output signal will be in acc32
; Uses CREGS lp, hp, temp and temp2
; lp is reusable for any filter (must be saved in a separate MREG for each filter)
; temp and temp2 are temporary CREGs for use within a routine
; values in temp and temp2 are not important on input and undefined on output

cpy_cs acc32,in0 		; Read in the input - required for testing only

; ========== Entry point here with signal in acc32 ======================

cpy_cc temp,acc32		; We need it again below so save in temp
cpy_cm lp,lpsaveLS2		; Get the saved lp value Ylp[n-1]

cpy_cm temp2, ks1		; Get the shelf boost/cut from the preset (constant) value in the MREG

; First high shelf

subs temp, lp			; Yhp[n] = X[n] -Ylp[n-1]
multrr temp2, acc32		; adjust the shelf level from the ks scaling above 
adds acc32, temp 		; add the input
cpy_cc shelf, acc32 		; Save high shelf result

cpy_cm temp2, kf1		; save K into a core register

; Now low pass 
subs temp, lp 			; X[n] - Ylp[n] 
multrr acc32, temp2		; *kf 
adds acc32, lp			; + Ylp[n] 
cpy_cc lp, acc32 		; Save low pass result
cpy_cc acc32, shelf		; High shelf out on acc32
cpy_mc lpsaveLS2, lp		; Save the lp value for next iteration

cpy_sc out0, acc32 		; High shelf out on out0 - required for testing only
And here is the Bode plot for this code (fc = 500 Hz and gain coefficient = 0.5).
Image

The low shelf filter code is as follows:

Code: Select all

; Low shelf with fixed fc and ks
; fc is set by mreg 16 (kf2)
; Shelf level (ks) set by mreg 17 (ks2)
; 

.equ fs 32000	; Sample rate

; Registers, may need to change so they do not conflict with other items 
.rn lp r9
.rn shelf r5
.rn temp r8 
.rn temp2 r4

; User settings
.equ fc 500		; The desired fc frequency in Hz
.mreg kf2 kfc		; Put the value of the fc coefficient in mreg so it's there on startup
.mreg ks2 0.5		; Put the value of the shelf coefficient in mreg

.rn kf2 mr16		; Frequency coefficient for fc
.rn ks2 mr17		; ks = shelving coefficient (controls boost/cut)
.rn lpsaveLS2 mr11	; Location to save the lp value between iterations
.rn lpsaveLS1 mr10


; Constants and equations 
.equ e 2.71828183 
.equ pi 3.14159265359 

; Calculate the fc coefficient
.equ kfc 1-e^(-2*pi*fc/fs)


; The filters 'subroutine'
; Input Signal should be in acc32
; Output signal will be in acc32
; Uses CREGS lp, shelf, temp and temp2
; lp is reusable for any filter (must be saved in a separate MREG for each filter)
; temp and temp2 are temporary CREGs for use within a routine
; values in temp and temp2 are not important on input and undefined on output

cpy_cs acc32,in0 		; Read in the input - required for testing only

; ========== Entry point here with signal in acc32 ======================

cpy_cc temp,acc32		; We need it again below so save in temp
cpy_cm lp,lpsaveLS1		; Get the saved lp value Ylp[n-1]

cpy_cm temp2, ks2		; Get the shelf boost/cut from the preset (constant) value in the MREG

; First low shelf

;subs temp, lp			; Yhp[n] = X[n] -Ylp[n-1]
multrr temp2, lp		; adjust the shelf level from the ks scaling above 
adds acc32, temp		; add the input
cpy_cc shelf, acc32		; Save high shelf result

cpy_cm temp2, kf2		; save K into a core register

; Now low pass
subs temp, lp			; X[n] - Ylp[n] 
multrr acc32, temp2		; *kf 
adds acc32, lp			; + Ylp[n] 
cpy_cc lp, acc32		; Save low pass result
cpy_mc lpsaveLS1, lp		; Save the lp value for next iteration
cpy_cc acc32, shelf		; High shelf out on acc32

cpy_sc out0, acc32 		; High shelf out on out0 - required for testing only

Bode plot for above:
Image
Philip Hawthorne

Blue Nebula Development Team
Post Reply