Digital Filters For Offset Removal: Digital High Pass Filter
Digital Filters For Offset Removal: Digital High Pass Filter
TheAtmegaADC(Arduino)hasaninputvoltagerangeof0toVccandsowhen
samplinganACwaveformthewaveformneedstobebiasedatVcc/2.This
translatestoadigitaloffsetvalueofapproximately512.Thewaveformsample
digitalvaluewillbebetween0and1023,centeredaround512.
Todothemathsforrealpower,rmsvoltageandcurrentcalculations,weneed
removethisoffset.Thiscanbedonewithadigitalfilter.Therearetwo
approaches:thehighpassfilter,whichallowsthehighfrequencycomponent
throughremovingthebias,orthelowpassfilter,whichfirstfindsthebias,then
subtractsthebiasfromthesignal.Let'sstartwiththehighpassfilter.
Digitalhighpassfilter
Thefloatingpointimplementationlookslikethis:
filtered_value=0.996(last_filtered_value+samplelast_sample)
Why0.996?Itisnotamagicnumber,allthatisrequiredisanumberreasonably
closetounityinordertoprovideanadequatelylongtimeconstantsothereis
somephaseandamplitudedistortionatthe50Hzfundamentalfrequencybeing
measured.0.996yieldsafiltertimeconstantof250sampleperiods.
Codeexample:
intsample=0;
intlast_sample=0;
doublea=0;
doublefiltered_value=0;
voidsetup()
{
Serial.begin(9600);
}
voidloop()
{
//Generateatestsignal
last_sample=sample;
a+=0.1;sample=512+sin(a)*100;
//Floatingmathsimplementationofhighpassfiltertakes3640microseconds
filtered_value=0.996*(filtered_value+samplelast_sample);
Serial.print(sample);
Serial.print('');
Serial.println(filtered_value);
delay(50);
Noticethatittakesasignificantamountoftimetosettletothepointwhere
filtered_valuegoesbothpositiveandnegativewithanamplitudeof100.
Integerbitwiseimplementation
Apartfrombeingclosetounity,andthereforesuitableforthetypeoffilterwe
want,thevalue0.996abovewasselectedbecauseyoucanmultiplyby0.996
efficientlyusinglowleveloperationsbitshiftsandsubtractions.0.996isnearly
equalto255/256,andmultiplicationordivisionby256iseasilydonewith
bitwiseoperators:
n256=n<<8(bitwiseleftshiftby8bits=multiplicationby256)
n/256=n>>8(bitwiserightshiftby8bits=divisionby256)
n255=n256n=((n<<8)n)
Wecanrewritethedigitalhighpassfilteras:
n=last_filtered_value+samplelast_sample
filtered_value=0.996n=255n/256=(n256n)/256
substitutingbitwiseoperatorsyields:
n=last_filtered_value+samplelast_sample
filtered_value=((n<<8)n)>>8
Codeexample:
intsample=0;
intlast_sample=0;
doublea=0;
longfiltered_value=0;
voidsetup()
{
Serial.begin(9600);
}
voidloop()
{
//Generateatestsignal
last_sample=sample;
a+=0.1;sample=512+sin(a)*100;
longn=filtered_value+samplelast_sample;
filtered_value=((n<<8)n)>>8;
filtered_value=((n<<8)n)>>8;
Serial.print(sample);
Serial.print('');
Serial.println(filtered_value);
delay(50);
}
Ifyouwatchthefiltersettle,italmostworks,itappearstobesettlingcorrectly,
butthere'saproblem.
filtered_valuecontinuestodecreaseuntilithasapositiveamplitudeofaround0
andanegativeamplitudeof200
Thisispartlyduetoroundingerror,wecanimprovethingsbyadding128before
bitshiftingright,atricktoroundtothenearestinteger:
128is<<8
Changingthefilterlineabovefrom
filtered_value=((n<<8)n)>>8;
to
filtered_value=((n<<8)n+128)>>8;
Plottingtheresultgives:
Butit'sstillnotcorrect.Theproblemisthefiltered_valuevariabledoesnothave
enoughresolutiontoworkcorrectly.Withfloatingpointmathstheresolutionisin
thedecimalpoints,withintegermathswe'reroundingtothenearestinteger
value.
Thesolutionistouseascaledfiltered_valueforthe'evolving'filtered_value
variableandthendividethescaledfiltered_valuewhenweneedfiltered_value.
Thisgivesusahigherresolutiontoworkwithfortheevolvingfiltered_value
variable.
Letslookagainatthefilterequationabove:
n=last_filtered_value+samplelast_sample
filtered_value=(n256n)/256
Withabitofrearranging,wecanbringoutfiltered_valuemultipliedby256asour
higherresolution'evolving'filtered_value.
Ifwemovethe256totheleftsideoftheequation,wecanrewriteitas:
256filtered_value=n256n
(letscall256filtered_valueshifted_filter,asmultiplyingby256isthesameas
bitshiftingtotheleftbyeight(<<8))
ifwethencalculaten256separately:
shiftedFCL=256filtered_value+256(samplelast_sample)
(shiftedFCLstandsforbitshiftedFilter_value+Current_sampleLast_sample).
Byseparatingoutfiltered_valuefromsamplelast_samplewecanuse
theshifted_filtervalue:
shiftedFCL=shifted_filter+256(samplelast_sample)
Wecannowrewrite256filtered_value=n256nas:
shiftedFCL=shifted_filter+256(samplelast_sample)
shifted_filter=shiftedFCL(shiftedFCL/256)
Thefinalstepistodivideshifted_filterby256toarriveattheactual
filtered_value:
shiftedFCL=shifted_filter+256(samplelast_sample)
shifted_filter=shiftedFCL(shiftedFCL/256)
filtered_value=shifted_filter/256;
Replacingmultiplyby256anddivideby256withbitshiftoperatorsthecomplete
filterlookslikethis:
longshiftedFCL=shifted_filter+(long)((samplelast_sample)<<8);
shifted_filter=shiftedFCL(shiftedFCL>>8);
longfiltered_value=(shifted_filter+128)>>8;
Noticetheadditional128toimproverounding.
Examplecode:
intsample=0;
intlast_sample=0;
doublea=0;
longshifted_filter=10000;
voidsetup()
{
Serial.begin(9600);
}
voidloop()
{
//Generateatestsignal
last_sample=sample;
a+=0.1;sample=512+sin(a)*100;
longshiftedFCL=shifted_filter+(long)((samplelast_sample)<<8);
shifted_filter=shiftedFCL(shiftedFCL>>8);
longfiltered_value=(shifted_filter+128)>>8;
Serial.print(sample);
Serial.print('');
Serial.println(filtered_value);
delay(50);
}
Here'stheoutput:
Here'sanexampletoshowthatthefilterworkswellwithamorecomplex
waveform.Thewaveformbelowiswhatyou'dexpectfromamixtureofresistive
loadsandanonlinearswitchmodepowersupplyforsay,alaptopcomputer.
Digitallowpassfilter
Whyalowpassfilter?ThelowpassfilterwasintroducedwiththeMk2Energy
Routerwhichusesacommonbiassupply(bufferedbyanoperationalamplifier)to
supplytheoffsetvoltageforbothvoltageandcurrentchannels.Thefilteronlyhas
tobecalculatedonce,andtheresultingoffsetisnaturallythesameforboth
channelsandthereforecanbesubtractedfrombothreadings.Thisreduces
processingtimebyasignificantamount.
Thefloatingpointimplementationoftheclassiclowpassfilterlookslikethis:
filtered_value=last_filtered_value+0.004(samplelast_filtered_value)
Why0.004?Allthatisrequiredisareasonablysmallnumbertoprovidean
adequatelylongtimeconstantsothereislittleripplefromthe50Hzfundamental
frequencybeingmeasured.=0.004givesafiltertimeconstantof(1)/=
250sampleperiods.
Codeexample:
intsample=0;
doublea=0;
doublefiltered_value=0;
doublelast_filtered_value;
voidsetup()
{
Serial.begin(9600);
}
voidloop()
{
//Generateatestsignal
last_filtered_value=filtered_value;
a+=0.1;sample=512+sin(a)*100;
//Floatingmathsimplementationofhighpassfiltertakes3236microseconds
filtered_value=last_filtered_value+0.004*(samplelast_filtered_value);
Serial.print(sample);
Serial.print('');
Serial.println(filtered_value);
delay(50);
}
Unfortunately,thistakesquitealongtimetosettleandthereisstillasignificant
ripplepresent.Reducingthefilterconstantwillimprovetheripplebutworsenthe
settlingtimehoweverbecausewehaveagoodideaofwhatthefinalvalueshould
be,itispossibletopreloadthefilterbysettingtheinitialvalueoftheoutputto
512.Nowthatwehavepreloadedthefilter,thefilterconstantcanbereducedto
averysmallvaluewithoutforcingalongwaitwhilstthefiltersettlesbeforeuseful
readingscanbehad.Thisiswhattheoutputlookslikewithafilterof0.000122
therippleiscount.
Thistoocanbeconvertedtousethemuchfasterintegermaths,andherethe
filterisupdatedfromthevoltageinputeachtimethevoltageisread.Thissnippet
appearsintheinterruptserviceroutineofMartinRsPLLimplementationofthe
Mk2router.Ratherthanmultiplyingthedifferencebetweenthecurrentsample
andthelastfilteredvaluebyasmallnumber<<1,thefilteredvalueis
multipliedby1/(=213)instead.Thisgivesanof0.000122andatime
constantof8191samples.Therippleis0.1%,whichisabout1countwiththe
normalamplitudeofvoltageinput.Itincludesthefixforintegerrounding:
#defineFILTERSHIFT13
//forlowpassfilterstodetermineADCoffsets
#defineFILTERROUNDING(1<<12)
intvoltsOffset=512;
staticlongfVoltsOffset=512L<<13;
ISR(ADC_vect)//interrupthander
{
newV=sampleVvoltsOffset;//sampleVisthevaluereadbyADC,
//newVistheoutputvalue
fVoltsOffset+=(sampleVvoltsOffset);//updatethefilter
voltsOffset=(int)((fVoltsOffset+FILTERROUNDING)>>FILTERSHIFT);
}
(Thecurrentreadingisobtainedsimilarlybysubtractingtheoffset.)
Analternativealgorithmforderivingtheoffsetistomakeaninitialguessatthe
valueoftheoffset,subtracttheoffsetfromthereadingtogivethedesiredvalue,
andaccumulatethedesiredvaluesoveronemainscycle.Ideally,theresulting
valuewillbezero.Anyerrorisusedtocorrecttheoffsetforthenextcycle.This
algorithmsuffersfromthedisadvantagethat,unlessyouknowwhereamains
cyclestartsandends,additionalcodeisnecessarytodeterminethat.This
algorithmgivesabsolutelyzerorippleontheoutput,butifthebiasdriftsfromone
cycletothenext(unlikelythoughthisis,withstablevoltages),therewillbeastep
changefromonecycletothenext.
Mk2RouterLowPassFilterusingfloatingpointmaths:
(allvariablesexceptsampleV&sampleIaredeclaredasdouble)
if(startingNewCycle)
{
prevDCoffset=DCoffset;
DCoffset=prevDCoffset+(0.01*cumVdeltasThisCycle);
cumVdeltasThisCycle=0;
}
sampleVminusDC=sampleVDCoffset;
sampleIminusDC=sampleIDCoffset;
cumVdeltasThisCycle+=(sampleVDCoffset);