#!/usr/bin/env python3 __author__ = "kll" __copyright__ = "Copyright 2018, KLL engineering" #__credits__ = ["1", "2"] __license__ = "CC BY SA" __version__ = "0.1.2" # but also see vertxt variable __maintainer__ = "kll" __email__ = "raspberryonpi@gmail.com" __status__ = "still play" """ my_filter.py a numeric recursive average filter first order use the most simple idea Fin is a incoming signal, sensor value, here a random number [ range 0..30..Fin..70..100.00 ] F is the filtered signal used for processing / control / trending ... F = Fin * A + F * B rule ( to keep the amplitude of that average ) : A + B = 1.0 add we remember the MIN MAX values ( in integer ) of Fin print of it [enable][disable] and now also try a max high filter // a filtered PEAK VU meter means we make a second ( not so strong ) filter what only uses the Fin values what are higher as the filtered value F to create FH but if Fin is lower the filtered value F what we do with this FH? we must drag it down to F by FH - FH_downramp links: http://kll.engineering-news.org/kllfusion01/articles.php?article_id=146 looks like ( when used from PUTTY SSH ) http://kll.engineering-news.org/kllfusion01/downloads/PY3_signal_filter_linechart_putty.jpg https://www.raspberrypi.org/forums/viewtopic.php?f=91&t=211126#p1303104 rev 0.1.0 use command line parameters ( args / opts ) https://www.tutorialspoint.com/python/python_command_line_arguments.htm """ from random import random from time import sleep import sys, getopt def main(argv): #_________________________Filter setup A = 0.1 # A = 0.001 .. 1.0 ( strong .. to .. no filter ) B = 1.0 - A #_________________________Signal Variables and settings F = 50.0 Fin = 0.0 #_________________________Random signal generation setup Finbase=30.0 # set instrument signal input range 50 +- 20 // 30 means 30 ... 70 // Finspan 40 Finspan=2*(F-Finbase) #_________________________how many lines we want produce #_________________________filter might need to swing in depending on tuning and startvalues longlist = 30 # set line count ( 0 means run until [ctrl][z] ) simrealtime = 0.2 # a delaytimer for each line makes it look like actually reading some hardware samplefrq = 1.0 / simrealtime # sampling [Hz] #_________________________my LINE CHART dejavu print_chart_line = True # set print chart line enable chart_line='' osci_F = 'o' osci_Fin = '+' osci_FH = '>' # use terminal color defs as from BASH WHT='\033[37;44m' # white on blue background BLU='\033[47;34m' # blue on white background MAG='\033[47;35m' # magenta on white background GRN='\033[0;32m' # green on NO background RED='\033[47;31m' # red on white background BLK='\033[47;30m' # black on white background BOLD='\033[1m' # and BOLD END2='\033[0m' # end style #_________________________Signal MIN MAX Fimin = 100 Fimax = 0 Fi = int(F) print_Fi = False #_________________________Signal HIGH FILTER FH = F FH_downramp = 2.0 # kind of memory setting, drag it back down to F FH_A = 0.5 # set not too strong filter on that FH_B = 1.0 - FH_A #_________________________check for command line parameters my_prog='my_filter.py' helptxt = my_prog+'\n [-v][--version] version\n [-h][--help] this help' helptxt += '\n show:' helptxt += '\n [-c][--chart] print chart line OFF' helptxt += '\n [-i][--iminmax] print min max ON' helptxt += '\n [-s][--samples] <0> run forever .. or fixed length, default '+str(longlist) helptxt += '\n ** in any case can stop by [ctrl][z] or [ctrl][c]' helptxt += '\n [-f][--ftime] float (sim / sleep), default: '+str(simrealtime) helptxt += '\n [-n][--noise] float (0.0 .. 50.0), default: '+str(Finbase) helptxt += '\n tuning:' helptxt += '\n [-A][--Atune] (float) 0.001 .. 1.0, default: '+str(A) helptxt += '\n [-H][--Htune] (float) > A, default: '+str(FH_A) helptxt += '\n [-d][--downramp] (float), default: '+str(FH_downramp) vertxt = 'rev 0.1.2' try: # short opt : and long opt = means required opts, args = getopt.getopt(argv,"hvcis:f:A:H:d:n:",["help","version","chart","iminmax","ftime=","samples=","Atune=","Htune=","downramp=","noise="]) except getopt.GetoptError: print ('error: ',helptxt) sys.exit(2) for opt, arg in opts: if opt in ('-h','--help'): print (helptxt) sys.exit() elif opt in ('-v','--version'): print (vertxt) sys.exit() elif opt in ('-i', '--iminmax'): print_Fi=True elif opt in ('-c', '--chart'): print_chart_line=False elif opt in ('-s', '--samples'): try: longlist = int(arg) except ValueError: print("That is not an integer number!") sys.exit() elif opt in ('-f', '--ftime'): try: simrealtime = float(arg) samplefrq = 1.0 / simrealtime # sampling [Hz] except ValueError: print("That is not an floating point number!") sys.exit() elif opt in ('-A', '--Atune'): try: A = float(arg) B = 1.0 - A except ValueError: print("That is not an floating point number!") sys.exit() elif opt in ('-H', '--Htune'): try: FH_A = float(arg) FH_B = 1.0 - FH_A except ValueError: print("That is not an floating point number!") sys.exit() elif opt in ('-d', '--downramp'): try: FH_downramp = float(arg) except ValueError: print("That is not an floating point number!") sys.exit() elif opt in ('-n', '--noise'): try: Finbase = float(arg) Finspan=2*(F-Finbase) except ValueError: print("That is not an floating point number!") sys.exit() #_________________________oscilloscope / chart print output resolution 100 (chars) def make_osci(F,Fin,FH): # Fx expected in range 0.0 .. 100.0 mapped to 100 character position of a text terminal osci='' Fpos=int(F) Finpos=int(Fin) FHpos=int(FH) for k in range(101): adds=' ' # '_' use this when you need to copy result as text to HTML web... if ( k == 0 or k == 10 or k == 20 or k == 30 or k == 40 or k == 50 or k == 60 or k == 70 or k == 80 or k == 90 or k == 100 ): adds='|' if (k == FHpos ): adds=osci_FH if (k == Fpos ): adds=osci_F if (k == Finpos ): adds=osci_Fin osci = osci+adds return osci #_________________________simulate random signal def get_signal(): signal = Finbase + Finspan * random() sleep(simrealtime) # simulate realtime return signal #_________________________print headerline if (longlist == 0): print ("my_filter :run until [ctrl][z]") else: print ("my_filter :%4.0f samples or [ctrl][z]" % (longlist)) print ("filter use: F = Fin * %4.1f + F * %4.1f | Fin random from %4.1f .. %4.1f | sampling %4.1f Hz" % (A,B,Finbase,(Finbase+Finspan),samplefrq)) print ("PEAKVU use: if (Fin > F ): FH = Fin * %4.1f + FH * %4.1f else: FH = FH - %4.1f" % (FH_A,FH_B,FH_downramp)) if (print_chart_line): print ("Line_Chart: F (%s) FH (%s) Fin (%s)" % (osci_F,osci_FH,osci_Fin)) #_________________________produce "longlist" signal values myrun = True i = 0 while (myrun): i = i + 1 # loop counter if (longlist == 0): # run forever or [ctrl][c] myrun = True else: if (i == longlist): myrun = False #_________________________SAMPLE AND FILTER Fin = get_signal() F = Fin * A + F * B # the filter job #_________________________MIN VAL MAX ( integer ) if (print_Fi): Fi = int(F) if ( Fi > Fimax ): Fimax = Fi if ( Fi < Fimin ): Fimin = Fi #_________________________FH by not so strong filter /and/ only on the high values if ( Fin > F ): FH = Fin * FH_A + FH * FH_B # filtered high values else: if (FH > F): FH = FH - FH_downramp # drag it back down to F if (FH < F): FH = F # repair if now too low by FH_dragdown stepsize #_________________________Output ( chart + data ) chart_line = '' if ( print_chart_line) : chart_line=make_osci(F,Fin,FH) if (print_Fi): print (chart_line+"Fimin= %2.0f,Fi= %2.0f,Fimax= %2.0f,FH= %4.1f,F= %4.1f,Fin= %4.1f" % (Fimin, Fi, Fimax, FH, F, Fin)) else: print("{color}{text}{default}{values}".format(color=RED,text=chart_line,default=END2,values="FH= %4.1f,F= %4.1f,Fin= %4.1f" % (FH, F, Fin))) # print (chart_line+"FH= %4.1f,F= %4.1f,Fin= %4.1f" % (FH, F, Fin)) if __name__ == '__main__': main(sys.argv[1:]) # end