// -*- C++ -*- generated by wxGlade 0.4 on Wed Apr 19 09:12:48 2006

/********************************

Copyright 2006-2012 E.J Boks, Hogeschool van Arnhem en Nijmegen
Demonstratieprogramma voor IIR implementatie met Matlab filter coefficienten

********************************/ 

#include "algdef.h"

#include "iirfloatfilter.h"
#include "iircoeff.h"



/******** Filter klasse code **********/

/*
 * Filter Design and Analysis Tool - Generated Filter Coefficients - C Source 
 *  Generated by MATLAB - Signal Processing Toolbox
 */
/* General type conversion for MATLAB generated C-code  */
/* 
 * Expected path to tmwtypes.h 
 * /usr/local/matlab65/extern/include/tmwtypes.h 
 */

const UInt16 tellerLengte[MWSPT_NSEC] = { 1,3,3,3,3,3,3,2 };
const Double tellerCoefficienten[MWSPT_NSEC][3] = {
  {
       0.51615906391,                 0,                 0 
  },
  {
     0.7776382699331,   0.4908779174325,   0.7776382699331 
  },
  {
     0.8144293542159,   0.6001828338982,   0.8144293542159 
  },
  {
     0.7485207296405,   0.7085061289624,   0.7485207296405 
  },
  {
     0.6402019868512,   0.7979739416136,   0.6402019868512 
  },
  {
     0.5405199753053,    0.859783121813,   0.5405199753053 
  },
  {
     0.4118972566877,   0.7754465411765,   0.4118972566877 
  },
  {
     0.4096996863761,   0.4096996863761,                 0 
  }
};
const UInt16 noemerLengte[MWSPT_NSEC] = { 1,3,3,3,3,3,3,2 };
const Double noemerCoefficienten[MWSPT_NSEC][3] = {
  {
                   1,                 0,                 0 
  },
  {
                   1,   0.1074131298721,   0.8559698954839 
  },
  {
                   1,   0.1485514710581,   0.6186239641556 
  },
  {
                   1,   0.2249254723762,    0.428406853158 
  },
  {
                   1,   0.3162749074981,   0.2750753846405 
  },
  {
                   1,   0.4024802753935,   0.1587022884367 
  },
  {
                   1,   0.4641954702153,  0.08472534046386 
  },
  {
                   1,   0.2433203441677,                 0 
  }
};



FilterIIRDoubleSectie::FilterIIRDoubleSectie(double const * const xc,    
                                             double const * const yc) : xCoeffs(RingBuffer<Double>(3)),
                                                                        yCoeffs(RingBuffer<Double>(3)),
                                                                        xWaarden(RingBuffer<Double>(3)),
                                                                        yWaarden(RingBuffer<Double>(2))
{
    for (unsigned int i=0;i<3;i++)
    {
        xCoeffs.schrijf(*(xc+i));
        yCoeffs.schrijf(*(yc+i));
    }
    reset();
}

FilterIIRDoubleSectie::~FilterIIRDoubleSectie()
{

}
	

void FilterIIRDoubleSectie::reset()
{
	xWaarden.reset();
	yWaarden.reset();
}

double FilterIIRDoubleSectie::filter(const double invoer)
{
	register double mac=0;
	
	xWaarden.schrijf(invoer);

	for (unsigned int i=0;i<3;i++)
    {
        const double h = xCoeffs[i];
        const double x = xWaarden.lees();
		
        mac += h*x;  
    }
	
	for (unsigned int i=1;i<3;i++)  /* coeff [0] = y[n], dus niet gebruiken */
    {
        const double h = yCoeffs[i];
        const double y = yWaarden.lees();
		
        mac -= h*y;  /* matlab coeffs zijn negatief uitgedruk, staan aan de kant van y[n] in de vergelijking */  
    }
	
	/* mac is nu de huidige uitkomst. sla deze op voor de volgende keer */
	yWaarden.schrijf(mac);
	
	return(mac);
}



FilterIIRDouble::FilterIIRDouble(const Teller as,
                                 double const * const xc,     
                                 double const * const yc)  : aantalSekties(as)
{
    wxASSERT(aantalSekties <= MaxAantalSekties);
	
    for (unsigned int i=0;i<aantalSekties;i++)
    {
        sekties[i] = new FilterIIRDoubleSectie((xc+3*i),
                                               (yc+3*i));
		
    }
	
}

FilterIIRDouble::~FilterIIRDouble()
{
	for (unsigned int i=0;i<aantalSekties;i++)
		delete sekties[i];

}

void FilterIIRDouble::reset()
{
	for (unsigned int i=0;i<aantalSekties;i++)
		sekties[i]->reset();
}

