"""
this is a program for designing IIR/FIR digital filters
"""

from PythonCard import clipboard,dialog,graphic,model
from PythonCard.components import radiogroup,bitmapcanvas,slider
import wx
import os
import random
import sys,time
from math import *

from pyspuc.fir_coeff import *
from pyspuc.butterworth_fir import *
from pyspuc.iir_allpass1 import iir_allpass1_double
from pyspuc.iir_allpass1_cascade import iir_allpass1_cascade_double
from pyspuc.gaussian_fir import *
from pyspuc.template_functions import *
from pyspuc.freq_functions import *
from pyspuc.create_remez_lpfir import *
from pyspuc.complex import complex_double
from pyspuc.notch_allpass import *
from pyspuc.cutboost import *

from pyspuc.iir_coeff import iir_coeff
from pyspuc.butterworth_iir import butterworth_iir
from pyspuc.chebyshev_iir import chebyshev_iir
from pyspuc.elliptic_iir import elliptic_iir

pts = 500
pi = 3.1416
w = []
for i in xrange(pts):
    w.append(pi*i/float(pts))


class Filtplot(model.Background):

    def on_initialize(self, event):
        self.filename = None
        comp = self.components
        self.sliderLabels = {
        'stcWeight':comp.stcWeight.text,
        'stcPassband':comp.stcPassband.text,
        'stctrans':comp.stctrans.text,
        'stcOrder':comp.stcOrder.text,
        'stcTaps':comp.stcTaps.text,
        'stcBits':comp.stcBits.text,
        'stcAlpha':comp.stcAlpha.text,
        }
        self.setSliderLabels()
        self.components.bufOff.backgroundColor = 'white'
        self.components.bufOff.clear()
        self.doFiltplot()
        t = time.localtime();
        s = "Digital Filter Design Demo, built using Boost Python library\n"
        s += "Copyright: Tony Kirke 2006\n"
        s += "Copyright: DSP Templates Corporation 2006\n"
        s += "Revision 665\n"
        r = dialog.messageDialog(self,s, 'Notice') 
        if (r.accepted == False): sys.exit()


    def doFiltplot(self):
        comp = self.components
        
        canvas = comp.bufOff
        width, height = canvas.size
        xOffset = width / 2
        yOffset = height / 2


        pass_edge = comp.sldPassband.value/2000.0
        trans = pass_edge*comp.sldtrans.value/2000.0
        hb_trans = comp.sldtrans.value/2000.0
        delta = comp.sldtrans.value/2000.0
        notch_trans = 1.0-comp.sldtrans.value/1000.0
        stop_edge = pass_edge + trans
        if (stop_edge > 0.42):
            stop_edge = 0.42
        stop_dBs = -comp.sldWeight.value/10
        stop_weight = 10**(-stop_dBs/20.0)
        taps = comp.sldTaps.value
        self.bits = comp.sldBits.value
        order = comp.sldOrder.value
        ripple = stop_weight
        if(ripple>1):
            ripple = 1
        alpha = comp.sldAlpha.value/1000.0
        CF = iir_coeff(order)
        MF = fir_coeff_double(taps);
        use_fir = 0
        use_iir = 0

        comp.Coefficients.clear()
        if (comp.filtType.stringSelection == 'Maxflat FIR'):
            butterworth_fir(MF, pass_edge)
            use_fir = 1
        elif (comp.filtType.stringSelection == 'Remez FIR'):
            create_remez_lpfir(MF,pass_edge,stop_edge,stop_weight)
            use_fir = 1
        elif (comp.filtType.stringSelection == 'Gaussian FIR'):
            gaussian_fir(MF, pass_edge, 8)
            use_fir = 1
        elif (comp.filtType.stringSelection == 'Raised Cosine FIR'):
            raised_cosine(MF, alpha, 2)
            use_fir = 1
        elif (comp.filtType.stringSelection == 'Root Raised Cosine FIR'):
            root_raised_cosine(MF, alpha, 2)
            use_fir = 1
        elif (comp.filtType.stringSelection == 'Elliptic'):
            elliptic_iir(CF,pass_edge,stop_edge,stop_dBs,ripple);
            use_iir = 1
        elif (comp.filtType.stringSelection == 'Chebyshev'):
            chebyshev_iir(CF,pass_edge,ripple);
            use_iir = 1
        elif (comp.filtType.stringSelection == 'Notch IIR'):
            NF = notch_allpass_double(pass_edge,notch_trans)
            z = self.other_freq(NF)
        elif (comp.filtType.stringSelection == 'Cut Boost'):
            BF = cutboost_double(pass_edge,notch_trans,stop_weight)
            z = self.other_freq(BF)
        elif (comp.filtType.stringSelection == 'Halfband IIR'):
            AF = iir_allpass1_cascade_double(pass_edge,order,self.bits)
            z = self.other_freq(AF)
            s0 = "A0 = "
            s1 = "A1 = "
            for i in xrange(order):
                if (AF.get_a0(i) > 0.0001):
                    s0 += str(AF.get_a0(i)) + " "
                if (AF.get_a1(i) > 0.0001):
                    s1 += str(AF.get_a1(i)) + " "
            comp.Coefficients.setInsertionPoint(0)
            comp.Coefficients.appendText(s0)
            comp.Coefficients.appendText("\n"+s1)
        else:
            butterworth_iir(CF,pass_edge,3.0);
            use_iir = 1

        if use_fir:
            z = self.filt_freq(MF)
            s0 = "Coefficients = "
            for i in xrange(taps):
                if (i==taps-1):
                    s0 += str(MF.gettap(i))
                else:
                    s0 += str(MF.gettap(i)) + ", "
            comp.Coefficients.clear()
            comp.Coefficients.appendText(s0)

        if use_iir:
            z = self.filt_freq(CF)
            s0 = "Coefficients in second order sections\n"
            s0 += "B = "
            for i in xrange(order/2):
                s0 += "1.0,"
                s0 += str(CF.get_coeff_b(2*i)) + ","
                s0 += str(CF.get_coeff_b(2*i+1)) + "/"
            s0 += "\n"
            s0 += "A  = "
            for i in xrange(order/2):
                s0 += "1.0,"
                s0 += str(CF.get_coeff_a(2*i)) + ","
                s0 += str(CF.get_coeff_a(2*i+1)) + "/"
            comp.Coefficients.clear()
            comp.Coefficients.appendText(s0)

        color = 'red'

        canvas.foregroundColor = color
        canvas.autoRefresh = 0
        canvas.clear()
        
        lastX = 0
        lastY = yOffset
        self.keepDrawing = 1
        points = []
        grid  = []
            
        for i in xrange(10):
            y_grid = i*height/10
            grid.append((0, y_grid, width, y_grid))
        grid.append((0, height-1, width, height-1))

        for i in xrange(10):
            x_grid = i*width/10
            grid.append((x_grid, 0, x_grid, height))
        grid.append((width-1, 0, width-1, height))

        canvas.drawLineList(grid)
        canvas.foregroundColor = 'blue'
        
        for i in xrange(pts):
            x = i
            y = 0.2*yOffset - 0.01*height*z[i]
            points.append((lastX, lastY, x, y))
            lastX = x
            lastY = y


        canvas.drawLineList(points)
        canvas.autoRefresh = 1
        canvas.refresh()

    def on_select(self, event):
        name = event.target.name
        # only process Sliders
        if name.startswith('sld'):
            labelName = 'stc' + name[3:]
            self.components[labelName].text = self.sliderLabels[labelName] + \
                ' ' + str(event.target.value)
        self.doFiltplot()

    def setSliderLabels(self):
        comp = self.components
        for key in self.sliderLabels:
            sliderName = 'sld' + key[3:]
            comp[key].text = self.sliderLabels[key] + ' ' + str(comp[sliderName].value)

    def on_editClear_command(self, event):
        self.components.bufOff.clear()

    def to_complex(self,cp):
        return(complex(cp.re,cp.im))

    def filt_freq(self,FIR):
        z = []
        FIR.quantize(self.bits)
        h0 = FIR.freqz_mag(0)
        if (h0 < 0.01): h0 = 1.0
        for i in xrange(pts):
            h = FIR.freqz_mag(w[i])
            t = h/h0
            if (t == 0): t = 0.00001
            tl = 20*log10(t)
            z.append(tl)
        return z

    def other_freq(self,AP):
        imp = 1
        dsum = 0
        d = []
        h = []
        for i in xrange(pts):
            d.append(AP.clock(imp))
            dsum = dsum+d[i]
            imp = 0
        dsum = 1.0/dsum

        for k in xrange(pts):
            sum = 0
            z = complex(1.0,0.0)
            z_inc = complex(cos(w[k]),sin(w[k]))
            for i in xrange(pts):
                sum = sum + z*d[i]*dsum
                z   = z*z_inc
            h.append(20*log10(abs(sum)))
        return h

if __name__ == '__main__':
    app = model.Application(Filtplot)
    app.MainLoop()