Digital Low-pass Elliptic filter design

The flow calculates zeroes and poles, draws plot of Low-pass digital Elliptic filter, as well shows calculated order and number of second-order blocks for implementation. To start, on the dashboard please enter your desired parameters: fc/fs - the end of passband (normalized frequency); fp/fs - the beginning of stopband (normalized frequency); pul - passband ripples, dB; sl - stopband attenuation, dB. By changing position of fp/fs slider try to get calculated order as close as possible to even number (e.g. 5.99, not 6.01!). Otherwise sl value will slightly differ from desired.

[{"id":"476d396.c530d48","type":"tab","label":"DSP_Ok","disabled":false,"info":""},{"id":"5181fae9.f4b864","type":"ui_text","z":"476d396.c530d48","group":"bfc05775.82ec28","order":5,"width":"2","height":"1","name":"","label":"","format":"   {{msg.payload}} ","layout":"row-left","x":510,"y":80,"wires":[]},{"id":"7d604f45.490cd8","type":"inject","z":"476d396.c530d48","name":"","topic":"","payload":"0.12","payloadType":"num","repeat":"","crontab":"","once":true,"onceDelay":"","x":110,"y":132,"wires":[["59514728.b51198"]]},{"id":"b708f2a9.92adb","type":"ui_slider","z":"476d396.c530d48","name":"","label":"pul, dB","tooltip":"","group":"bfc05775.82ec28","order":3,"width":"4","height":"1","passthru":true,"outs":"all","topic":"","min":"0.1","max":"5","step":"0.1","x":320,"y":298,"wires":[["49709706.28af78","11ffbb1.6b963c5"]]},{"id":"25869a55.4abe4e","type":"inject","z":"476d396.c530d48","name":"","topic":"","payload":"0.1","payloadType":"num","repeat":"","crontab":"","once":true,"onceDelay":"","x":110,"y":298,"wires":[["b708f2a9.92adb"]]},{"id":"d37d91b6.afcaa","type":"ui_slider","z":"476d396.c530d48","name":"","label":"sl, dB","tooltip":"","group":"bfc05775.82ec28","order":4,"width":"4","height":"1","passthru":true,"outs":"all","topic":"","min":"2","max":"100","step":"1","x":311,"y":385,"wires":[["6e739f71.59c4e","879015ce.0636d8"]]},{"id":"eb685569.6be818","type":"inject","z":"476d396.c530d48","name":"","topic":"","payload":"38","payloadType":"num","repeat":"","crontab":"","once":true,"onceDelay":"","x":111,"y":385,"wires":[["d37d91b6.afcaa"]]},{"id":"73126482.db32b4","type":"function","z":"476d396.c530d48","name":"fc_set","func":"var fc=msg.payload;\nflow.set('fc',fc);\nreturn msg;","outputs":1,"noerr":0,"x":512.5,"y":39,"wires":[[]]},{"id":"fb1f39bf.fdfe88","type":"function","z":"476d396.c530d48","name":"fp_set","func":"var fp=msg.payload;\nvar fc=flow.get('fc');\nif(fp<=fc){msg.payload=\"fp > fc always!!!\";}\nflow.set('fp',fp);\nreturn msg;","outputs":1,"noerr":0,"x":510,"y":120,"wires":[["313291b5.f3e9d6"]]},{"id":"49709706.28af78","type":"function","z":"476d396.c530d48","name":"pul_set","func":"var pul=msg.payload;\nflow.set('pul',pul);\nreturn msg;","outputs":1,"noerr":0,"x":520,"y":200,"wires":[[]]},{"id":"6e739f71.59c4e","type":"function","z":"476d396.c530d48","name":"sl_set","func":"var sl=msg.payload;\nflow.set('sl',sl);\nreturn msg;","outputs":1,"noerr":0,"x":510,"y":305,"wires":[[]]},{"id":"aabadeb4.05de88","type":"function","z":"476d396.c530d48","name":"Elf","func":"/*cls\ndim sm(6): dim lm(6): dim rea(14): dim ima(14):dim text$(2): dim xy(305)\nfd=1: pul=0.5: sl=60*/ \nvar sm=[];\nvar lm=[];\nvar zepo=[[],[]];\nvar msg1 = {};\n\n\nvar msg2 = {};  \nvar ze=[[],[]];\nvar po=[[],[]];\n\nvar rea=[];\nvar ima=[];\nvar xy=[];\n\n//var fd=flow.get('fd');\nvar fd=1.0;\nvar fc=flow.get('fc');\nvar fp=flow.get('fp');\n//if (fp<=fc){node.error(\"fp should be > fc\");}\nvar pul=flow.get('pul');\nvar sl=flow.get('sl');\nvar a2=Math.pow(10,(0.1*sl));\n //a2=10^(0.1*sl)\n var e3=Math.pow(10,(0.1*pul));\n//e3=10^(0.1*pul):  \nvar e2=e3-1.0;\nvar am=Math.sqrt(e2);\n  //xm=tan(pi()*fc/fd)\n  var xm= Math.tan(Math.PI*fc/fd);\n  //xk=xm/tan(pi()*fp/fd)\n  var xk= xm/Math.tan(Math.PI*fp/fd);\n  var vv=Math.PI*fc/fd;\n  //rk=sqrt(1-xk*xk)\n  var rk=Math.sqrt(1.0-xk*xk);\n //xk1=am/sqrt(a2-1): xk12=sqrt(1-xk1*xk1)\n var xk1=am/Math.sqrt(a2-1.0);\n var xk12=Math.sqrt(1.0-xk1*xk1);\n \n //****************************************\n// var ee= the3(1000.0,1.0);\n// node.warn(ee);\n  \n var b1=ElIn(rk);\n\n \n //node.warn(b7);\n //node.warn(vv);\n  var b2=ElIn(xk12);\n  var b3=ElIn(xk);\n  var b4=ElIn(xk1);\n  var b5=b3*b2/b4/b1;\n  flow.set('b5',b5);\n  flow.set('sl',sl);\n  flow.set('pul',pul);\n  var nn=Math.floor(b5+1.0);\n  //******************************************\n// node.warn('Resultto->');\n//node.warn(b5);\n//msg.payload='b5';\n  /*:dlt=0.001/abs(nn-5.5)/10\n#;rer=fmod($nn,2);?>\n  nn=floor(b5+1) \nprint \"*****************************\"\n   print \" Calculated Filter Order N= : \";\n  print    b5\n#****************************************************\n#*************Ok************************************\n*/\n\n var u0=-b1/b2*Math.log((Math.sqrt(e3)+1.0)/am);\n  var q=Math.exp(-Math.PI*b1/b3);\n  var q1=Math.exp(-Math.PI*b3/b1);\n   var pr=b3/nn;\n  \n   \n   //**************************************************************************************************\n  sm[0]=-b1; sm[1]=u0;\n   nn=Math.floor(nn/2);\n   \n   \n   for (var m = 0; m<=nn-1; m++) {  \n   lm[m]=2*m+1;\n    //node.warn(sm[m]); \n   }\n\n/*    print \"**** Z-plane Zeroes : ****\"\ntext$[1]=\"****Z-plane Poles : **** \"\n   # $text [3]=\"Where A1=2*Re{Pole}, A2= -((Re{Pole})^2+(Im{Pole})^2),\n   #  B1=2*(Re{Pole} - Re{Zero}), B2=A2+1\";  $text [4]=\" \";*/\n/***************************************************************************************/\n\n\n\n\n\n   \n    for (var i = 0; i<=1; i++) {  \n   var rr=sm[i];\n   //node.warn(sm[i]);\n      for (var j = 0; j<=nn-1; j++) {  \n //if (i=1 and j=0) then  print text$[1]\n   var i1=lm[j];\n  var sk=the3(pr*i1,q);\n\n var pk=the3(rr,q1);\n  var sv=thet1(sk,q);  var sw=thet4(sk,q);\n   var pv=thet1(pk,q1); var pw=thet4(pk,q1);\n   var sn1=sv/sw/Math.sqrt(xk);var sn2=pv/pw/Math.sqrt(rk);\n   var dn1=1.0-xk*xk*sn1*sn1;\n   var dn2=Math.sqrt(Math.abs(1.0-rk*rk*sn2*sn2)); var zd=1.0-sn2*sn2*dn1;\n   var sor=sn1*dn2*xm/zd;\n   var bor=sn2*Math.sqrt(Math.abs(dn1))*Math.sqrt(Math.abs(1.0-sn1*sn1))*Math.sqrt(Math.abs(1.0-sn2*sn2))*xm/zd;\n  var  zn=(1.0-bor)*(1.0-bor)+sor*sor;\n  var re=(1.0-bor*bor-sor*sor)/zn;\n  var aim=2.0*sor/zn;\n    i1=i*nn+j;\n    zepo[i1]=[re,aim];\n  rea[i1]=re; ima[i1]=aim;\n  if (i===0){ze[j]=zepo[i1];}\n if (i===1){po[j]=zepo[i1];}\n // msg1.payload= zepo; \n\n//node.warn(\" +/-j \");\n//node.warn(aim);\n//next j\n//next i\n// node.warn(zepo[i1]) ; \n      }         \n  }\n//********Grafik**************************************************************************************************\n\nvar picWidth=250;\n  sk=Math.PI/picWidth;\n  // for i=0 to picWidth-1\nfor ( i = 0; i<=picWidth-1; i++) {  \n   pk=Math.cos(sk*i); \n   pw=Math.sin(sk*i);\n   pr=1;rr=1;\n  // for j=0 to nn-1\n    for ( j=0; j<=nn-1; j++) {  \n   x1=pk-rea[j]; y1=pw-ima[j];\n   y2=pw+ima[j];\n   r1=Math.sqrt(x1*x1+y1*y1); r2= Math.sqrt(x1*x1+y2*y2);\n   rr=rr*r1*r2;\n     x1=pk-rea[nn+j];y1=pw-ima[nn+j];\n   y2=pw+ima[nn+j];\n   p1=Math.sqrt(x1*x1+y1*y1); p2=Math.sqrt(x1*x1+y2*y2);\n   pr=pr*p1*p2 ;\n    }\n//next j\n   xy[i]=rr/pr;\n}//next i\n\n\n\nvar max=0.0;\n  for (j=0; j<= picWidth-1;j++ ){\n    if (Math.abs(xy[j])>max){\n        max=Math.abs(xy[j]);\n    }\n  }\n // node.warn(max);\n//next j\n  for (j=0; j<= picWidth;j++ ){\n dB=20.0*Math.log10(Math.abs(xy[j]+0.000000001)/max);\n//node.warn(dB);\n    if (dB<-100.0) {  dB=-100.0;} \n   xy[j]=dB; \n  }\n  // node.warn(xy[2]);node.warn(xy[17]);\n   flow.set('xy',xy);\n\n//****End of grafiks**************************\n\n\n\nfunction the3(ds,q) {\n  var th=1.0+2.0*(q+q*q*q*q+q*q*q*q*q*q*q*q*q);\n   return ds/th/th;\n   }\n   \n\n\n//#************************************************************\n   function thet4(t,q) {  \n   return 1.0+2.0*(-q*Math.cos(2.0*t)+q*q*q*q*Math.cos(4.0*t)-Math.pow(q,9.0)*Math.cos(6.0*t));\n   }\n  \n//#*******************************************************\n   function thet1(t,q){\n   return 2.0*Math.pow(q,0.25)*Math.sin(t)-2.0*Math.pow(q,(9.0/4.0))*Math.sin(3.0*t)+2.0*Math.pow(q,(25.0/4.0))*Math.sin(5.0*t);\n\t}\n\n// #*********Elliptic Integral**************************************  \n    function ElIn(k) {    \n   // dim a(15)\n   var a=[];\n  \n    var Theta=[];\n  \n  a[0]=Math.atan(k/Math.sqrt(1-k*k));\n \n\n Theta[0]=Math.PI/2;\n var p=1.0;\n var i=0;\n var x1=1.0;\n var e=0.1;\n while (e > 0.0000001) {\n var x =2.0/(1.0+Math.sin(a[i]))-1.0;\n var y=Math.sin(a[i])*Math.sin(Theta[i]);\n a[i+1]=Math.atan((Math.sqrt(1.0-x*x))/x);\n Theta[i+1]= 0.5*(Theta[i]+Math.atan(y/Math.sqrt(1.0-y*y)));\n e=1.0-a[i+1]*2/Math.PI;\n \ni=i+1;\n}\n  for (var j = 1; j<=i; j++) {   \n  // node.warn(i);\n //node.warn(j);   \np=p*(1.0+Math.cos(a[j]));\n  x1=Math.PI/4.0+ (Theta[i])/2.0;\n}\n return Math.log(Math.sin(x1)/Math.cos(x1))*p;\n    } \nmsg.payload=zepo;  \nmsg1.payload=ze;\nmsg2.payload=po;\n//node.warn(ze[1]);\nglobal.set('re',rea);\nglobal.set('im',ima);\n//var msg1=zepo1;\n//msg.payload=xy;\nreturn [msg1,msg2,msg];","outputs":3,"noerr":0,"x":422,"y":512,"wires":[["7269ec18.2653b4"],["68ed47b3.d7a94"],["1217f73c.912ac1"]]},{"id":"74189919.a5655","type":"ui_button","z":"476d396.c530d48","name":"Z&P","group":"bfc05775.82ec28","order":9,"width":"4","height":"1","passthru":false,"label":"Get Zeroes&Poles","tooltip":"","color":"","bgcolor":"","icon":"","payload":"","payloadType":"str","topic":"hero","x":198.5,"y":473,"wires":[["f623fc86.4da1c8"]]},{"id":"7269ec18.2653b4","type":"ui_template","z":"476d396.c530d48","group":"b6fd928a.2d71a8","name":"Two dimension array table","order":1,"width":"0","height":"0","format":"<p style=\"text-align:center\">***Z-plane Zeroes****</p>\n<table id=\"table\" border=\"1\">\n <tr>\n <th>Real part</th> \n <th>(+/-j) x Image part</th>\n \n </tr>\n <tbody>\n <tr ng-repeat=\"row in msg.payload\">\n <td ng-repeat=\"item in row\" >{{item}}</td>\n </tr>\n </tbody>\n</table>\n\n","storeOutMessages":false,"fwdInMessages":true,"templateScope":"local","x":712,"y":497,"wires":[[]]},{"id":"59514728.b51198","type":"ui_slider","z":"476d396.c530d48","name":"","label":"fc/fs","tooltip":"","group":"bfc05775.82ec28","order":1,"width":"4","height":"1","passthru":true,"outs":"all","topic":"","min":"0.1","max":"0.4","step":"0.01","x":288,"y":95,"wires":[["73126482.db32b4","5181fae9.f4b864","59ca2b44.6820bc"]]},{"id":"f35be140.f8f088","type":"function","z":"476d396.c530d48","name":"chart data","func":"var xy=flow.get('xy');\n//node.warn(xy[1]);\nvar nn=250;\n//var lm=[];\nvar am=[];\nfor ( m = 0; m<=nn-1; m++) {  \n    am[m]=m/500\n}\n var lm1=   [{\n    \"series\": [ \"\" ],\n    \"data\": [xy],\n   // \"labels\": [\"1\",\"2\" ,\"3\",\"4\",\"5\",\"8\",\"3\",\"4\",\"5\",\"3\",\"4\",\"5\",\"1\",\"2\" ,\"3\",\"4\",\"5\",\"8\",\"3\",\"4\",\"5\",\"3\",\"4\",\"5\"  ]\n    \"labels\":am\n}];\n   msg.payload = lm1;\n   return msg;\n\n\n","outputs":1,"noerr":0,"x":244.5,"y":561,"wires":[["eec78b51.8a1548"]]},{"id":"eec78b51.8a1548","type":"ui_chart","z":"476d396.c530d48","name":"H(z)","group":"b6fd928a.2d71a8","order":2,"width":"7","height":"3","label":"Gain, dB","chartType":"line","legend":"false","xformat":"f / fd ","interpolate":"bezier","nodata":"bubb","dot":false,"ymin":"-100","ymax":"0","removeOlder":"3","removeOlderPoints":"100","removeOlderUnit":"1","cutout":0,"useOneColor":false,"colors":["#1f77b4","#aec7e8","#ff7f0e","#2ca02c","#98df8a","#bda9a9","#ff9896","#9467bd","#c5b0d5"],"useOldStyle":false,"x":395.5,"y":583,"wires":[[],[]]},{"id":"59ca2b44.6820bc","type":"function","z":"476d396.c530d48","name":"delta","func":"msg.payload=msg.payload+0.02;\nreturn msg;","outputs":1,"noerr":0,"x":157.5,"y":207,"wires":[["9f84305e.ed1168"]]},{"id":"f623fc86.4da1c8","type":"function","z":"476d396.c530d48","name":"fp<=fc!!","func":"var sl=flow.get('sl');\nvar pul=flow.get('pul');\n\nvar fp=flow.get('fp');\nvar fc=flow.get('fc');\nif (fp<=fc||sl<=pul) {\n   return [ null, msg ];\n} else {\n   return [ msg, null ];\n}\n","outputs":1,"noerr":0,"x":315,"y":431,"wires":[["aabadeb4.05de88","f35be140.f8f088","fd4bfa7a.69b1a8"]]},{"id":"fd4bfa7a.69b1a8","type":"function","z":"476d396.c530d48","name":"Filter order","func":"var msg1 = {};\nmsg.payload=flow.get('b5');\n var nn=Math.floor(msg.payload+1.0);\nmsg1.payload=Math.floor(nn/2);\nreturn [msg,msg1];","outputs":2,"noerr":0,"x":543,"y":416,"wires":[["bcc3bb78.29b37"],["e435a1a0.b04e98"]]},{"id":"bcc3bb78.29b37","type":"ui_text","z":"476d396.c530d48","group":"bfc05775.82ec28","order":10,"width":"5","height":"1","name":"","label":"Calculated_order :","format":"{{msg.payload | number:2}}","layout":"row-spread","x":693,"y":360,"wires":[]},{"id":"11ffbb1.6b963c5","type":"ui_text","z":"476d396.c530d48","group":"bfc05775.82ec28","order":7,"width":"2","height":"1","name":"","label":"","format":"{{msg.payload}} dB","layout":"row-spread","x":510,"y":240,"wires":[]},{"id":"879015ce.0636d8","type":"ui_text","z":"476d396.c530d48","group":"bfc05775.82ec28","order":8,"width":"2","height":"1","name":"","label":"","format":"{{msg.payload}}dB","layout":"row-spread","x":512,"y":348,"wires":[]},{"id":"9f84305e.ed1168","type":"ui_slider","z":"476d396.c530d48","name":"","label":"fp/fs","tooltip":"","group":"bfc05775.82ec28","order":2,"width":"4","height":"1","passthru":true,"outs":"all","topic":"","min":"0.1","max":"0.43","step":"0.005","x":324.5,"y":200,"wires":[["fb1f39bf.fdfe88"]]},{"id":"313291b5.f3e9d6","type":"ui_text","z":"476d396.c530d48","group":"bfc05775.82ec28","order":6,"width":"2","height":"1","name":"","label":"","format":"{{msg.payload}}","layout":"row-spread","x":691,"y":128,"wires":[]},{"id":"1217f73c.912ac1","type":"file","z":"476d396.c530d48","name":"Z&P_to_file","filename":"~/zeroes_poles","appendNewline":true,"createDir":true,"overwriteFile":"true","x":594,"y":606,"wires":[[]]},{"id":"e65c7c7e.dfff8","type":"debug","z":"476d396.c530d48","name":"","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","x":710,"y":454,"wires":[]},{"id":"68ed47b3.d7a94","type":"ui_template","z":"476d396.c530d48","group":"b6fd928a.2d71a8","name":"Toto dimension array table","order":1,"width":"0","height":"0","format":"<p style=\"text-align:center\">***Z-plane Poles***</p>\n<table id=\"table\" border=\"1\">\n <tr>\n <th>Real part</th> \n <th>(+/-j) x Image part</th>\n \n </tr>\n <tbody>\n <tr ng-repeat=\"row in msg.payload\">\n <td ng-repeat=\"item in row\" >{{item}}</td>\n </tr>\n </tbody>\n</table>\n\n","storeOutMessages":false,"fwdInMessages":true,"templateScope":"local","x":716,"y":555,"wires":[[]]},{"id":"513ce11e.85eff","type":"inject","z":"476d396.c530d48","name":"","topic":"","payload":"","payloadType":"date","repeat":"","crontab":"","once":true,"onceDelay":"0.5","x":75,"y":440,"wires":[["74189919.a5655"]]},{"id":"e435a1a0.b04e98","type":"ui_text","z":"476d396.c530d48","group":"bfc05775.82ec28","order":10,"width":"5","height":"1","name":"","label":"Second_order_modules :","format":"{{msg.payload | number:0}}","layout":"row-spread","x":762,"y":405,"wires":[]},{"id":"bfc05775.82ec28","type":"ui_group","z":"","name":"Enter parameters","tab":"cdf855f7.839698","disp":true,"width":"6","collapse":false},{"id":"b6fd928a.2d71a8","type":"ui_group","z":"","name":"Output","tab":"cdf855f7.839698","disp":true,"width":"9","collapse":false},{"id":"cdf855f7.839698","type":"ui_tab","z":"","name":"DSP","icon":"dashboard","order":17,"disabled":false,"hidden":false}]

Flow Info

Created 7 years, 1 month ago
Updated 6 years, 11 months ago
Rating: not yet rated

Owner

Actions

Rate:

Node Types

Core
  • debug (x1)
  • file (x1)
  • function (x9)
  • inject (x4)
Other
  • tab (x1)
  • ui_button (x1)
  • ui_chart (x1)
  • ui_group (x2)
  • ui_slider (x4)
  • ui_tab (x1)
  • ui_template (x2)
  • ui_text (x6)

Tags

  • Digital
  • Signal
  • Processing
  • Elliptic
  • filter
  • design
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option