double FilterIIRDouble::filter(const double invoer)
{
	register double tusseninvoer = sekties[0]->filter(invoer);
	for (unsigned int i=1;i<aantalSekties;i++)
		tusseninvoer = sekties[i]->filter(tusseninvoer);

	return(tusseninvoer);
}



typedef enum
{
    startKnopID=0,
    schoonKnopID,
    eindeKnopID,
    signaalKeuzeID,
    signaalAmplitudeID,
    signaalFreqKeuzeID,
	GrafiekVensterID
} knoppenIDs;



IIRFloatVenster::IIRFloatVenster(wxWindow* parent, int id, const wxString& title, const wxPoint& pos, const wxSize& size, long style):
    wxFrame(parent, id, title, pos, size, wxDEFAULT_FRAME_STYLE),
    filter(MWSPT_NSEC,
           (const Double *)tellerCoefficienten,
           (const Double *)noemerCoefficienten),
    start(false)
{
    SetBackgroundStyle(wxBG_STYLE_SYSTEM);

    // begin wxGlade: IIRFloatVenster::IIRFloatVenster
    paneel = new wxPanel(this, wxID_ANY);
    iirFloatVenster_menubar = new wxMenuBar();
    wxMenu* wxglade_tmp_menu_1 = new wxMenu();
    wxglade_tmp_menu_1->Append(wxID_ABOUT, wxT("&About"), wxEmptyString, wxITEM_NORMAL);
    wxglade_tmp_menu_1->Append(wxID_EXIT, wxT("&Exit\tCtrl+Q"), wxEmptyString, wxITEM_NORMAL);
    iirFloatVenster_menubar->Append(wxglade_tmp_menu_1, wxT("Bestand"));
    SetMenuBar(iirFloatVenster_menubar);
    const wxString signaalKeuzeRadioBox_choices[] = {
        wxT("cosinus"),
        wxT("blokgolf"),
        wxT("impulsfunktie"),
        wxT("stapfunktie")
    };
    signaalKeuzeRadioBox = new wxRadioBox(paneel, signaalKeuzeID, wxT("Signaal"), wxDefaultPosition, wxDefaultSize, 4, signaalKeuzeRadioBox_choices, 0, wxRA_SPECIFY_ROWS);
    amplitudeLabel = new wxStaticText(paneel, wxID_ANY, wxT("Signaalamplitude"));
    amplitudeSpin = new wxSpinCtrl(paneel, signaalAmplitudeID, wxT("20000"), wxDefaultPosition, wxDefaultSize, wxSP_ARROW_KEYS, 0, 32768);
    sigFreqLabel = new wxStaticText(paneel, wxID_ANY, wxT("Signaalfrequentie"));
    const wxString signaalFreqKeuze_choices[] = {
        wxT("DC"),
        wxT("0,05*PI"),
        wxT("0,1*PI"),
        wxT("0,2*PI"),
        wxT("0,4*PI"),
        wxT("0,6*PI"),
        wxT("0,8*PI"),
        wxT("0,9*PI"),
        wxEmptyString,
        wxEmptyString
    };
    signaalFreqKeuze = new wxChoice(paneel, signaalFreqKeuzeID, wxDefaultPosition, wxDefaultSize, 10, signaalFreqKeuze_choices, 0);
    startKnop = new wxToggleButton(paneel, startKnopID, wxT("Teken"));
    eindeKnop = new wxButton(paneel, wxID_EXIT, wxEmptyString);
    kopTekstLabel = new wxStaticText(paneel, wxID_ANY, wxT("Implementatie van een double floating point IIR filter"));
    grafiekPaneel = new GrafiekVenster(paneel, GrafiekVensterID, wxDefaultPosition, wxSize(900,400));

    set_properties();
    do_layout();
    // end wxGlade
	
	signaal.Alloc(AantalDataPunten);
	signaalGefilterd.Alloc(AantalDataPunten);

	const wxSize grootte = grafiekPaneel->geefTekenVeldGrootte();
	grafiekPaneel->zetGroteText(_("Floating Point IIR Demo"),wxPoint(0,2*grootte.GetHeight()/3));
}


BEGIN_EVENT_TABLE(IIRFloatVenster, wxFrame)

    EVT_UPDATE_UI(eindeKnopID, IIRFloatVenster::eindeUpdateHandler)
    EVT_UPDATE_UI(signaalKeuzeID, IIRFloatVenster::eindeUpdateHandler)
    EVT_UPDATE_UI(signaalAmplitudeID, IIRFloatVenster::eindeUpdateHandler)
    EVT_UPDATE_UI(signaalFreqKeuzeID, IIRFloatVenster::eindeUpdateHandler)
  
    // begin wxGlade: IIRFloatVenster::event_table
    EVT_MENU(wxID_ABOUT, IIRFloatVenster::overHandler)
    EVT_MENU(wxID_EXIT, IIRFloatVenster::eindeHandler)
    EVT_RADIOBOX(signaalKeuzeID, IIRFloatVenster::signaalKeuzeHandler)
    EVT_SPINCTRL(signaalAmplitudeID, IIRFloatVenster::signaalAmplitudeHandler)
    EVT_CHOICE(signaalFreqKeuzeID, IIRFloatVenster::signaalFreqHandler)
    EVT_TOGGLEBUTTON(startKnopID, IIRFloatVenster::startStopHandler)
    EVT_BUTTON(wxID_ANY, IIRFloatVenster::eindeHandler)
    // end wxGlade
END_EVENT_TABLE();


void IIRFloatVenster::eindeUpdateHandler(wxUpdateUIEvent &event)
{
    event.Enable(start==False);
}

void IIRFloatVenster::signaalKeuzeHandler(wxCommandEvent &event)
{
   const UInt32 keuze = signaalKeuzeRadioBox->GetSelection();
    
    if ((keuze == 2) || (keuze == 3))
	signaalFreqKeuze->Disable();
}


void IIRFloatVenster::signaalAmplitudeHandler(wxSpinEvent &event)
{
    amplitude = (double)amplitudeSpin->GetValue();
}


void IIRFloatVenster::signaalFreqHandler(wxCommandEvent &event)
{
    switch(signaalFreqKeuze->GetSelection())
    {
    case 0: 
	hoekFreq = 0.0;
	break;

    case 1:
	hoekFreq = 0.05*Pi;
	break;

    case 2:
	hoekFreq = 0.1*Pi;
	break;

    case 3:
	hoekFreq = 0.2*Pi;
	break;
    case 4:
	hoekFreq = 0.4*Pi;
	break;
    case 5:
	hoekFreq = 0.6*Pi;
	break;
    case 6:
	hoekFreq = 0.8*Pi;
	break;
    case 7:
	hoekFreq = 0.9*Pi;
	break;

    default:
	break;
    }
   
}


void IIRFloatVenster::startStopHandler(wxCommandEvent &event)
{
  start = startKnop->GetValue();
    
	if (start==false)
	{
			grafiekPaneel->maakSchoon();
			startKnop->SetLabel(wxT("Teken"));
	}
	else
		{
			amplitude = (double)amplitudeSpin->GetValue();
			signaalFreqHandler(event);

			bouwSignaal();

			filterSignaal();

           tekenSignalen();	
		}

}


void IIRFloatVenster::eindeHandler(wxCommandEvent &event)
{
    Close();
}

void IIRFloatVenster::overHandler(wxCommandEvent &event)
{
	wxGetApp().geefCopyright(wxT("IIR Float Filter demonstratie"), 
                                 wxT("Deze toepassing laat zien hoe een C/C+ implementatie van een IIR Filter, gebaseerd op Matlab coefficienten, er uit ziet."));
	
	
}
				 
// wxGlade: add IIRFloatVenster event handlers


void IIRFloatVenster::set_properties()
{
    // begin wxGlade: IIRFloatVenster::set_properties
    SetTitle(wxT("IIR filter implementatie demo"));
    signaalKeuzeRadioBox->SetSelection(0);
    signaalFreqKeuze->SetSelection(2);
    kopTekstLabel->SetFont(wxFont(16, wxDEFAULT, wxNORMAL, wxNORMAL, 0, wxT("")));
    grafiekPaneel->SetMinSize(wxSize(900,400));
    // end wxGlade
}


void IIRFloatVenster::do_layout()
{
    // begin wxGlade: IIRFloatVenster::do_layout
    wxBoxSizer* sizer_1 = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer* sizer_2 = new wxBoxSizer(wxHORIZONTAL);
    wxBoxSizer* sizer_3 = new wxBoxSizer(wxVERTICAL);
    wxBoxSizer* sizer_4 = new wxBoxSizer(wxVERTICAL);
    sizer_4->Add(signaalKeuzeRadioBox, 0, wxALL|wxALIGN_BOTTOM, 10);
    sizer_4->Add(amplitudeLabel, 0, wxLEFT|wxRIGHT|wxTOP, 10);
    sizer_4->Add(amplitudeSpin, 0, wxLEFT|wxRIGHT|wxBOTTOM|wxALIGN_CENTER_HORIZONTAL, 10);
    sizer_4->Add(sigFreqLabel, 0, wxLEFT|wxRIGHT|wxTOP|wxALIGN_CENTER_HORIZONTAL, 10);
    sizer_4->Add(signaalFreqKeuze, 0, wxLEFT|wxRIGHT|wxBOTTOM|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 10);
    sizer_4->Add(startKnop, 0, wxALL|wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL, 20);
    sizer_4->Add(eindeKnop, 0, wxALL|wxALIGN_CENTER_HORIZONTAL, 20);
    sizer_2->Add(sizer_4, 1, wxEXPAND, 0);
    sizer_3->Add(kopTekstLabel, 0, wxALIGN_CENTER_HORIZONTAL, 0);
    sizer_3->Add(grafiekPaneel, 1, wxALL|wxEXPAND|wxFIXED_MINSIZE, 10);
    sizer_2->Add(sizer_3, 6, wxEXPAND, 0);
    paneel->SetSizer(sizer_2);
    sizer_1->Add(paneel, 1, wxEXPAND, 0);
    SetSizer(sizer_1);
    sizer_1->Fit(this);
    Layout();
    // end wxGlade
}

/****************** filter funkties *******************/
void IIRFloatVenster::bouwSignaal()
{
    UInt32 i;
	
	signaal.Empty();
	
    switch(signaalKeuzeRadioBox->GetSelection())
    {
    case 0:  /* cosinus */          /* signaal  = cos(2*pi*f/fs * i ) = cos( 0 .. pi * i) */
	for (i=0;i<AantalDataPunten;i++)
	    signaal.Add((amplitude*cos(hoekFreq*i)));
	break;

    case 1:  /* blokgolf */
	for (i=0;i<AantalDataPunten;i++)
	{
	    if (cos(hoekFreq*i) > 0 )
			signaal.Add(amplitude);
	    else
			signaal.Add( -1*amplitude);
	}
	
	break;
	
    case 2: /* impuls op 25% van de totale invoer */
	for (i=0;i<(AantalDataPunten/4);i++)
	    signaal.Add(0);

	signaal.Add(amplitude);
			
	for (i=0;i<((3*AantalDataPunten)/4);i++)
		signaal.Add(0);
	
	break;
	
    case 3:  /* stapfunktie vanaf 25% vanaf begin */
	for (i=0;i<AantalDataPunten/4;i++)
	    signaal.Add(0);

	for (i=0;i<((3*AantalDataPunten)/4);i++)
		    signaal.Add(amplitude);
	break;
	
    default:
	break;
	
    }
}



void IIRFloatVenster::filterSignaal()
{
	signaalGefilterd.Empty();
	filter.reset();

	for (unsigned int i=0;i<AantalDataPunten;i++)
		signaalGefilterd.Add(filter.filter(signaal[i]));
		
}

void IIRFloatVenster::tekenSignalen()
{
//	if (Ok != grafiekPaneel->kopieerSignaal(signaal,sigGefilterd))
//	    wxLogDebug(wxT("(startStopHandler) kon data niet inladen."));
//	else
    const wxSize grootte = grafiekPaneel->geefTekenVeldGrootte();

    const double xSchaal = (grootte.GetWidth()*1.0)/(2*AantalDataPunten);
    const double ySchaal = grootte.GetHeight()/(2.5*amplitude);


    for (unsigned int i=0;i<AantalDataPunten;i++)
    {
        const wxCoord xSig=2*i*xSchaal,xGefSig=(2*i+1)*xSchaal;

        const wxPoint sigOffset(xSig,grootte.GetWidth()/4);
        const wxPoint gefSigOffset(xGefSig,(grootte.GetWidth())/4);

        const wxPoint sig(xSig,sigOffset.y+ySchaal*signaal[i]);
        const wxPoint gefSig(xGefSig,gefSigOffset.y+ySchaal*signaalGefilterd[i]);

        grafiekPaneel->zetPen(wxPen(wxT("RED"),xSchaal));            
        grafiekPaneel->tekenLijn(sigOffset,sig);

        grafiekPaneel->zetPen(wxPen(wxT("BLUE"),xSchaal));            
        grafiekPaneel->tekenLijn(gefSigOffset,gefSig);

    }

    grafiekPaneel->Refresh();    
    startKnop->SetLabel(wxT("Stop"));
}

/******* Hieronder : de applikatie *******/

IMPLEMENT_APP(IIRFloatFilter)

IIRFloatFilter::IIRFloatFilter() : DesktopApp(wxT("IIRFloatFilter"))
{
	
}

bool IIRFloatFilter::OnInit()
{
    IIRFloatVenster *venster = new IIRFloatVenster(0, -1,_(""));
    SetTopWindow(venster);
    venster->Show();
    return true;
}


