diff --git a/Makefile.am b/Makefile.am
index c7049e00..2b5fd331 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -36,6 +36,7 @@ SUBDIRS = \
qucs-help \
qucs-lib \
qucs-transcalc \
+ qucs-activefilter \
qucs-rescodes \
contrib \
$(FILTERV2) \
@@ -48,7 +49,7 @@ if COND_MACOSX
app_PROGS = $(top_builddir)/qucs/qucs \
$(top_builddir)/qucs-attenuator/qucsattenuator \
$(top_builddir)/qucs-filter/qucsfilter \
- $(top_builddir)/qucsactivefilter/qucsactivefilter \
+ $(top_builddir)/qucs-activefilter/qucsactivefilter \
$(top_builddir)/qucs-help/qucshelp \
$(top_builddir)/qucs-lib/qucslib \
$(top_builddir)/qucs-edit/qucsedit \
diff --git a/configure.ac b/configure.ac
index e819e778..fcd88338 100644
--- a/configure.ac
+++ b/configure.ac
@@ -801,7 +801,7 @@ AC_CONFIG_FILES([Makefile
qucs-help/docs/cs/Makefile
qucs-help/docs/pt/Makefile
qucs-filter/Makefile
- qucsactivefilter/Makefile
+ qucs-activefilter/Makefile
qucs-transcalc/Makefile
qucs-transcalc/examples/Makefile
qucs-lib/Makefile
diff --git a/qucs-activefilter/.gitignore b/qucs-activefilter/.gitignore
new file mode 100644
index 00000000..9d1b6d2a
--- /dev/null
+++ b/qucs-activefilter/.gitignore
@@ -0,0 +1,19 @@
+*.o
+*.cpp~
+*.h~
+qucsactivefilter
+*.pro.user
+Makefile
+moc_*.cpp
+*.sch
+*.sch~
+*.dat
+*.dpl
+qrc_*.cpp
+moc_*.cxx
+qrc_*.cxx
+CMakeFiles
+CMakeCache.txt
+*.cmake
+*.depends
+
diff --git a/qucs-activefilter/AFR.svg b/qucs-activefilter/AFR.svg
new file mode 100644
index 00000000..04a1f40d
--- /dev/null
+++ b/qucs-activefilter/AFR.svg
@@ -0,0 +1,401 @@
+
+
+
+
diff --git a/qucs-activefilter/CMakeLists.txt b/qucs-activefilter/CMakeLists.txt
new file mode 100644
index 00000000..b316a279
--- /dev/null
+++ b/qucs-activefilter/CMakeLists.txt
@@ -0,0 +1,96 @@
+PROJECT(qucsactivefilter CXX C)
+CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
+cmake_policy(VERSION 2.6)
+
+set(PROJECT_VERSION_MAJOR "0")
+set(PROJECT_VERSION_MINOR "0")
+set(PROJECT_VERSION_PATCH "18")
+set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
+set(PROJECT_VENDOR "Qucs team. This program is licensed under the GNU GPL")
+set(PROJECT_COPYRIGHT_YEAR "2014")
+set(PROJECT_DOMAIN_FIRST "qucs")
+set(PROJECT_DOMAIN_SECOND "org")
+
+SET(CMAKE_BUILD_TYPE Debug)
+
+ADD_DEFINITIONS( -DHAVE_CONFIG_H )
+
+# define variables
+SET(BINARYDIR "${CMAKE_INSTALL_PREFIX}/bin/")
+SET(BITMAPDIR "${CMAKE_INSTALL_PREFIX}/share/qucs/bitmaps/")
+SET(DOCDIR "${CMAKE_INSTALL_PREFIX}/share/qucs/docs/")
+SET(LANGUAGEDIR "${CMAKE_INSTALL_PREFIX}/share/qucs/lang/")
+SET(LIBRARYDIR "${CMAKE_INSTALL_PREFIX}/share/qucs/library/")
+SET(OCTAVEDIR "${CMAKE_INSTALL_PREFIX}/share/qucs/octave/")
+
+#configure the header config.h
+CONFIGURE_FILE (
+ "${PROJECT_SOURCE_DIR}/../config.h.cmake"
+ "${PROJECT_BINARY_DIR}/config.h"
+)
+
+INCLUDE_DIRECTORIES("${PROJECT_BINARY_DIR}")
+
+FIND_PACKAGE( Qt4 REQUIRED )
+SET( QT_USE_QTGUI TRUE )
+SET( QT_USE_QTSVG TRUE )
+
+INCLUDE( ${QT_USE_FILE} )
+
+ADD_DEFINITIONS(${QT_DEFINITIONS})
+
+SET(QUCS-ACTIVE-FILTER_SRCS
+filter.cpp
+mfbfilter.cpp
+main.cpp
+qf_poly.cpp
+sallenkey.cpp
+schcauer.cpp
+transferfuncdialog.cpp
+qucsactivefilter.cpp
+)
+
+SET(QUCS-ACTIVE-FILTER_MOC_HDRS
+transferfuncdialog.h
+qucsactivefilter.h
+)
+
+QT4_WRAP_CPP(QUCS-ACTIVE-FILTER_MOC_SRCS ${QUCS-ACTIVE-FILTER_MOC_HDRS})
+
+SET(RESOURCES qucsactivefilter.qrc)
+QT4_ADD_RESOURCES(RESOURCES_SRCS ${RESOURCES})
+
+
+IF(APPLE)
+ # set information on Info.plist file
+ SET(MACOSX_BUNDLE_INFO_STRING "${PROJECT_NAME} ${PROJECT_VERSION}")
+ SET(MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_NAME} ${PROJECT_VERSION}")
+ SET(MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_NAME} ${PROJECT_VERSION}")
+ SET(MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION}")
+ SET(MACOSX_BUNDLE_COPYRIGHT "${PROJECT_COPYRIGHT_YEAR} ${PROJECT_VENDOR}")
+ SET(MACOSX_BUNDLE_GUI_IDENTIFIER "${PROJECT_DOMAIN_SECOND}.${PROJECT_DOMAIN_FIRST}")
+ SET(MACOSX_BUNDLE_BUNDLE_NAME "${PROJECT_NAME}")
+ SET(MACOSX_BUNDLE_ICON_FILE qucsactivefilter.icns)
+
+ # set where in the bundle to put the icns file
+ SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/../qucs/bitmaps/qucsactivefilter.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
+ # include the icns file in the target
+ SET(QUCS-ACTIVE-FILTER_SRCS ${QUCS-ACTIVE-FILTER_SRCS} ${CMAKE_CURRENT_SOURCE_DIR}/../qucs/bitmaps/qucsactivefilter.icns)
+
+ENDIF(APPLE)
+
+ADD_EXECUTABLE(qucsactivefilter MACOSX_BUNDLE WIN32
+ ${QUCS-ACTIVE-FILTER_SRCS}
+ ${QUCS-ACTIVE-FILTER_MOC_SRCS}
+ ${RESOURCES_SRCS} )
+
+TARGET_LINK_LIBRARIES(qucsactivefilter ${QT_LIBRARIES})
+
+INSTALL(TARGETS qucsactivefilter
+ BUNDLE DESTINATION bin COMPONENT Runtime
+ RUNTIME DESTINATION bin COMPONENT Runtime
+ )
+
+# man pages
+INSTALL( FILES qucsactivefilter.1 DESTINATION share/man/man1 )
+
diff --git a/qucsactivefilter/Makefile.am b/qucs-activefilter/Makefile.am
similarity index 100%
rename from qucsactivefilter/Makefile.am
rename to qucs-activefilter/Makefile.am
diff --git a/qucs-activefilter/README b/qucs-activefilter/README
new file mode 100644
index 00000000..d8acf12c
--- /dev/null
+++ b/qucs-activefilter/README
@@ -0,0 +1,2 @@
+QucsActiveFilter is tool for sintezing active and passive analog filters.
+
diff --git a/qucs-activefilter/bessel-poles.m b/qucs-activefilter/bessel-poles.m
new file mode 100755
index 00000000..b8b13654
--- /dev/null
+++ b/qucs-activefilter/bessel-poles.m
@@ -0,0 +1,57 @@
+#!/usr/bin/octave -qf
+
+printf("Generating bessel.h...\n");
+
+maxorder=20;
+
+fid=fopen("bessel.h","w");
+fprintf(fid,"#ifndef BESSEL_H\n");
+fprintf(fid,"#define BESSEL_H\n");
+fprintf(fid,"//Bessel coeffs table\n //Generated automatically! DO NOT EDIT!!!\n\n\n");
+fprintf(fid,"\n\ndouble BesselPoles[%d][%d]={\n\n",maxorder,2*maxorder);
+
+for n=1:maxorder;
+
+fprintf(fid,"/* %d th order */ {\n",n);
+b=1;
+for k=1:n+1;
+b(k)=factorial(2*n-(k-1))/((2^(n-(k-1)))*factorial(k-1)*factorial(n-(k-1)));
+endfor;
+b=fliplr(b);
+#disp(b);
+#printf("Bessel polynomial %dth order poles:",n);
+poles=roots(b);
+Np=length(poles);
+
+for i=1:Np;
+fprintf(fid," %f, ",real(poles(i)));
+#fprintf(fid,"\t%f,\n",imag(poles(i)));
+if (i==maxorder)
+fprintf(fid," %f \n",imag(poles(i)));
+else
+fprintf(fid," %f, ",imag(poles(i)));
+endif;
+endfor;
+
+for i=Np+1:maxorder;
+#fprintf(fid," 0.0,\n");
+if (i==maxorder)
+fprintf(fid," 0.0 \n");
+else
+fprintf(fid," 0.0, ");
+endif;
+endfor;
+
+if (n==maxorder)
+fprintf(fid,"\t}\n");
+else
+fprintf(fid,"\t},\n");
+endif;
+
+endfor;
+
+fprintf(fid,"\n};\n");
+fprintf(fid,"#endif\n");
+fclose(fid);
+
+printf("bessel.h successfully generated!\n");
diff --git a/qucs-activefilter/bessel.h b/qucs-activefilter/bessel.h
new file mode 100644
index 00000000..387d342b
--- /dev/null
+++ b/qucs-activefilter/bessel.h
@@ -0,0 +1,73 @@
+#ifndef BESSEL_H
+#define BESSEL_H
+//Bessel coeffs table
+ //Generated automatically! DO NOT EDIT!!!
+
+
+
+
+double BesselPoles[20][40]={
+
+/* 1 th order */ {
+ -1.000000, 0.000000, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
+ },
+/* 2 th order */ {
+ -1.500000, 0.866025, -1.500000, -0.866025, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
+ },
+/* 3 th order */ {
+ -1.838907, 1.754381, -1.838907, -1.754381, -2.322185, 0.000000, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
+ },
+/* 4 th order */ {
+ -2.103789, 2.657418, -2.103789, -2.657418, -2.896211, 0.867234, -2.896211, -0.867234, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
+ },
+/* 5 th order */ {
+ -2.324674, 3.571023, -2.324674, -3.571023, -3.646739, 0.000000, -3.351956, 1.742661, -3.351956, -1.742661, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
+ },
+/* 6 th order */ {
+ -2.515932, 4.492673, -2.515932, -4.492673, -3.735708, 2.626272, -3.735708, -2.626272, -4.248359, 0.867510, -4.248359, -0.867510, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
+ },
+/* 7 th order */ {
+ -2.685677, 5.420694, -2.685677, -5.420694, -4.070139, 3.517174, -4.070139, -3.517174, -4.971787, 0.000000, -4.758291, 1.739286, -4.758291, -1.739286, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
+ },
+/* 8 th order */ {
+ -2.838984, 6.353911, -2.838984, -6.353911, -4.368289, 4.414443, -4.368289, -4.414443, -5.204841, 2.616175, -5.204841, -2.616175, -5.587886, 0.867614, -5.587886, -0.867614, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
+ },
+/* 9 th order */ {
+ -2.979261, 7.291464, -2.979261, -7.291464, -4.638440, 5.317272, -4.638440, -5.317272, -5.604422, 3.498157, -5.604422, -3.498157, -6.297019, 0.000000, -6.129368, 1.737848, -6.129368, -1.737848, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
+ },
+/* 10 th order */ {
+ -3.108916, 8.232699, -3.108916, -8.232699, -4.886220, 6.224985, -4.886220, -6.224985, -5.967528, 4.384947, -5.967528, -4.384947, -6.615291, 2.611568, -6.615291, -2.611568, -6.922045, 0.867665, -6.922045, -0.867665, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
+ },
+/* 11 th order */ {
+ -3.229722, 9.177112, -3.229722, -9.177112, -5.115648, 7.137021, -5.115648, -7.137021, -6.301337, 5.276192, -6.301337, -5.276192, -7.057892, 3.489015, -7.057892, -3.489015, -7.622340, 0.000000, -7.484230, 1.737103, -7.484230, -1.737103, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
+ },
+/* 12 th order */ {
+ -3.343023, 10.124297, -3.343023, -10.124297, -5.329709, 8.052907, -5.329709, -8.052907, -6.611004, 6.171535, -6.611004, -6.171535, -7.465571, 4.370170, -7.465571, -4.370170, -7.997271, 2.609067, -7.997271, -2.609067, -8.253422, 0.867694, -8.253422, -0.867694, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
+ },
+/* 13 th order */ {
+ -3.449867, 11.073929, -3.449867, -11.073929, -5.530681, 8.972248, -5.530681, -8.972248, -6.900373, 7.070644, -6.900373, -7.070644, -7.844380, 5.254903, -7.844380, -5.254903, -8.470592, 3.483868, -8.470592, -3.483868, -8.947710, 0.000000, -8.830252, 1.736666, -8.830252, -1.736666, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
+ },
+/* 14 th order */ {
+ -3.551087, 12.025738, -3.551087, -12.025738, -5.720352, 9.894708, -5.720352, -9.894708, -7.172396, 7.973217, -7.172396, -7.973217, -8.198847, 6.143041, -8.198847, -6.143041, -8.911001, 4.361604, -8.911001, -4.361604, -9.363146, 2.607553, -9.363146, -2.607553, -9.583171, 0.867711, -9.583171, -0.867711, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0
+ },
+/* 15 th order */ {
+ -3.647357, 12.979501, -3.647357, -12.979501, -5.900152, 10.819999, -5.900152, -10.819999, -7.429397, 8.878983, -7.429397, -8.878983, -8.532459, 7.034394, -8.532459, -7.034394, -9.323599, 5.242259, -9.323599, -5.242259, -9.859567, 3.480671, -9.859567, -3.480671, -10.273109, 0.000000, -10.170914, 1.736389, -10.170914, -1.736389, 0.0, 0.0, 0.0, 0.0, 0.0
+ },
+/* 16 th order */ {
+ -3.739232, 13.935028, -3.739232, -13.935028, -6.071241, 11.747875, -6.071241, -11.747875, -7.673241, 9.787697, -7.673241, -9.787697, -8.847968, 7.928773, -8.847968, -7.928773, -9.712326, 6.125761, -9.712326, -6.125761, -10.325121, 4.356163, -10.325121, -4.356163, -10.911887, 0.867721, -10.911887, -0.867721, -10.718985, 2.606568, -10.718985, -2.606568, 0.0, 0.0, 0.0, 0.0
+ },
+/* 17 th order */ {
+ -3.827174, 14.892159, -3.827174, -14.892159, -6.234581, 12.678120, -6.234581, -12.678120, -7.905450, 10.699145, -7.905450, -10.699145, -9.147588, 8.825998, -9.147588, -8.825998, -10.080296, 7.012010, -10.080296, -7.012010, -10.764132, 5.234075, -10.764132, -5.234075, -11.233439, 3.478542, -11.233439, -3.478542, -11.598530, 0.000000, -11.508076, 1.736203, -11.508076, -1.736203, 0.0, 0.0, 0.0
+ },
+/* 18 th order */ {
+ -3.911572, 15.850754, -3.911572, -15.850754, -6.390973, 13.610547, -6.390973, -13.610547, -8.127284, 11.613132, -8.127284, -11.613132, -9.433133, 9.725901, -9.433133, -9.725901, -10.430010, 7.900893, -10.430010, -7.900893, -11.180044, 6.114391, -11.180044, -6.114391, -11.718943, 4.352488, -11.718943, -4.352488, -12.068139, 2.605877, -12.068139, -2.605877, -12.239902, 0.867741, -12.239902, -0.867741, 0.0, 0.0
+ },
+/* 19 th order */ {
+ -3.992759, 16.810692, -3.992759, -16.810692, -6.541095, 14.544991, -6.541095, -14.544991, -8.339801, 12.529484, -8.339801, -12.529484, -9.706101, 10.628321, -9.706101, -10.628321, -10.763544, 8.792290, -10.763544, -8.792290, -11.575589, 6.997092, -11.575589, -6.997092, -12.179243, 5.228415, -12.179243, -5.228415, -12.597062, 3.477100, -12.597062, -3.477100, -12.923980, 0.000000, -12.842816, 1.736037, -12.842816, -1.736037, 0.0
+ },
+/* 20 th order */ {
+ -4.071019, 17.771869, -4.071019, -17.771869, -6.685527, 15.481306, -6.685527, -15.481306, -8.543895, 13.448046, -8.543895, -13.448046, -9.967765, 11.533112, -9.967765, -11.533112, -11.082571, 9.686112, -11.082571, -9.686112, -11.953103, 7.881991, -11.953103, -7.881991, -12.617294, 6.106632, -12.617294, -6.106632, -13.098755, 4.349634, -13.098755, -4.349634, -13.567377, 0.867486, -13.567377, -0.867486, -13.412693, 2.605660, -13.412693, -2.605660
+ }
+
+};
+#endif
diff --git a/qucs-activefilter/cauer.svg b/qucs-activefilter/cauer.svg
new file mode 100644
index 00000000..48308459
--- /dev/null
+++ b/qucs-activefilter/cauer.svg
@@ -0,0 +1,1595 @@
+
+
diff --git a/qucs-activefilter/filter.cpp b/qucs-activefilter/filter.cpp
new file mode 100644
index 00000000..32c7861d
--- /dev/null
+++ b/qucs-activefilter/filter.cpp
@@ -0,0 +1,561 @@
+/***************************************************************************
+ filter.cpp
+ ----------------
+ begin : Wed Apr 10 2014
+ copyright : (C) 2014 by Vadim Kuznetsov
+ email : ra3xdh@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include
+#endif
+
+#include "filter.h"
+#include "qf_poly.h"
+#include "bessel.h"
+
+Filter::Filter(Filter::FilterFunc ffunc_, Filter::FType type_, FilterParam par)
+{
+ ffunc = ffunc_;
+ ftype = type_;
+ Fc = par.Fc;
+ Fs = par.Fs;
+ Rp = par.Rp;
+ As = par.As;
+ Ap = par.Ap;
+ Kv = par.Kv;
+ if (ffunc==Filter::Bessel) {
+ order = par.order;
+ }
+}
+
+Filter::~Filter()
+{
+
+}
+
+void Filter::createSchematic(QString &s)
+{
+ switch (ftype) {
+ case Filter::HighPass : createHighPassSchematic(s);
+ break;
+ case Filter::LowPass : createLowPassSchematic(s);
+ break;
+ default: break;
+ }
+
+ /*QFile sch("filter.sch");
+ sch.open(QFile::WriteOnly);
+ QTextStream out(&sch);
+ out<\n";
+}
+
+void Filter::createLowPassSchematic(QString &s)
+{
+ s = "\n";
+}
+
+bool Filter::calcFilter()
+{
+ Sections.clear();
+ Poles.clear();
+ Zeros.clear();
+
+ switch (ffunc) {
+ case Filter::Chebyshev : calcChebyshev();
+ break;
+ case Filter::Butterworth : calcButterworth();
+ break;
+ case Filter::Cauer : calcCauer();
+ break;
+ case Filter::InvChebyshev : calcInvChebyshev();
+ break;
+ case Filter::Bessel : calcBessel();
+ break;
+ case Filter::User : calcUserTrFunc();
+ break;
+ default :
+ return false;
+ break;
+ }
+
+ if (Poles.isEmpty()) {
+ return false;
+ }
+
+ if (((ffunc==Filter::Cauer)||
+ (ffunc==Filter::InvChebyshev))
+ &&(Zeros.isEmpty())) {
+ return false;
+ }
+
+ switch (ftype) {
+ case Filter::LowPass : calcLowPass();
+ break;
+ case Filter::HighPass : calcHighPass();
+ break;
+ default: return false;
+ break;
+ }
+
+ bool res = checkRCL();
+
+ Nr = Nr1*(order/2);
+ Nc = Nc1*(order/2);
+ Nopamp = Nop1*order/2;
+ return res;
+}
+
+
+void Filter::calcHighPass()
+{
+
+}
+
+void Filter::calcLowPass()
+{
+
+}
+
+void Filter::calcFirstOrder()
+{
+ if (order%2 != 0) {
+
+ float R1, R2,R3;
+
+ int k = order/2 + 1;
+ float Wc = 2*M_PI*Fc;
+ float re = Poles.at(k-1).real();
+ //float im = Poles.at(k-1).imag();
+ //float C = re*re + im*im;
+ float C = -re;
+ float C1 = 10/Fc;
+
+ if (ftype==Filter::HighPass) {
+ R1 = 1.0*C/(Wc*C1);
+ } else {
+ R1 = 1.0/(Wc*C*C1);
+ }
+
+ qDebug()< zero;
+ foreach(zero,Zeros) {
+ lst< pole;
+ foreach(pole,Poles) {
+ lst<\n").arg(Nopamp+1).arg(270+dx);
+ s += QString("\n").arg(170+dx);
+ s += QString("\n").arg(220+dx);
+ s += QString("\n").arg(Nr+2).arg(220+dx).arg(stage.R2,0,'f',3);
+ s += QString("\n").arg(Nr+1).arg(170+dx).arg(stage.R1,0,'f',3);
+ s += QString("\n").arg(Nr+3).arg(310+dx).arg(stage.R3,0,'f',3);
+ s += QString("\n").arg(Nc+1).arg(100+dx).arg(C1,0,'f',3).arg(suf);
+}
+
+
+void Filter::createFirstOrderComponentsLPF(QString &s,RC_elements stage,int dx)
+{
+ QString suf;
+ float C1 = autoscaleCapacitor(stage.C1,suf);
+ s += QString("\n").arg(Nopamp+1).arg(270+dx);
+ s += QString("\n").arg(170+dx);
+ s += QString("\n").arg(220+dx);
+ s += QString("\n").arg(Nr+2).arg(220+dx).arg(stage.R2,0,'f',3);
+ s += QString("\n").arg(Nr+1).arg(100+dx).arg(stage.R1,0,'f',3);
+ s += QString("\n").arg(Nr+3).arg(310+dx).arg(stage.R3,0,'f',3);
+ s += QString("\n").arg(Nc+1).arg(170+dx).arg(C1,0,'f',3).arg(suf);
+}
+
+void Filter::createFirstOrderWires(QString &s, int dx, int y)
+{
+ s += QString("<%1 190 %2 190 \"\" 0 0 0 \"\">\n").arg(dx-20).arg(70+dx);
+ s += QString("<%1 190 %2 %3 \"\" 0 0 0 \"\">\n").arg(dx-20).arg(dx-20).arg(y);
+ s += QString("<%1 %2 %3 %4 \"\" 0 0 0 \"\">\n").arg(dx-20).arg(y).arg(dx-50).arg(y);
+
+ s += QString("<%1 190 %2 190 \"\" 0 0 0 \"\">\n").arg(130+dx).arg(170+dx);
+ s += QString("<%1 160 %2 160 \"out\" %3 130 39 \"\">\n").arg(310+dx).arg(360+dx).arg(380+dx);
+ s += QString("<%1 260 %2 260 \"\" 0 0 0 \"\">\n").arg(340+dx).arg(360+dx);
+ s += QString("<%1 160 %2 260 \"\" 0 0 0 \"\">\n").arg(360+dx).arg(360+dx);
+ s += QString("<%1 190 %2 210 \"\" 0 0 0 \"\">\n").arg(170+dx).arg(170+dx);
+ s += QString("<%1 140 %2 190 \"\" 0 0 0 \"\">\n").arg(170+dx).arg(170+dx);
+ s += QString("<%1 140 %2 140 \"\" 0 0 0 \"\">\n").arg(170+dx).arg(240+dx);
+ s += QString("<%1 180 %2 260 \"\" 0 0 0 \"\">\n").arg(220+dx).arg(220+dx);
+ s += QString("<%1 180 %2 180 \"\" 0 0 0 \"\">\n").arg(220+dx).arg(240+dx);
+ s += QString("<%1 260 %2 260 \"\" 0 0 0 \"\">\n").arg(220+dx).arg(280+dx);
+ s += QString("<%1 260 %2 310 \"\" 0 0 0 \"\">\n").arg(220+dx).arg(220+dx);
+}
+
+
+float Filter::autoscaleCapacitor(float C, QString &suffix)
+{
+ float C1 = C*1e-6;
+
+ if (C1>=1e-7) {
+ suffix = "uF";
+ C1 *= 1e6;
+ }
+
+ if ((C1<1e-7)&&(C1>=1e-8)) {
+ suffix = "nF";
+ C1 *= 1e9;
+ }
+
+ if (C1<1e-8) {
+ suffix = "pF";
+ C1 *= 1e12;
+ }
+ return C1;
+}
+
+bool Filter::checkRCL()
+{
+ RC_elements sec;
+ foreach (sec,Sections) {
+ if (std::isnan(sec.R1)||
+ std::isnan(sec.R2)||
+ std::isnan(sec.R3)||
+ std::isnan(sec.R4)||
+ std::isnan(sec.C1)||
+ std::isnan(sec.C2)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void Filter::calcChebyshev()
+{
+ float kf = std::max(Fs/Fc,Fc/Fs);
+ float eps=sqrt(pow(10,0.1*Rp)-1);
+
+ float N1 = acosh(sqrt((pow(10,0.1*As)-1)/(eps*eps)))/acosh(kf);
+ int N = ceil(N1);
+
+ float a = sinh((asinh(1/eps))/N);
+ float b = cosh((asinh(1/eps))/N);
+
+ Poles.clear();
+ Zeros.clear();
+
+ for (int k=1;k<=N;k++) {
+ float re = -1*a*sin(M_PI*(2*k-1)/(2*N));
+ float im = b*cos(M_PI*(2*k-1)/(2*N));
+ std::complex pol(re,im);
+ Poles.append(pol);
+ }
+
+ order = Poles.count();
+}
+
+void Filter::calcButterworth()
+{
+ float kf = std::min(Fc/Fs,Fs/Fc);
+
+ float C1=(pow(10,(0.1*Ap))-1)/(pow(10,(0.1*As))-1);
+ float J2=log10(C1)/(2*log10(kf));
+ int N2 = round(J2+1);
+
+ Poles.clear();
+ Zeros.clear();
+
+ for (int k=1;k<=N2;k++) {
+ float re =-1*sin(M_PI*(2*k-1)/(2*N2));
+ float im =cos(M_PI*(2*k-1)/(2*N2));
+ std::complex pol(re,im);
+ Poles.append(pol);
+ }
+
+ order = Poles.count();
+}
+
+void Filter::calcInvChebyshev() // Chebyshev Type-II filter
+{
+ Poles.clear();
+ Zeros.clear();
+
+ float kf = std::max(Fs/Fc,Fc/Fs);
+
+ order = ceil(acosh(sqrt(pow(10.0,0.1*As)-1.0))/acosh(kf));
+
+ float eps = 1.0/(sqrt(pow(10.0,0.1*As)-1.0));
+ float a = sinh((asinh(1.0/eps))/(order));
+ float b = cosh((asinh(1.0/eps))/(order));
+
+ for (int k=1;k<=order;k++) {
+ float im = 1.0/(cos(((2*k-1)*M_PI)/(2*order)));
+ Zeros.append(std::complex(0,im));
+ }
+
+ for (int k=1;k<=order;k++) {
+ float re = -1*a*sin(M_PI*(2*k-1)/(2*order));
+ float im = b*cos(M_PI*(2*k-1)/(2*order));
+ std::complex invpol(re,im); // inverse pole
+ std::complex pol;
+ pol = std::complex(1.0,0) / invpol; // pole
+ Poles.append(pol);
+ }
+
+}
+
+void Filter::cauerOrderEstim() // from Digital Filter Design Handbook page 102
+{
+ float k = std::min(Fc/Fs,Fs/Fc);
+ float kk = sqrt(sqrt(1.0-k*k));
+ float u = 0.5*(1.0-kk)/(1.0+kk);
+ float q = 150.0*pow(u,13) + 2.0*pow(u,9) + 2.0*pow(u,5) + u;
+ float dd = (pow(10.0,As/10.0)-1.0)/(pow(10.0,Rp/10.0)-1.0);
+ order = ceil(log10(16.0*dd)/log10(1.0/q));
+}
+
+void Filter::calcCauer() // from Digital Filter Designer's handbook p.103
+{
+ float P0;
+ //float H0;
+ float mu;
+ float aa[50],bb[50],cc[50];
+
+ cauerOrderEstim();
+ float k = Fc/Fs;
+ float kk = sqrt(sqrt(1.0-k*k));
+ float u = 0.5*(1.0-kk)/(1.0+kk);
+ float q = 150.0*pow(u,13) + 2.0*pow(u,9) + 2.0*pow(u,5) + u;
+ float numer = pow(10.0,Rp/20.0)+1.0;
+ float vv = log(numer/(pow(10.0,Rp/20.0)-1.0))/(2.0*order);
+ float sum = 0.0;
+ for (int m=0;m<5;m++) {
+ float term = pow(-1.0,m);
+ term = term*pow(q,m*(m+1));
+ term = term*sinh((2*m+1)*vv);
+ sum = sum +term;
+ }
+ numer = 2.0*sum*sqrt(sqrt(q));
+
+ sum=0.0;
+ for (int m=1;m<5;m++) {
+ float term = pow(-1.0,m);
+ term = term*pow(q,m*m);
+ term = term*cosh(2.0*m*vv);
+ sum += term;
+ }
+ float denom = 1.0+2.0*sum;
+ P0 = fabs(numer/denom);
+ float ww = 1.0+k*P0*P0;
+ ww = sqrt(ww*(1.0+P0*P0/k));
+ int r = (order-(order%2))/2;
+ //float numSecs = r;
+
+ for (int i=1;i<=r;i++) {
+ if ((order%2)!=0) {
+ mu = i;
+ } else {
+ mu = i-0.5;
+ }
+ sum = 0.0;
+ for(int m=0;m<5;m++) {
+ float term = pow(-1.0,m)*pow(q,m*(m+1));
+ term = term*sin((2*m+1)*M_PI*mu/order);
+ sum += term;
+ }
+ numer = 2.0*sum*sqrt(sqrt(q));
+
+ sum = 0.0;
+ for(int m=1;m<5;m++) {
+ float term = pow(-1.0,m)*pow(q,m*m);
+ term = term*cos(2.0*m*M_PI*mu/order);
+ sum += term;
+ }
+ denom = 1.0+2.0*sum;
+ float xx = numer/denom;
+ float yy = 1.0 - k*xx*xx;
+ yy = sqrt(yy*(1.0-(xx*xx/k)));
+ aa[i-1] = 1.0/(xx*xx);
+ denom = 1.0 + pow(P0*xx,2);
+ bb[i-1] = 2.0*P0*yy/denom;
+ denom = pow(denom,2);
+ numer = pow(P0*yy,2)+pow(xx*ww,2);
+ cc[i-1] = numer/denom;
+ }
+
+ if (order%2!=0) {
+ cc[order-1] = P0; // first order section
+ bb[order-1] = 0;
+ }
+
+ Zeros.clear();
+ Poles.clear();
+ for (int i=0;i(0,im));
+ float re = -0.5*bb[i];
+ im = 0.5*sqrt(-1.0*bb[i]*bb[i]+4*cc[i]);
+ Poles.append(std::complex(re,im));
+ }
+
+ if (order%2!=0) {
+ Poles.append(std::complex(-cc[order-1],0.0));
+ }
+
+ for (int i=r-1;i>=0;i--) {
+ float im = sqrt(aa[i]);
+ Zeros.append(std::complex(0,-im));
+ float re = -0.5*bb[i];
+ im = 0.5*sqrt(-1.0*bb[i]*bb[i]+4*cc[i]);
+ Poles.append(std::complex(re,-im));
+ }
+}
+
+void Filter::calcBessel()
+{
+ Poles.clear();
+ Zeros.clear();
+
+ if (order<=0) return;
+
+ for (int i=0;i(BesselPoles[order-1][2*i],BesselPoles[order-1][2*i+1]));
+ }
+
+ reformPolesZeros();
+}
+
+void Filter::calcUserTrFunc()
+{
+ if ((!vec_A.isEmpty())&&(!vec_B.isEmpty())) {
+ long double *a = vec_A.data();
+ long double *b = vec_B.data();
+
+ int a_order = vec_A.count() - 1;
+ int b_order = vec_B.count() - 1;
+
+ order = std::max(a_order,b_order);
+
+ qf_poly Numenator(b_order,b);
+ qf_poly Denomenator(a_order,a);
+
+ Numenator.to_roots();
+ Denomenator.to_roots();
+
+ Numenator.disp_c();
+ Denomenator.disp_c();
+
+ Numenator.roots_to_complex(Zeros);
+ Denomenator.roots_to_complex(Poles);
+
+ reformPolesZeros();
+ }
+
+}
+
+void Filter::reformPolesZeros()
+{
+ int Np = Poles.count();
+ int Nz = Zeros.count();
+
+ for (int i=0;i tmp;
+ tmp = Poles[i];
+ Poles[i]=Poles[Np-1-i];
+ Poles[Np-1-i]=tmp;
+ }
+ }
+
+ for (int i=0;i tmp;
+ tmp = Poles[i];
+ Poles[i]=Poles[Nz-1-i];
+ Poles[Nz-1-i]=tmp;
+ }
+ }
+}
+
+void Filter::set_TrFunc(QVector a, QVector b)
+{
+ vec_A = a;
+ vec_B = b;
+}
diff --git a/qucs-activefilter/filter.h b/qucs-activefilter/filter.h
new file mode 100644
index 00000000..2f8db423
--- /dev/null
+++ b/qucs-activefilter/filter.h
@@ -0,0 +1,108 @@
+/***************************************************************************
+ filter.h
+ ----------------
+ begin : Wed Apr 10 2014
+ copyright : (C) 2014 by Vadim Kuznetsov
+ email : ra3xdh@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef FILTER_H
+#define FILTER_H
+
+#include
+#include
+#include
+
+struct RC_elements {
+ int N;
+ float R1;
+ float R2;
+ float R3;
+ float R4;
+ float R5;
+ float C1;
+ float C2;
+};
+
+struct FilterParam {
+ float Ap;
+ float As;
+ float Fc;
+ float Fs;
+ float Rp;
+ float Kv;
+ int order;
+};
+
+class Filter
+{
+
+public:
+ enum FType {HighPass, LowPass, BandPass, BandStop, NoFilter};
+ enum FilterFunc {Butterworth, Chebyshev, Cauer, Bessel, InvChebyshev, NoFunc, User};
+
+private:
+ void cauerOrderEstim();
+ void reformPolesZeros();
+
+protected:
+ QVector< std::complex > Poles;
+ QVector< std::complex > Zeros;
+ QVector vec_B; // Transfer function numenator
+ QVector vec_A; // and denominator
+ QVector Sections;
+
+ Filter::FType ftype;
+ Filter::FilterFunc ffunc;
+ int order;
+ float Fc,Kv,Fs,Ap,As,Rp;
+ int Nr,Nc,Nopamp; // total number of R,C, opamp
+
+ int Nr1,Nc1,Nop1; // number of R,C, opamp per stage
+
+ void calcButterworth();
+ void calcChebyshev();
+ void calcInvChebyshev();
+ void calcCauer();
+ void calcBessel();
+ void calcUserTrFunc();
+ bool checkRCL(); // Checks RCL values. Are one of them NaN or not?
+
+ void createFirstOrderComponentsHPF(QString &s,RC_elements stage, int dx);
+ void createFirstOrderComponentsLPF(QString &s,RC_elements stage, int dx);
+ void createFirstOrderWires(QString &s, int dx, int y);
+ float autoscaleCapacitor(float C, QString &suffix);
+ virtual void calcHighPass();
+ virtual void calcLowPass();
+ virtual void createHighPassSchematic(QString &s);
+ virtual void createLowPassSchematic(QString &s);
+
+public:
+
+
+ Filter(Filter::FilterFunc ffunc_, Filter::FType type_, FilterParam par);
+ virtual ~Filter();
+
+ void calcFirstOrder();
+
+ void createPartList(QStringList &lst);
+ void createPolesZerosList(QStringList &lst);
+
+ virtual void createSchematic(QString &s);
+
+ virtual bool calcFilter();
+
+ void set_TrFunc(QVector a, QVector b);
+
+};
+
+#endif // FILTER_H
diff --git a/qucs-activefilter/high-pass.svg b/qucs-activefilter/high-pass.svg
new file mode 100644
index 00000000..342637b2
--- /dev/null
+++ b/qucs-activefilter/high-pass.svg
@@ -0,0 +1,393 @@
+
+
+
+
diff --git a/qucs-activefilter/main.cpp b/qucs-activefilter/main.cpp
new file mode 100644
index 00000000..4da040be
--- /dev/null
+++ b/qucs-activefilter/main.cpp
@@ -0,0 +1,28 @@
+/***************************************************************************
+ main.cpp
+ ----------------
+ begin : Wed Apr 10 2014
+ copyright : (C) 2014 by Vadim Kuznetsov
+ email : ra3xdh@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#include
+#include "qucsactivefilter.h"
+
+int main(int argc, char *argv[])
+{
+ QApplication a(argc, argv);
+ QucsActiveFilter w;
+ w.show();
+
+ return a.exec();
+}
diff --git a/qucs-activefilter/mfb-highpass.svg b/qucs-activefilter/mfb-highpass.svg
new file mode 100644
index 00000000..a7926fe0
--- /dev/null
+++ b/qucs-activefilter/mfb-highpass.svg
@@ -0,0 +1,1050 @@
+
+
diff --git a/qucs-activefilter/mfb-lowpass.svg b/qucs-activefilter/mfb-lowpass.svg
new file mode 100644
index 00000000..9f67fa0b
--- /dev/null
+++ b/qucs-activefilter/mfb-lowpass.svg
@@ -0,0 +1,1053 @@
+
+
diff --git a/qucs-activefilter/mfbfilter.cpp b/qucs-activefilter/mfbfilter.cpp
new file mode 100644
index 00000000..c11fb0d3
--- /dev/null
+++ b/qucs-activefilter/mfbfilter.cpp
@@ -0,0 +1,264 @@
+/***************************************************************************
+ mfbfilter.cpp
+ ----------------
+ begin : Wed Apr 10 2014
+ copyright : (C) 2014 by Vadim Kuznetsov
+ email : ra3xdh@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include
+#endif
+
+
+#include "mfbfilter.h"
+
+MFBfilter::MFBfilter(Filter::FilterFunc ffunc_, Filter::FType type_, FilterParam par)
+ : Filter(ffunc_,type_,par)
+{
+ switch (ftype) {
+ case Filter::LowPass :
+ Nr1=3;
+ Nc1=2;
+ break;
+ case Filter::HighPass :
+ Nr1=2;
+ Nc1=3;
+ break;
+ default:
+ break;
+ }
+
+ //Nr1 = 3;
+ //Nc1 = 2;
+ Nop1 = 1;
+}
+
+void MFBfilter::createLowPassSchematic(QString &s)
+{
+ //int const N_R=4; // number of resisitors in 2-order Sallen-Key stage
+ //int const N_C=2; // number of capacitors in 2-order Sallen-Key stage
+ RC_elements stage;
+ int dx = 0;
+ int N2ord = order/2; // number of 2-nd order stages
+ int N1stOrd = order%2; // number of 1-st order stages
+
+ s += "\n";
+ s += "\n";
+ s += QString("<.AC AC1 1 300 440 0 61 0 0 \"lin\" 1 \"1 Hz\" 1 \"%1 kHz\" 1 \"501\" 1 \"no\" 0>\n").arg((10.0*Fc)/1000.0);
+ s += "<.DC DC1 1 60 440 0 61 0 0 \"26.85\" 0 \"0.001\" 0 \"1 pA\" 0 \"1 uV\" 0 \"no\" 0 \"150\" 0 \"no\" 0 \"none\" 0 \"CroutLU\" 0>\n";
+ s += "\n";
+ s += QString("\n").arg(70+dx);
+ s += QString("\n").arg(70+dx);
+ for (int i=1; i<=N2ord; i++) {
+ stage = Sections.at(i-1);
+ qDebug()<\n").arg(200+dx);
+ s += QString("\n").arg(360+dx);
+ s += QString("\n").arg(1+(i-1)*Nop1).arg(390+dx);
+ s += QString("\n").arg(2+(i-1)*Nc1).arg(200+dx).arg(C2,0,'f',3).arg(suffix2);
+ s += QString("\n").arg(1+(i-1)*Nc1).arg(320+dx).arg(C1,0,'f',3).arg(suffix1);
+ s += QString("\n").arg(1+(i-1)*Nr1).arg(200+dx).arg(stage.R1,0,'f',3);
+ s += QString("\n").arg(2+(i-1)*Nr1).arg(150+dx).arg(stage.R2,0,'f',3);
+ s += QString("\n").arg(3+(i-1)*Nr1).arg(250+dx).arg(stage.R3,0,'f',3);
+ dx += 510;
+ }
+
+ if (N1stOrd!=0) {
+ createFirstOrderComponentsLPF(s,Sections.last(),dx+10);
+ }
+
+ s += "\n";
+ s += "\n";
+ dx = 0;
+ s += "<70 250 120 250 \"in\" 120 220 22 \"\">\n";
+ s += "<70 250 70 300 \"\" 0 0 0 \"\">\n";
+ for (int i=1; i<=N2ord; i++) {
+ if (i!=1) {
+ s += QString("<%1 250 %2 270 \"\" 0 0 0 \"\">\n").arg(120+dx).arg(120+dx);
+ s += QString("<%1 270 %2 270 \"\" 0 0 0 \"\">\n").arg(dx-40).arg(120+dx);
+ }
+ s += QString("<%1 250 %2 250 \"\" 0 0 0 \"\">\n").arg(180+dx).arg(200+dx);
+ s += QString("<%1 250 %2 250 \"\" 0 0 0 \"\">\n").arg(200+dx).arg(220+dx);
+ s += QString("<%1 210 %2 250 \"\" 0 0 0 \"\">\n").arg(200+dx).arg(200+dx);
+ s += QString("<%1 250 %2 320 \"\" 0 0 0 \"\">\n").arg(200+dx).arg(200+dx);
+ s += QString("<%1 290 %2 350 \"\" 0 0 0 \"\">\n").arg(360+dx).arg(360+dx);
+ s += QString("<%1 130 %2 150 \"\" 0 0 0 \"\">\n").arg(200+dx).arg(200+dx);
+ s += QString("<%1 130 %2 130 \"\" 0 0 0 \"\">\n").arg(200+dx).arg(320+dx);
+ s += QString("<%1 130 %2 150 \"\" 0 0 0 \"\">\n").arg(320+dx).arg(320+dx);
+ s += QString("<%1 250 %2 250 \"\" 0 0 0 \"\">\n").arg(280+dx).arg(320+dx);
+ s += QString("<%1 250 %2 250 \"\" 0 0 0 \"\">\n").arg(320+dx).arg(360+dx);
+ s += QString("<%1 210 %2 250 \"\" 0 0 0 \"\">\n").arg(320+dx).arg(320+dx);
+ s += QString("<%1 130 %2 130 \"\" 0 0 0 \"\">\n").arg(320+dx).arg(470+dx);
+ s += QString("<%1 270 %2 270 \"\" 0 0 0 \"\">\n").arg(430+dx).arg(470+dx);
+ if ((2*i)==order) {
+ s += QString("<%1 130 %2 270 \"out\" %3 170 70 \"\">\n").arg(470+dx).arg(470+dx).arg(500+dx);
+ } else {
+ s += QString("<%1 130 %2 270 \"\" 0 0 0 \"\">\n").arg(470+dx).arg(470+dx);
+ }
+ dx += 510;
+ }
+
+ if (N1stOrd!=0) {
+ createFirstOrderWires(s,dx+10,270);
+ }
+
+ s += "\n";
+}
+
+void MFBfilter::createHighPassSchematic(QString &s)
+{
+ RC_elements stage;
+ int dx = 0;
+ int N2ord = order/2; // number of 2-nd order stages
+ int N1stOrd = order%2; // number of 1-st order stages
+
+ s += "\n";
+ s += "\n";
+ s += QString("<.AC AC1 1 300 440 0 61 0 0 \"lin\" 1 \"1 Hz\" 1 \"%1 kHz\" 1 \"501\" 1 \"no\" 0>\n").arg((10.0*Fc)/1000.0);
+ s += "<.DC DC1 1 60 440 0 61 0 0 \"26.85\" 0 \"0.001\" 0 \"1 pA\" 0 \"1 uV\" 0 \"no\" 0 \"150\" 0 \"no\" 0 \"none\" 0 \"CroutLU\" 0>\n";
+ s += "\n";
+ s += QString("\n").arg(70+dx);
+ s += QString("\n").arg(70+dx);
+ for (int i=1; i<=N2ord; i++) {
+ stage = Sections.at(i-1);
+ qDebug()<\n").arg(200+dx);
+ s += QString("\n").arg(360+dx);
+ s += QString("\n").arg(1+(i-1)*Nop1).arg(390+dx);
+ s += QString("\n").arg(1+(i-1)*Nr1).arg(200+dx).arg(stage.R1,0,'f',3);
+ s += QString("\n").arg(2+(i-1)*Nr1).arg(320+dx).arg(stage.R2,0,'f',3);
+ s += QString("\n").arg(1+(i-1)*Nc1).arg(200+dx).arg(C1,0,'f',3).arg(suffix1);
+ s += QString("\n").arg(2+(i-1)*Nc1).arg(150+dx).arg(C2,0,'f',3).arg(suffix2);
+ s += QString("\n").arg(3+(i-1)*Nc1).arg(250+dx).arg(C1,0,'f',3).arg(suffix1);
+ dx += 510;
+ }
+
+ if (N1stOrd!=0) {
+ createFirstOrderComponentsHPF(s,Sections.last(),dx+10);
+ }
+
+ s += "\n";
+ s += "\n";
+ dx = 0;
+ s += "<70 250 120 250 \"in\" 120 220 22 \"\">\n";
+ s += "<70 250 70 300 \"\" 0 0 0 \"\">\n";
+ for (int i=1; i<=N2ord; i++) {
+ if (i!=1) {
+ s += QString("<%1 250 %2 270 \"\" 0 0 0 \"\">\n").arg(120+dx).arg(120+dx);
+ s += QString("<%1 270 %2 270 \"\" 0 0 0 \"\">\n").arg(dx-40).arg(120+dx);
+ }
+ s += QString("<%1 250 %2 250 \"\" 0 0 0 \"\">\n").arg(180+dx).arg(200+dx);
+ s += QString("<%1 250 %2 250 \"\" 0 0 0 \"\">\n").arg(200+dx).arg(220+dx);
+ s += QString("<%1 210 %2 250 \"\" 0 0 0 \"\">\n").arg(200+dx).arg(200+dx);
+ s += QString("<%1 250 %2 320 \"\" 0 0 0 \"\">\n").arg(200+dx).arg(200+dx);
+ s += QString("<%1 290 %2 350 \"\" 0 0 0 \"\">\n").arg(360+dx).arg(360+dx);
+ s += QString("<%1 130 %2 150 \"\" 0 0 0 \"\">\n").arg(200+dx).arg(200+dx);
+ s += QString("<%1 130 %2 130 \"\" 0 0 0 \"\">\n").arg(200+dx).arg(320+dx);
+ s += QString("<%1 130 %2 150 \"\" 0 0 0 \"\">\n").arg(320+dx).arg(320+dx);
+ s += QString("<%1 250 %2 250 \"\" 0 0 0 \"\">\n").arg(280+dx).arg(320+dx);
+ s += QString("<%1 250 %2 250 \"\" 0 0 0 \"\">\n").arg(320+dx).arg(360+dx);
+ s += QString("<%1 210 %2 250 \"\" 0 0 0 \"\">\n").arg(320+dx).arg(320+dx);
+ s += QString("<%1 130 %2 130 \"\" 0 0 0 \"\">\n").arg(320+dx).arg(470+dx);
+ s += QString("<%1 270 %2 270 \"\" 0 0 0 \"\">\n").arg(430+dx).arg(470+dx);
+ if ((2*i)==order) {
+ s += QString("<%1 130 %2 270 \"out\" %3 170 70 \"\">\n").arg(470+dx).arg(470+dx).arg(500+dx);
+ } else {
+ s += QString("<%1 130 %2 270 \"\" 0 0 0 \"\">\n").arg(470+dx).arg(470+dx);
+ }
+ dx += 510;
+ }
+
+ if (N1stOrd!=0) {
+ createFirstOrderWires(s,dx+10,270);
+ }
+
+ s += "\n";
+}
+
+void MFBfilter::calcHighPass()
+{
+ float R1,R2,C1,C2;
+ float Wc = 2*M_PI*Fc;
+
+ for (int k=1; k <= order/2; k++) {
+ float re = Poles.at(k-1).real();
+ float im = Poles.at(k-1).imag();
+ float B = -2.0*re;
+ float C = re*re + im*im;
+
+ qDebug()<calcFirstOrder();
+
+}
+
+void MFBfilter::calcLowPass()
+{
+ float R1,R2,R3,C1,C2;
+ float Wc = 2*M_PI*Fc;
+
+ for (int k=1; k <= order/2; k++) {
+ float re = Poles.at(k-1).real();
+ float im = Poles.at(k-1).imag();
+ float B = -2.0*re;
+ float C = re*re + im*im;
+
+ qDebug()<calcFirstOrder();
+}
diff --git a/qucs-activefilter/mfbfilter.h b/qucs-activefilter/mfbfilter.h
new file mode 100644
index 00000000..13b03a4f
--- /dev/null
+++ b/qucs-activefilter/mfbfilter.h
@@ -0,0 +1,38 @@
+/***************************************************************************
+ mfbfilter.h
+ ----------------
+ begin : Wed Apr 10 2014
+ copyright : (C) 2014 by Vadim Kuznetsov
+ email : ra3xdh@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef MFBFILTER_H
+#define MFBFILTER_H
+
+#include
+#include
+#include "filter.h"
+
+class MFBfilter : public Filter
+{
+protected:
+ void calcHighPass();
+ void calcLowPass();
+ void createHighPassSchematic(QString &s);
+ void createLowPassSchematic(QString &s);
+
+public:
+ MFBfilter(Filter::FilterFunc ffunc_, Filter::FType type_, FilterParam par);
+
+};
+
+#endif // MFBFILTER_H
diff --git a/qucs-activefilter/qf_matrix.h b/qucs-activefilter/qf_matrix.h
new file mode 100644
index 00000000..0b4a3f87
--- /dev/null
+++ b/qucs-activefilter/qf_matrix.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ qf_matrix.h
+ ----------------
+ begin : Mon Jan 02 2006
+ copyright : (C) 2006 by Stefan Jahn
+ email : stefan@lkcc.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef _QF_MATRIX_H
+#define _QF_MATRIX_H
+
+class qf_matrix
+{
+ public:
+ // constructor
+ qf_matrix (unsigned int d) {
+ data = (qf_double_t *) calloc (d * d, sizeof (qf_double_t));
+ n = d;
+ }
+
+ // destructor
+ ~qf_matrix () {
+ free (data);
+ }
+
+ // accessor operators
+ qf_double_t operator () (int r, int c) const {
+ return data[r * n + c];
+ }
+ qf_double_t & operator () (int r, int c) {
+ return data[r * n + c];
+ }
+
+ // size of matrix
+ unsigned int n;
+
+ private:
+ qf_double_t * data;
+};
+
+#endif // _QF_MATRIX_H
diff --git a/qucs-activefilter/qf_poly.cpp b/qucs-activefilter/qf_poly.cpp
new file mode 100644
index 00000000..80705da0
--- /dev/null
+++ b/qucs-activefilter/qf_poly.cpp
@@ -0,0 +1,1580 @@
+/***************************************************************************
+ qf_poly.cpp
+ ----------------
+ begin : Mon Jan 02 2006
+ copyright : (C) 2006 by Vincent Habchi, F5RCS
+ email : 10.50@free.fr
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+// Class for polynoms with real coefficients (R[X])
+// Basic operations are covered
+// It includes also an algorithm to find all the roots of a real
+// polynom.
+
+#include
+#include
+#include
+#include
+
+#undef _QF_POLY_DEBUG
+
+#include "qf_poly.h"
+
+// A polynom is essentially a structure with an order (max. index)
+// and a table storing coefficients
+qf_poly::qf_poly () :
+ rep (NONE), d (0), krts (0), p (NULL), rts (NULL) {
+}
+
+// Creates default polynoms
+qf_poly::qf_poly (unsigned o) :
+ rep (NONE), d (o), krts (0), p (NULL), rts (NULL) {
+}
+
+// This function creates irreductible real polynoms
+// That is either constants, monoms, or binoms
+qf_poly::qf_poly (qf_double_t a, qf_double_t b, qf_double_t c, unsigned deg) {
+
+#ifdef _QF_POLY_DEBUG
+ std::cout << "qf_poly (ax^2+bx+c), a = " << a << ", b = " << b
+ << ", c = " << c << ", d = " << deg << "\n";
+#endif
+
+ // Pathological cases
+ if ((deg == 2) && (a == 0)) {
+ deg = 1;
+ a = b;
+ b = c;
+ }
+ if ((deg == 1) && (a == 0)) {
+ deg = 0;
+ a = b;
+ }
+
+ // Proceed with normal cases
+ switch (deg) {
+ case 0:
+ // Constant
+ d = 0;
+ p = new qf_double_t[1];
+ p[0] = a;
+ rts = NULL; // no root (or an infinite #of them)
+ krts = a;
+ rep = BOTH;
+ break;
+ case 1:
+ // (aX + b)
+ d = 1;
+ p = new qf_double_t[2];
+ p[0] = b;
+ p[1] = a;
+ rts = new qf_double_t[2];
+ rts[0] = ROUND_ROOT (-b / a);
+ rts[1] = 0;
+ krts = a;
+ rep = BOTH;
+ break;
+ default:
+ // Polynom of d 2 (aX^2 + bX + c)
+ if (deg > 2)
+ std::cout << "Warning: qf_poly called with deg > 2.\n";
+ d = 2;
+ p = new qf_double_t[3];
+ p[0] = c;
+ p[1] = b;
+ p[2] = a;
+ rts = new qf_double_t[4];
+ krts = a;
+ qf_double_t dlt = (b * b - 4 * a * c);
+ if (dlt == 0) {
+ // Double root (should not occur)
+ rts[0] = rts[2] = ROUND_ROOT (-b / (2 * a));
+ rts[1] = rts[3] = 0;
+ } else if (dlt > 0) {
+ // Two real roots (should not occur)
+ rts[1] = rts[3] = 0;
+ rts[0] = ROUND_ROOT ((-b + sqrt (dlt)) / (2 * a));
+ rts[2] = ROUND_ROOT (-(b + sqrt (dlt)) / (2 * a));
+ } else {
+ // Two conjugate complex root (normal case)
+ rts[0] = rts[2] = ROUND_ROOT (-b / (2 * a));
+ rts[1] = ROUND_ROOT (sqrt (-dlt) / (2 * a));
+ rts[3] = -rts[1];
+ }
+ rep = BOTH;
+ break;
+ }
+
+#ifdef _QF_POLY_DEBUG
+ std::cout << "qf_poly ax^2+bx+c: ";
+ this->disp ("prod");
+#endif
+}
+
+// Creates a polynom and instantiates it out of a constant table
+qf_poly::qf_poly (int o, const qf_double_t coef[]) :
+ rep (COEFF), d (o), krts (0), rts (NULL) {
+
+ p = new qf_double_t[o + 1];
+ for (int i = o; i >= 0; i--) p[i] = coef[o - i];
+
+#ifdef _QF_POLY_DEBUG
+ std::cout << "qf_poly coeffs: ";
+ this->disp ("P");
+#endif
+ return;
+}
+
+// Creates a polynom out of its roots and a constant factor
+// The roots are complex numbers
+// If a root is complex, then its conjugate is also a root
+// since the coefficients are real.
+qf_poly::qf_poly (int o, qf_double_t k, const qf_double_t r[]) :
+ rep (ROOTS), d (o), p (NULL) {
+
+ rts = new qf_double_t[2 * o];
+ for (int i = 0; i < 2 * o; i++)
+ rts[i] = ROUND_ROOT (r[i]);
+ krts = k;
+
+#ifdef _QF_POLY_DEBUG
+ std::cout << "qf_poly (roots): ";
+ this->disp ("P");
+#endif
+ return;
+}
+
+// Copy constructor
+qf_poly::qf_poly (const qf_poly & P) :
+ rep (P.rep), d (P.d), krts (0), p (NULL), rts (NULL) {
+
+ if (rep & COEFF) {
+ p = new qf_double_t[d + 1];
+ memcpy (p, P.p, sizeof (qf_double_t) * (d + 1));
+ }
+ if (rep & ROOTS) {
+ rts = new qf_double_t[2 * d];
+ memcpy (rts, P.rts, sizeof (qf_double_t) * 2 * d);
+ krts = P.krts;
+ }
+}
+
+// Assignment operator
+// Identical to previous
+qf_poly & qf_poly::operator = (const qf_poly & P) {
+ if (&P == this) // Self copy, nothing to do
+ return (*this);
+
+ d = P.d;
+ rep = P.rep;
+
+ if (p != NULL) delete[] p;
+ if (rts != NULL) delete[] rts;
+ p = rts = NULL;
+ krts = 0;
+
+ if (rep & COEFF) {
+ p = new qf_double_t[d + 1];
+ memcpy (p, P.p, sizeof (qf_double_t) * (d + 1));
+ }
+ if (rep & ROOTS) {
+ rts = new qf_double_t[2 * d];
+ memcpy (rts, P.rts, sizeof (qf_double_t) * (2 * d));
+ krts = P.krts;
+ }
+ return (*this);
+}
+
+// Garbage bin
+qf_poly::~qf_poly () {
+ if (p != NULL) delete[] p;
+ if (rts != NULL) delete[] rts;
+}
+
+// Basic functions.
+
+// Access to the element of nth order
+// [] overload
+qf_double_t & qf_poly::operator [] (int i) {
+ if (rep == NONE) {
+ std::cout << "qf_poly::[] used on a NONE polynom.\n";
+ exit (-1);
+ }
+ if (rep & COEFF)
+ return p[i];
+ return rts[i];
+}
+
+// Returns d (order) of polynom
+unsigned qf_poly::deg () {
+ return d;
+}
+
+qf_double_t qf_poly::k () {
+ if (rep == NONE) {
+ std::cout << "qf_poly::k () used on a NONE polynom.\n";
+ exit (-1);
+ }
+ if (rep & ROOTS)
+ return krts;
+ return p[d];
+}
+
+// Simplifies a polynom
+// This function looks for the highest non-zero term and sets
+// d accordingly, so that we do not perform useless operations on 0s
+// Note that the unused 0s are not freed. We cannot do that at that
+// time without copying, which is a ** overhead
+// Useful after additions
+void qf_poly::spl () {
+ int i = d;
+
+ if (rep == NONE) {
+ std::cout << "qf_poly::spl () used on a NONE polynom.\n";
+ exit (-1);
+ }
+
+ if (d == 0)
+ return;
+
+ if (rep == ROOTS)
+ return;
+
+ // We scan from highest to lowest order
+ while (i > 0) {
+ if (p[i] == 0)
+ i--;
+ else
+ break;
+ }
+ d = i;
+
+ return;
+}
+
+// Arithmetical operations
+
+// Negates (Unary minus : P -> -P)
+qf_poly qf_poly::operator - (void) {
+ if (rep == NONE) {
+ std::cout << "qf_poly::unary - used on a NONE polynom.\n";
+ exit (-1);
+ }
+
+ qf_poly R (d);
+
+ if (rep & COEFF) {
+ R.p = new qf_double_t[d + 1];
+ for (unsigned i = 0; i <= d; i++)
+ R.p[i] = -p[i];
+ }
+ if (rep & ROOTS) {
+ R.rts = new qf_double_t[2 * d];
+ memcpy (R.rts, rts, sizeof (qf_double_t) * 2 * d);
+ R.krts = -krts;
+ }
+
+ R.rep = rep;
+ return R;
+}
+
+// Addition
+qf_poly operator + (qf_poly P, qf_poly Q) {
+ if ((Q.rep == NONE) || (P.rep == NONE)) {
+ std::cout << "qf_poly::+ used on a NONE polynom.\n";
+ exit (-1);
+ }
+
+ if (Q.d >= P.d) {
+ qf_poly R (Q);
+ return R += P;
+ }
+ else {
+ qf_poly R (P);
+ return R += Q;
+ }
+}
+
+// Self-Addition
+qf_poly qf_poly::operator += (qf_poly P) {
+ if ((rep == NONE) || (P.rep == NONE)) {
+ std::cout << "qf_poly::+= used on a NONE polynom.\n";
+ exit (-1);
+ }
+
+ // We cannot add two polynoms if one of them is under the ROOTS form
+ if (rep == ROOTS)
+ to_coeff ();
+
+ // We add coefficients, not roots!
+ if (P.rep == ROOTS)
+ P.to_coeff ();
+
+ if (d >= P.d) {
+ for (unsigned i = 0; i <= P.d; i++)
+ p[i] += P.p[i];
+ }
+ else {
+ qf_double_t * pp = new qf_double_t[P.d];
+ memcpy (pp, P.p, sizeof (qf_double_t) * P.d);
+ for (unsigned i = 0; i <= d; i++)
+ pp[i] += p[i];
+ delete[] p;
+ p = pp;
+ }
+
+ if (rep & ROOTS) {
+ rep = COEFF; // We must recompute roots if needed
+ delete[] rts;
+ rts = NULL;
+ krts = 0;
+ }
+ spl (); // Simplifies
+ return (*this);
+}
+
+// Substraction
+qf_poly operator - (qf_poly P, qf_poly Q) {
+ if ((P.rep == NONE) || (Q.rep == NONE)) {
+ std::cout << "qf_poly::- used on a NONE polynom.\n";
+ exit (-1);
+ }
+
+ if (P.d >= Q.d) {
+ qf_poly R (P);
+ return R -= Q;
+ }
+ else {
+ qf_poly R (Q);
+ return R -= P;
+ }
+}
+
+// Self-Substraction
+qf_poly qf_poly::operator -= (qf_poly P) {
+ if ((rep == NONE) || (P.rep == NONE)) {
+ std::cout << "qf_poly::-= used on a NONE polynom.\n";
+ exit (-1);
+ }
+
+ if (rep == ROOTS)
+ to_coeff ();
+
+ if (P.rep == ROOTS)
+ P.to_coeff ();
+
+ if (d >= P.d) {
+ for (unsigned i = 0; i <= P.d; i++)
+ p[i] -= P.p[i];
+ }
+ else {
+ qf_double_t * pp = new qf_double_t[P.d + 1];
+ memcpy (pp, P.p, sizeof (qf_double_t) * (P.d + 1));
+ for (unsigned i = 0; i <= P.d; i++)
+ if (i <= d)
+ pp[i] = p[i] - pp[i];
+ else
+ pp[i] = -pp[i];
+ delete[] p;
+ p = pp;
+ }
+
+ if (rep & ROOTS) {
+ rep = COEFF; // We must recompute roots if needed
+ delete[] rts;
+ rts = NULL;
+ krts = 0;
+ }
+ spl (); // Simplifies
+ return (*this);
+}
+
+// Multiplication of two polynoms
+qf_poly operator * (qf_poly P, qf_poly Q) {
+ if ((P.rep == NONE) || (Q.rep == NONE)) {
+ std::cout << "qf_poly::* used on a NONE polynom.\n";
+ exit (-1);
+ }
+
+ qf_poly R (P);
+ R *= Q;
+ return R;
+}
+
+// Multiplication with a scalar
+qf_poly operator * (qf_poly P, const qf_double_t m) {
+ if (P.rep == NONE) {
+ std::cout << "qf_poly::* (scalar) used on a NONE polynom.\n";
+ exit (-1);
+ }
+
+ qf_poly R (P);
+ R *= m;
+ return R;
+}
+
+// Self-Multiply
+qf_poly qf_poly::operator *= (qf_poly P) {
+ if ((rep == NONE) || (P.rep == NONE)) {
+ std::cout << "qf_poly::*= () used on a NONE polynom.\n";
+ exit (-1);
+ }
+
+ // Just a constant to multiply
+ if (P.d < 1) {
+ if (P.rep & COEFF)
+ return ((*this) *= P.p[0]);
+ else
+ return ((*this) *= P.krts);
+ }
+
+ // Resizes the coefficient list
+ if (rep & COEFF) {
+ if (!(P.rep & COEFF)) P.to_coeff ();
+ qf_double_t * q = new qf_double_t[d + P.d + 1];
+ memset (q, 0, sizeof (qf_double_t) * (d + P.d + 1));
+ for (unsigned i = 0; i <= d; i++)
+ for (unsigned j = 0; j <= P.d; j++)
+ q[i + j] += p[i] * P.p[j];
+ delete[] p;
+ p = q;
+ }
+
+ // The roots are the concatenation of the roots of both polynoms
+ if (rep & ROOTS) {
+ if (!(P.rep & ROOTS)) P.to_roots ();
+ qf_double_t * rtsp = new qf_double_t[2 * (d + P.d)];
+ memcpy (rtsp, rts, sizeof (qf_double_t) * 2 * d);
+ memcpy (&rtsp[2 * d], P.rts, sizeof (qf_double_t) * 2 * P.d);
+ delete[] rts;
+ rts = rtsp;
+ krts *= P.krts;
+ }
+
+ d += P.d;
+ return (*this);
+}
+
+// Self-Scalar-Multiply
+qf_poly qf_poly::operator *= (const qf_double_t m) {
+ if (rep == NONE) {
+ std::cout << "qf_poly::*= (scalar) used on a NONE polynom.\n";
+ exit (-1);
+ }
+
+ if (m == 0) {
+ krts = d = 0;
+ delete[] rts;
+ delete[] p;
+ rts = p = NULL;
+ rep = COEFF;
+ return (*this);
+ }
+
+ if (m == 1)
+ return (*this);
+
+ if (rep & COEFF)
+ for (unsigned i = 0; i <= d; i++)
+ p[i] *= m;
+
+ if (rep & ROOTS)
+ krts *= m;
+
+ return (*this);
+}
+
+// Test
+bool qf_poly::operator == (qf_poly P) {
+ if (rep == NONE)
+ return false;
+
+ // Two polynoms can be equal only if their degree is the same
+ if (d != P.d)
+ return false;
+
+ // We can't compare two polynoms using the roots, because they can
+ // be stored in different order, and therefore the comparison would
+ // be cumbersome. It is shorter to translate the polynoms in COEFF
+ // form, then make a comparison of each coefficient
+
+ if (rep == ROOTS)
+ to_coeff ();
+
+ if (P.rep == ROOTS)
+ P.to_coeff ();
+
+ for (unsigned i = 0; i <= d; i++)
+ if (p[i] != P.p[i])
+ return false;
+
+ return true;
+}
+
+bool qf_poly::operator != (qf_poly P) {
+ return !((*this) == P);
+}
+
+bool qf_poly::is_null (void) {
+ if (rep == NONE) {
+ std::cout << "Warning qf_poly::is_null() on a NONE polynom.\n";
+ return true;
+ }
+
+ if (d == 0)
+ return true;
+
+ if (d > 1)
+ return false;
+
+ if (rep & ROOTS)
+ return (krts == 0);
+ else
+ return (p[0] == 0);
+}
+
+// Basic division by x^n == left shift n places
+qf_poly qf_poly::operator << (unsigned n) {
+ if (rep == NONE) {
+ std::cout << "qf_poly::<< used on a NONE polynom.\n";
+ exit (-1);
+ }
+
+ if (n == 0)
+ return (*this);
+
+ if (d < n)
+ return qf_poly (0, 0, 0, 0); // 0
+
+ else if (d == n)
+ return qf_poly (p[d], 0, 0, 0); // Q(x) = P(n)
+
+ qf_poly R;
+
+ if (rep & COEFF) {
+ for (unsigned i = 0; i < n; i++)
+ if (p[i] != 0) {
+ std::cout << "Warning: << by " << n << " asked for but only "
+ << i << " possible.\n";
+ n = i;
+ }
+
+ // Okay, proceed
+ R.p = new qf_double_t[d - n + 1];
+ memcpy (R.p, &(p[n]), sizeof (qf_double_t) * (d - n + 1));
+ R.d = d - n;
+ }
+
+ if (rep & ROOTS) {
+ int nbz = n;
+ R.rts = new qf_double_t[2 * d];
+ R.krts = krts;
+
+ // Eliminates n zero roots
+ for (unsigned i = 0, j = 0; i < 2 * d; i += 2) {
+ if ((rts[i] == 0) && (rts[i + 1] == 0) && (nbz != 0))
+ nbz--;
+
+ else {
+ R.rts[j] = rts[i];
+ R.rts[j + 1] = rts[i + 1];
+ j += 2;
+ }
+ }
+
+ R.d = d - n;
+
+ // We did not found a sufficient number of zeros
+ if (nbz != 0) {
+ std::cout << "Warning: << by " << n << " asked for but only "
+ << n - nbz << " possible.\n";
+ R.d += nbz;
+ }
+ }
+
+ R.rep = rep;
+ return R;
+}
+
+// Multiplies by x^n
+qf_poly qf_poly::operator >> (unsigned n) {
+ if (rep == NONE) {
+ std::cout << "qf_poly::>> used on a NONE polynom.\n";
+ exit (-1);
+ }
+
+ if (n == 0)
+ return (*this);
+
+ qf_poly R (d + n);
+
+ if (rep & COEFF) {
+ R.p = new qf_double_t[d + n + 1];
+ memset (R.p, 0, sizeof (qf_double_t) * n);
+ memcpy (&(R.p[n]), p, sizeof (qf_double_t) * (d + 1));
+ }
+
+ if (rep & ROOTS) {
+ R.rts = new qf_double_t[2 * (d + n)];
+ memset (R.rts, 0, sizeof (qf_double_t) * 2 * n); // n times root = 0
+ memcpy (&(R.rts[2 * n]), rts, sizeof (qf_double_t) * 2 * d);
+ R.krts = krts;
+ }
+
+ R.rep = rep;
+ return R;
+}
+
+// Creates the odd part of a polynom
+qf_poly qf_poly::odd () {
+ qpr orep = rep;
+
+ if (rep == NONE) {
+ std::cout << "qf_poly::odd () used on a NONE polynom.\n";
+ exit (-1);
+ }
+
+ if (rep == ROOTS)
+ to_coeff ();
+
+ qf_poly P (*this);
+
+ int i = d;
+
+ if ((i % 2) == 1)
+ i--;
+
+ for (; i >= 0; i -= 2)
+ P.p[i] = 0;
+
+ P.spl ();
+
+ if ((orep == ROOTS) || (orep == BOTH))
+ P.to_roots ();
+
+ return P;
+}
+
+// Creates the even part of a polynom
+qf_poly qf_poly::even () {
+ qpr orep = rep;
+
+ if (rep == NONE) {
+ std::cout << "qf_poly::even () used on a NONE polynom.\n";
+ exit (-1);
+ }
+
+
+ if (rep == ROOTS)
+ to_coeff ();
+
+ qf_poly P (*this);
+
+ int i = d;
+
+ if (i == 0)
+ return P;
+
+ if ((i % 2) == 0)
+ i--;
+
+ for (; i >= 1; i -= 2)
+ P.p[i] = 0;
+
+ P.spl ();
+
+ if ((orep == ROOTS) || (orep == BOTH))
+ P.to_roots ();
+
+ return P;
+}
+
+// computes P(-X)
+qf_poly qf_poly::mnx () {
+ if (rep == NONE) {
+ std::cout << "qf_poly::mnx () used on a NONE polynom.\n";
+ exit (-1);
+ }
+
+ qf_poly P (d);
+
+ if ((rep == COEFF) || (rep == BOTH)) {
+ P.p = new qf_double_t[d + 1];
+ for (unsigned i = 0; i <= d; i++)
+ P.p[i] = ((i % 2) == 0 ? p[i] : -p[i]);
+ }
+
+ if ((rep == ROOTS) || (rep == BOTH)) {
+ P.rts = new qf_double_t[2 * d];
+
+ for (unsigned i = 0; i < 2 * d; i++)
+ P.rts[i] = -rts[i];
+
+ P.krts = ((d % 2) == 0 ? krts : -krts);
+ }
+
+ P.rep = rep;
+ return P;
+}
+
+// "Half square" : P(X) * P(-X)
+qf_poly qf_poly::hsq () {
+ if (rep == NONE) {
+ std::cout << "qf_poly::hsq () used on a NONE polynom.\n";
+ exit (-1);
+ }
+
+ qf_poly P (*this);
+
+ P *= mnx ();
+
+ return P;
+}
+
+// Q(X) <- P(X^2)
+qf_poly qf_poly::sqr () {
+ if (rep == NONE) {
+ std::cout << "qf_poly::sqr () used on a NONE polynom.\n";
+ exit (-1);
+ }
+
+ if (rep == ROOTS)
+ to_coeff ();
+
+ qf_poly P (even ());
+
+ // Contains odd order terms
+ if ((*this) != P) {
+ std::cout << "Error! qf_poly::sqr () used on a non-square polynom.\n";
+ exit (-1);
+ }
+
+ qf_poly Q (d / 2);
+
+ Q.p = new qf_double_t[d / 2 + 1];
+
+ for (unsigned i = 0; i <= d / 2; i++)
+ Q.p[i] = p[2 * i];
+
+ Q.rep = COEFF;
+
+ if ((rep == BOTH) || (rep == ROOTS))
+ Q.to_roots ();
+
+ return Q; // Q(X) = P(X^2)
+}
+
+// Eliminates a prime factor
+void qf_poly::div (qf_double_t r, qf_double_t i) {
+ if (rep == NONE) {
+ std::cout << "qf_poly::div () used on a NONE polynom.\n";
+ exit (-1);
+ }
+
+ i = fabs (i); // Imaginary part must be > 0
+
+ // First examins pathological cases
+
+ if (d == 0) {
+ std::cout << "Warning: Div () called on a constant polynom.\n";
+ return;
+ }
+
+ if ((d == 1) && (i != 0)) {
+ std::cout << "Div () real/complex error.\n";
+ return;
+ }
+
+ if (d == 1) {
+ if (((rep == ROOTS) || (rep == BOTH))
+ && (fabs (rts[0] - r) < ROOT_TOL)
+ && (fabs (rts[1]) < ROOT_TOL)) {
+ d = 0;
+ delete[] rts;
+ rts = NULL;
+ delete[] p;
+ p = new qf_double_t[1];
+ p[0] = krts;
+ rep = BOTH;
+ return;
+ }
+
+ if ((rep == COEFF) && (fabs (p[0] / p[1] + r) < ROOT_TOL)) {
+ qf_double_t temp = p[1];
+ d = 0;
+ delete[] p;
+ p = new qf_double_t[1];
+ p[0] = temp;
+ delete[] rts;
+ krts = temp;
+ rep = BOTH;
+ return;
+ }
+
+ std::cout << "Warning: Div () error. Specified factor not found.\n";
+ return;
+ }
+
+ // Proceed to general case.
+ // If i = 0, we divide by (X - r)
+ // If i != 0, we divide by (X^2 - 2rX + r^2+i^2), that is to say
+ // by (X - (r + iI))(X - (r - iI)) where I^2 = -1
+ if (rep == COEFF)
+ to_roots ();
+
+ qf_double_t * rtsp = new qf_double_t[2 * d];
+
+ bool found = false;
+
+ for (unsigned k = 0, j = 0; k < 2 * d; k += 2) {
+#ifdef _QF_POLY_DEBUG
+ std::cout << "Div: " << fabs (rts[k] - r) << " "
+ << fabs (rts[k + 1] - i) << "\n";
+#endif
+
+ if ((fabs (rts[k] - r) > ROOT_TOL) || (fabs (rts[k + 1] - i) > ROOT_TOL)) {
+ rtsp[j] = rts[k];
+ rtsp[j + 1] = rts[k + 1];
+ j += 2;
+ }
+
+ else {
+ if (i != 0)
+ // If complex root, eliminates also next root (conjugate)
+ k += 2;
+
+ found = true;
+ }
+ }
+
+ if (!found) {
+ delete[] rtsp;
+ std::cout << "Div () : factor not found! \n";
+ return;
+ }
+
+ delete[] rts;
+ rts = rtsp;
+
+ if (i == 0)
+ d--;
+ else
+ d -= 2;
+
+ rep = ROOTS;
+}
+
+// Simplifies polynoms : eliminates common roots
+void smpf (qf_poly & N, qf_poly & D) {
+ unsigned dN = N.d;
+ unsigned dD = D.d;
+ unsigned i, j;
+
+ std::cout << "dN: " << dN << " dD : " << dD << '\n';
+
+ bool * Ln = new bool[dN];
+ bool * Ld = new bool[dD];
+
+ // Init
+ for (i = 0; i < dN; i++)
+ Ln[i] = true;
+
+ for (i = 0; i < dD; i++)
+ Ld[i] = true;
+
+ if (N.rep == COEFF)
+ N.to_roots ();
+
+ if (D.rep == COEFF)
+ D.to_roots ();
+
+ // Seek for common roots
+
+ unsigned ndN = dN;
+ unsigned ndD = dD;
+
+ for (i = 0; i < 2 * dN; i += 2) {
+ for (j = 0; j < 2 * dD; j += 2) {
+ std::cout << "N.rts[" << i << "] = " << N.rts[i] << ", ";
+ std::cout << "D.rts[" << j << "] = " << D.rts[j] << "\n";
+ std::cout << "N.rts[" << i + 1 << "] = " << N.rts[i + 1] << ", ";
+ std::cout << "D.rts[" << j + 1 << "] = " << D.rts[j + 1] << "\n";
+ if ((Ld[j / 2]) &&
+ (fabs (N.rts[i] - D.rts[j]) < ROOT_TOL) &&
+ (fabs (N.rts[i + 1] - D.rts[j + 1]) < ROOT_TOL)) {
+ Ln[i / 2] = false; // Eliminates both roots
+ Ld[j / 2] = false;
+ ndN--;
+ ndD--;
+ std::cout << "Common root: (" << D.rts[j]
+ << ", " << D.rts[j + 1] << "i)\n";
+ break; // Direct to next root
+ }
+ }
+ }
+
+ if (ndN != dN) { // We have simplified sth
+ qf_double_t * nrN = new qf_double_t[2 * ndN];
+ qf_double_t * nrD = new qf_double_t[2 * ndD];
+
+ for (i = 0, j = 0; i < 2 * dN; i += 2) {
+ if (Ln[i / 2]) { // Non common root
+ nrN[j] = N.rts[i];
+ nrN[j + 1] = N.rts[i + 1];
+ j += 2;
+ }
+ }
+
+ delete[] N.rts;
+ N.rts = nrN;
+ N.d = ndN;
+ N.rep = ROOTS;
+
+ for (i = 0, j = 0; i < 2 * D.d; i += 2) {
+ if (Ld[i / 2]) { // Non common root
+ nrD[j] = D.rts[i];
+ nrD[j + 1] = D.rts[i + 1];
+ j += 2;
+ }
+ }
+
+ delete[] D.rts;
+ D.rts = nrD;
+ D.d = ndD;
+ D.rep = ROOTS;
+
+ N.to_coeff ();
+ D.to_coeff ();
+ std::cout << "ndN: " << ndN << " ndD : " << ndD << '\n';
+ }
+ delete[] Ln;
+ delete[] Ld;
+}
+
+// Hurwitzes a polynom. That is to say, eliminate its roots whose real part
+// is positive
+void qf_poly::hurw () {
+ if (rep == NONE) {
+ std::cout << "qf_poly::hurw () used on a NONE polynom.\n";
+ return;
+ }
+
+ if (rep == COEFF)
+ to_roots ();
+
+ qf_double_t * rtsp = new qf_double_t[2 * d];
+ unsigned j = 0;
+
+ for (unsigned i = 0; i < 2 * d; i += 2) {
+ if (rts[i] > 0)
+ if (rts[i + 1] == 0) // Real positive root
+ continue;
+
+ else {
+ i += 2; // Skips conjugate
+ continue;
+ }
+
+ else {
+ rtsp[j] = rts[i];
+ rtsp[j + 1] = rts[i + 1];
+ j += 2;
+ }
+ }
+
+ delete[] rts;
+ rts = rtsp;
+ d = j / 2;
+
+ if (krts < 0)
+ krts = -krts;
+
+ rep = ROOTS;
+}
+
+// Evaluates a polynom. Computes P(a) for real a
+qf_double_t qf_poly::eval (qf_double_t a) {
+ if (rep == NONE) {
+ std::cout << "qf_poly::eval () used on a NONE polynom.\n";
+ return 0;
+ }
+
+ if ((rep == COEFF) || (rep == BOTH)) {
+
+ if (d == 0)
+ return p[0]; // Constant
+
+ qf_double_t r = p[d];
+
+ for (int i = d - 1; i >= 0; i--)
+ r = r * a + p[i];
+
+ return r;
+ }
+ // ROOTS form : P (a) = k prod (a - r[i])
+ if (d == 0)
+ return krts;
+
+ qf_double_t r = krts;
+
+ for (unsigned i = 0; i < 2 * d; i += 2) {
+ if (rts[i + 1] == 0) // Real root
+ r *= (a - rts[i]);
+
+ else {
+ qf_double_t m = rts[i] * rts[i] + rts[i + 1] * rts[i + 1];
+ qf_double_t n = -2 * rts[i];
+
+ r *= (a * a + n * a + m);
+ i += 2; // Skips conjugate (following root)
+ }
+ }
+
+ return r;
+}
+
+// Evaluates a polynom P(X^2) for X^2 = c (c can be negative)
+qf_double_t qf_poly::evalX2 (qf_double_t c) {
+ return (sqr ()).eval (c);
+}
+
+#ifdef _QF_POLY_DEBUG
+// Pretty prints a polynom
+void qf_poly::disp (const char *name) {
+
+ if (rep == NONE) {
+ std::cout << name << "(x) is not initalized.\n";
+ return;
+ }
+
+ if ((rep == COEFF) || (rep == BOTH)) {
+ std::cout << name << "(x) = ";
+ disp_c ();
+ }
+
+ if ((rep == ROOTS) || (rep == BOTH)) {
+ std::cout << name << "(x) = ";
+ disp_r ();
+ }
+}
+#else
+void qf_poly::disp (const char *) { }
+#endif // _QF_POLY_DEBUG
+
+void qf_poly::disp_c (void) {
+ if (d == 0) {
+ std::cout << p[0] << '\n';
+ return;
+ }
+
+ if (p[d] < 0)
+ std::cout << "-";
+
+ if (fabs (p[d]) != 1)
+ std::cout << fabs (p[d]);
+
+ if (d == 1) {
+ std::cout << " x ";
+ }
+
+ else {
+ std::cout << " x^" << d << ' ';
+
+ for (unsigned i = d - 1; i > 1; i--) {
+ if (p[i] == 0) // Null monome
+ continue;
+
+ if (p[i] > 0)
+ std::cout << "+ ";
+ else
+ std::cout << "- ";
+
+ if (fabs (p[i]) != 1)
+ std::cout << fabs (p[i]);
+
+ std::cout << " x^" << i << ' ';
+ }
+
+ if (p[1] != 0) {
+ if (p[1] > 0)
+ std::cout << "+ ";
+ else
+ std::cout << "- ";
+
+ if (fabs (p[1]) != 1)
+ std::cout << fabs (p[1]);
+
+ std::cout << " x ";
+ }
+ }
+
+ if (p[0] != 0) {
+ if (p[0] > 0)
+ std::cout << "+ ";
+ else
+ std::cout << "- ";
+
+ std::cout << fabs (p[0]);
+
+ }
+ std::cout << '\n';
+}
+
+void qf_poly::disp_r (void) {
+ if (krts == -1)
+ std::cout << "- ";
+
+ else if (krts != 1)
+ std::cout << krts << ' ';
+
+ for (unsigned i = 0; i < 2 * d; i += 2) {
+ if (rts[i + 1] == 0) { // Real root
+ std::cout << "(X";
+
+ if (rts[i] == 0)
+ std::cout << ") ";
+
+ else if (rts[i] < 0)
+ std::cout << " + " << fabs (rts[i]) << ") ";
+
+ else
+ std::cout << " - " << rts[i] << ") ";
+ }
+ else { // Complex conjugate root
+ std::cout << "(X^2 ";
+
+ qf_double_t m = rts[i] * rts[i] + rts[i + 1] * rts[i + 1];
+ qf_double_t n = 2 * rts[i];
+
+ if (n > 0)
+ std::cout << "- " << n << "X ";
+
+ if (n < 0)
+ std::cout << "+ " << fabs (n) << "X ";
+
+ std::cout << "+ " << m << ") ";
+
+ i += 2; // Skips next root (conjugate of present one)
+ }
+ }
+ std::cout << '\n';
+}
+
+/* This function calculates P(X) = sum (a[i] * X^i) (sum form) out of
+ the roots (product form) P(X) = k * prod (X - r[i]) */
+void qf_poly::to_coeff (void) {
+ if (rep == NONE) {
+ std::cout << "qf_poly::to_coeff () used on a NONE polynom.\n";
+ exit (-1);
+ }
+
+ if ((rep == COEFF) || (rep == BOTH))
+ return;
+
+ if (p != NULL)
+ delete[] p;
+
+ rep = BOTH;
+
+ p = new qf_double_t[1];
+ p[0] = krts;
+
+ if ((rts == NULL) || (d == 0))
+ return;
+
+ if (d == 1) {
+ p = new qf_double_t[2];
+ p[0] = -krts * rts[0];
+ p[1] = krts;
+ return;
+ }
+
+ unsigned r = 0;
+
+ do {
+ if (rts[2 * r + 1] == 0) { // Real root
+ qf_double_t *q = new qf_double_t[r + 2];
+
+ q[0] = 0;
+ memcpy (&(q[1]), p, sizeof (qf_double_t) * (r + 1)); // Q(X) = XP(X)
+
+ for (unsigned j = 0; j < r + 1; j++)
+ q[j] -= rts[2 * r] * p[j]; // Q(X) -= r[i]P(X)
+
+ delete[] p;
+ p = q;
+ r++;
+ }
+
+ else { // Complex conjugate root
+ qf_double_t m, n;
+ qf_double_t *q = new qf_double_t[r + 3];
+ qf_double_t *s = new qf_double_t[r + 2];
+
+ m = rts[2 * r] * rts[2 * r] + rts[2 * r + 1] * rts[2 * r + 1];
+ n = -2 * rts[2 * r];
+
+ q[0] = q[1] = s[0] = 0;
+
+ memcpy (&(q[2]), p, sizeof (qf_double_t) * (r + 1)); // Q(X) = X^2P(X)
+ memcpy (&(s[1]), p, sizeof (qf_double_t) * (r + 1)); // S(X) = XP(X)
+
+ for (unsigned j = 0; j < r + 1; j++) // Q(X) = (X^2 + nX + m) P(X)
+ q[j] += n * s[j] + m * p[j];
+
+ q[r + 1] += n * s[r + 1];
+
+ delete[] p;
+ delete[] s;
+ p = q;
+ r += 2;
+ }
+ }
+ while (r < d);
+
+ (*this).disp ("qf_poly::to_coeff: ");
+}
+
+/* The function finds the complex roots of the polynom given by:
+ p(x) = a_{n-1} * x^{n-1} + ... a_{2} * x^{2} + a_{1} * x + a_{0}
+ The results are stored in the vector rst, real part followed by
+ imaginary part for each complex root. It return zero on success
+ and non-zero otherwise. */
+void qf_poly::to_roots (void) {
+ if (rep == NONE) {
+ std::cout << "qf_poly::to_roots () used on a NONE polynom.\n";
+ exit (-1);
+ }
+
+ int status;
+
+ if ((rep == ROOTS) || (rep == BOTH))
+ return; // Nothing to do
+
+ if (d == 0)
+ // cannot solve for only one term
+ return;
+
+ qf_matrix m (d);
+
+ if (rts != NULL)
+ delete[] rts;
+
+ rts = new qf_double_t[2 * d];
+
+ krts = p[d];
+
+ qf_scm (m);
+ qf_bcm (m);
+ status = qf_qrc (m, rts);
+
+ // root solving qr method failed to converge
+ for (unsigned i = 0; i < 2 * d; i++) {
+ if (fabs (rts[i]) <= ROOT_PREC)
+ rts[i] = 0;
+ else
+ rts[i] = ROUND_ROOT (rts[i]);
+// std::cout << "root(" << i/2 << ") = " << rts [i] <<
+// " + " << rts [i+1] << " i\n" ;
+ }
+
+ rep = BOTH;
+}
+
+// Private functions used by qf_poly::solve
+
+// Set companion matrix.
+void qf_poly::qf_scm (qf_matrix & m) {
+ unsigned int i, j;
+ for (i = 0; i < m.n; i++)
+ for (j = 0; j < m.n; j++)
+ m (i, j) = 0;
+
+ for (i = 1; i < m.n; i++)
+ m (i, i - 1) = 1;
+
+ for (i = 0; i < m.n; i++)
+ m (i, m.n - 1) = -p[i] / p[m.n];
+}
+
+// Balance companion matrix
+void qf_poly::qf_bcm (qf_matrix & m) {
+ int not_converged = 1;
+ qf_double_t row_norm = 0;
+ qf_double_t col_norm = 0;
+
+ while (not_converged) {
+ unsigned int i, j;
+ qf_double_t g, f, s;
+
+ not_converged = 0;
+
+ for (i = 0; i < m.n; i++) {
+ /* column norm, excluding the diagonal */
+ if (i != m.n - 1) {
+ col_norm = fabs (m (i + 1, i));
+ }
+
+ else {
+ col_norm = 0;
+
+ for (j = 0; j < m.n - 1; j++) {
+ col_norm += fabs (m (j, m.n - 1));
+ }
+ }
+
+ /* row norm, excluding the diagonal */
+ if (i == 0) {
+ row_norm = fabs (m (0, m.n - 1));
+ }
+
+ else if (i == m.n - 1) {
+ row_norm = fabs (m (i, i - 1));
+ }
+
+ else {
+ row_norm = fabs (m (i, i - 1)) + fabs (m (i, m.n - 1));
+ }
+
+ if ((col_norm == 0) || (row_norm == 0)) {
+ continue;
+ }
+
+ g = row_norm / RADIX;
+ f = 1;
+ s = col_norm + row_norm;
+
+ while (col_norm < g) {
+ f *= RADIX;
+ col_norm *= RADIX2;
+ }
+
+ g = row_norm * RADIX;
+
+ while (col_norm > g) {
+ f /= RADIX;
+ col_norm /= RADIX2;
+ }
+
+ if ((row_norm + col_norm) < 0.95 * s * f) {
+ not_converged = 1;
+ g = 1 / f;
+ if (i == 0) {
+ m (0, m.n - 1) *= g;
+ }
+
+ else {
+ m (i, i - 1) *= g;
+ m (i, m.n - 1) *= g;
+ }
+
+ if (i == m.n - 1) {
+ for (j = 0; j < m.n; j++) {
+ m (j, i) *= f;
+ }
+ }
+ else {
+ m (i + 1, i) *= f;
+ }
+ }
+ }
+ }
+}
+
+// Root solver using QR method.
+int qf_poly::qf_qrc (qf_matrix & h, qf_double_t * zroot) {
+ qf_double_t t = 0;
+ unsigned int iterations, e, i, j, k, m;
+ qf_double_t w, x, y, s, z;
+ qf_double_t p = 0, q = 0, r = 0;
+ int notlast;
+ unsigned int n = d;
+
+next_root:
+ if (n == 0)
+ return 0;
+ iterations = 0;
+
+next_iteration:
+ for (e = n; e >= 2; e--) {
+ qf_double_t a1 = fabs (h (e - 1, e - 2));
+ qf_double_t a2 = fabs (h (e - 2, e - 2));
+ qf_double_t a3 = fabs (h (e - 1, e - 1));
+
+ if (a1 <= EPSILON * (a2 + a3))
+ break;
+ }
+
+ x = h (n - 1, n - 1);
+
+ if (e == n) {
+ SET_COMPLEX_PACKED (zroot, n - 1, x + t, 0); /* one real root */
+ n--;
+ goto next_root;
+ }
+
+ y = h (n - 2, n - 2);
+ w = h (n - 2, n - 1) * h (n - 1, n - 2);
+
+ if (e == n - 1) {
+ p = (y - x) / 2;
+ q = p * p + w;
+ y = sqrt (fabs (q));
+ x += t;
+
+ if (q > 0) { /* two real roots */
+ if (p < 0)
+ y = -y;
+
+ y += p;
+ SET_COMPLEX_PACKED (zroot, n - 1, x - w / y, 0);
+ SET_COMPLEX_PACKED (zroot, n - 2, x + y, 0);
+ }
+
+ else {
+ SET_COMPLEX_PACKED (zroot, n - 1, x + p, -y);
+ SET_COMPLEX_PACKED (zroot, n - 2, x + p, y);
+ }
+
+ n -= 2;
+ goto next_root;
+ }
+
+ /* No more roots found yet, do another iteration */
+ if (iterations == MAX_ITERATIONS) { /* increased from 30 to 60 */
+ /* too many iterations - give up! */
+ return -1;
+ }
+
+ if (iterations % 10 == 0 && iterations > 0) {
+ /* use an exceptional shift */
+ t += x;
+
+ for (i = 0; i < n; i++) {
+ h (i, i) -= x;
+ }
+
+ s = fabs (h (n - 1, n - 2)) + fabs (h (n - 2, n - 3));
+ y = 0.75 * s;
+ x = y;
+ w = -0.4375 * s * s;
+ }
+
+ iterations++;
+
+ for (m = n - 2; m >= e; m--) {
+ qf_double_t a1, a2, a3;
+
+ z = h (m - 1, m - 1);
+ r = x - z;
+ s = y - z;
+ p = h (m - 1, m) + (r * s - w) / h (m, m - 1);
+ q = h (m, m) - z - r - s;
+ r = h (m + 1, m);
+ s = fabs (p) + fabs (q) + fabs (r);
+ p /= s;
+ q /= s;
+ r /= s;
+
+ if (m == e)
+ break;
+
+ a1 = fabs (h (m - 1, m - 2));
+ a2 = fabs (h (m - 2, m - 2));
+ a3 = fabs (h (m, m));
+
+ if (a1 * (fabs (q) + fabs (r)) <= EPSILON * fabs (p) * (a2 + a3))
+ break;
+ }
+
+ for (i = m + 2; i <= n; i++) {
+ h (i - 1, i - 3) = 0;
+ }
+ for (i = m + 3; i <= n; i++) {
+ h (i - 1, i - 4) = 0;
+ }
+
+ /* double QR step */
+ for (k = m; k <= n - 1; k++) {
+ notlast = (k != n - 1);
+
+ if (k != m) {
+ p = h (k - 1, k - 2);
+ q = h (k, k - 2);
+ r = notlast ? h (k + 1, k - 2) : 0;
+ x = fabs (p) + fabs (q) + fabs (r);
+
+ if (x == 0)
+ continue; /* FIXME????? */
+
+ p /= x;
+ q /= x;
+ r /= x;
+ }
+
+ s = sqrt (p * p + q * q + r * r);
+
+ if (p < 0)
+ s = -s;
+
+ if (k != m) {
+ h (k - 1, k - 2) = -s * x;
+ } else if (e != m) {
+ h (k - 1, k - 2) *= -1;
+ }
+
+ p += s;
+ x = p / s;
+ y = q / s;
+ z = r / s;
+ q /= p;
+ r /= p;
+
+ /* do row modifications */
+ for (j = k; j <= n; j++) {
+ p = h (k - 1, j - 1) + q * h (k, j - 1);
+
+ if (notlast) {
+ p += r * h (k + 1, j - 1);
+ h (k + 1, j - 1) -= p * z;
+ }
+
+ h (k, j - 1) -= p * y;
+ h (k - 1, j - 1) -= p * x;
+ }
+ j = (k + 3 < n) ? (k + 3) : n;
+
+ /* do column modifications */
+ for (i = e; i <= j; i++) {
+ p = x * h (i - 1, k - 1) + y * h (i - 1, k);
+
+ if (notlast) {
+ p += z * h (i - 1, k + 1);
+ h (i - 1, k + 1) -= p * r;
+ }
+
+ h (i - 1, k) -= p * q;
+ h (i - 1, k - 1) -= p;
+ }
+ }
+
+ goto next_iteration;
+}
+
+
+void qf_poly::roots_to_complex(QVector< std::complex > &roots)
+{
+ roots.clear();
+ for (unsigned int i=0;i(rts[2*i],rts[2*i+1]));
+ }
+}
diff --git a/qucs-activefilter/qf_poly.h b/qucs-activefilter/qf_poly.h
new file mode 100644
index 00000000..06e61146
--- /dev/null
+++ b/qucs-activefilter/qf_poly.h
@@ -0,0 +1,142 @@
+/***************************************************************************
+ qf_poly.h
+ ----------------
+ begin : Mon Jan 02 2006
+ copyright : (C) 2006 by Vincent Habchi, F5RCS
+ email : 10.50@free.fr
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+#include
+#include
+
+#ifndef _QF_POLY_H
+#define _QF_POLY_H
+
+/* Headers for R[X] arithmetic */
+
+#define qf_double_t long double
+
+#include "qf_matrix.h"
+
+// A polynom can be described either by a product of monoms equal to
+// (x - r[i]) where r[i] is the ith root and a constant factor, or by
+// the classical series of coefficient a[0]...a[n], or both.
+
+enum qf_poly_rep
+{
+ NONE = 0, // Not initialized
+ ROOTS = 1, // P(X) = k * prod (x - r[i])
+ COEFF = 2, // P(X) = sum (a[i] * x^i)
+ BOTH = 3 // Both have been computed
+};
+
+typedef enum qf_poly_rep qpr;
+
+class qf_poly
+{
+ private:
+ qpr rep; // Type of representation
+ unsigned d; // Current degree
+ qf_double_t krts; // Constant k
+ qf_double_t * p; // Table of coefficients
+ qf_double_t * rts; // Table of complex roots
+
+ // Functions used by solve
+ void qf_bcm (qf_matrix &);
+ int qf_qrc (qf_matrix &, qf_double_t *);
+ void qf_scm (qf_matrix &);
+
+ public:
+ qf_poly ();
+ qf_poly (unsigned); // id with d
+ qf_poly (qf_double_t, qf_double_t, qf_double_t, unsigned); // Up to d=2
+ qf_poly (int, const qf_double_t[]); // Id, with inst.
+ qf_poly (int, qf_double_t, const qf_double_t[]);
+ qf_poly (const qf_poly &); // Copy
+ ~qf_poly ();
+
+ // access operators
+ qf_poly & operator = (const qf_poly &); // P = Q
+ qf_double_t & operator [] (int i); // Access to element
+
+ // arithmetic operators
+ qf_poly operator - (void); // Unary -
+
+ friend qf_poly operator + (qf_poly, qf_poly);
+ friend qf_poly operator - (qf_poly, qf_poly);
+ friend qf_poly operator * (qf_poly, qf_poly);
+ friend qf_poly operator * (qf_poly, const qf_double_t);
+
+ qf_poly operator += (qf_poly);
+ qf_poly operator -= (qf_poly);
+ qf_poly operator *= (qf_poly); // P(X) = P(X)*Q(X)
+ qf_poly operator *= (const qf_double_t);
+
+ qf_poly operator << (unsigned); // Basic div by X^n
+ qf_poly operator >> (unsigned); // Multiply by X^n
+
+ bool operator == (qf_poly); // Test
+ bool operator != (qf_poly); // Test
+ bool is_null (void);
+
+ unsigned deg (void); // Degree of poly
+ void spl (void); // Simplify
+ qf_poly odd (void); // Odd part
+ qf_poly even (void); // Even part
+ qf_poly mnx (void); // P(X) -> P(-X)
+ qf_poly hsq (void); // P(X)*P(-X)
+ qf_poly sqr (void); // Q(X) = P(X^2)
+ qf_double_t eval (qf_double_t); // P(X = a)
+ qf_double_t evalX2 (qf_double_t); // P(X^2 = a)
+
+ void to_roots (void); // Solves
+ qf_double_t k (void); // Return krts factor
+ void to_coeff (void); // Calculate normal form
+ void div (qf_double_t, qf_double_t); // Simple division
+ void hurw (void); // "Hurwitzes" polynom
+
+ void disp (const char *); // Prints P(X)
+ void disp_c (void);
+ void disp_r (void);
+
+ void roots_to_complex(QVector< std::complex > &roots);
+
+ friend void smpf (qf_poly &, qf_poly &); // Simplify
+};
+
+// For solve, we need some gibber
+
+// Save complex value elements
+#define SET_COMPLEX_PACKED(zp,n,r,i) \
+ *((zp)+2*(n)+0)=(r); *((zp)+2*(n)+1)=(i);
+
+// Some constants
+
+// IEEE long precision 2^{-52}
+// # define EPSILON 2.2204460492503131e-16
+// IEEE double long precision 2^{-63}
+#define EPSILON 1.0842021724855044e-19
+#define ROOT_PREC 1e-9
+#define ROOT_TOL 1e-7
+
+inline qf_double_t ROUND_ROOT (qf_double_t k) {
+ if (k > 0)
+ return floor (k / ROOT_PREC) * ROOT_PREC;
+ else
+ return ceil (k / ROOT_PREC) * ROOT_PREC;
+}
+
+#define RADIX 2
+#define RADIX2 (RADIX*RADIX)
+#define MAX_ITERATIONS 60
+
+#endif // _QF_POLY_H
+
diff --git a/qucsactivefilter/qucsactivefilter.1 b/qucs-activefilter/qucsactivefilter.1
similarity index 100%
rename from qucsactivefilter/qucsactivefilter.1
rename to qucs-activefilter/qucsactivefilter.1
diff --git a/qucs-activefilter/qucsactivefilter.cpp b/qucs-activefilter/qucsactivefilter.cpp
new file mode 100644
index 00000000..ec2e2507
--- /dev/null
+++ b/qucs-activefilter/qucsactivefilter.cpp
@@ -0,0 +1,447 @@
+/***************************************************************************
+ qucsactivefilter.cpp
+ ----------------
+ begin : Wed Apr 10 2014
+ copyright : (C) 2014 by Vadim Kuznetsov
+ email : ra3xdh@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+
+#include "qucsactivefilter.h"
+#include "sallenkey.h"
+#include "mfbfilter.h"
+#include "schcauer.h"
+#include "transferfuncdialog.h"
+#include
+
+
+QucsActiveFilter::QucsActiveFilter(QWidget *parent)
+ : QMainWindow(parent)
+{
+ Nfil = 4;
+ Fc = 1000;
+ ftyp = Filter::NoFilter;
+
+ QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
+
+ //lblInputData = new QLabel(tr("Входные данные"));
+ lblA1 = new QLabel(tr("Passband attenuation, Ap (dB)"));
+ lblA2 = new QLabel(tr("Stopband attenuation, As (dB)"));
+ lblF1 = new QLabel(tr("Cuttof frequency, Fc (Hz)"));
+ lblF2 = new QLabel(tr("Stopband frequency, Fs (Hz)"));
+ lblRpl1 = new QLabel(tr("Passband ripple Rp(dB)"));
+ //lblRpl2 = new QLabel(tr("Stopband ripple (dB)"));
+ lblKv = new QLabel(tr("Passband gain, Kv (dB)"));
+
+
+ edtA1 = new QLineEdit("3");
+ QDoubleValidator *val1 = new QDoubleValidator(0,100000,3);
+ edtA1->setValidator(val1);
+ edtA2 = new QLineEdit("20");
+ edtA2->setValidator(val1);
+ edtF1 = new QLineEdit("1000");
+ edtF1->setValidator(val1);
+ edtF2 = new QLineEdit("1200");
+ edtF2->setValidator(val1);
+ edtPassbRpl = new QLineEdit("3");
+ edtPassbRpl->setValidator(val1);
+ //edtStopbRpl = new QLineEdit("3");
+ //edtStopbRpl->setValidator(val1);
+ edtKv = new QLineEdit("0");
+ edtKv->setValidator(val1);
+ QIntValidator *val2 = new QIntValidator(2,20);
+ lblOrder = new QLabel(tr("Filter order"));
+ edtOrder = new QLineEdit("5");
+ edtOrder->setValidator(val2);
+
+ lblTyp = new QLabel(tr("Approximation type:"));
+ cbxFilterFunc = new QComboBox;
+ QStringList lst2;
+ lst2<addItems(lst2);
+ connect(cbxFilterFunc,SIGNAL(currentIndexChanged(int)),this,SLOT(slotSwitchParameters()));
+
+ btnDefineTransferFunc = new QPushButton(tr("Manually define transfer function"));
+ btnDefineTransferFunc->setEnabled(false);
+ connect(btnDefineTransferFunc,SIGNAL(clicked()),this,SLOT(slotDefineTransferFunc()));
+
+ btnCalcSchematic = new QPushButton(tr("Calculate and copy to clipboard"));
+ connect(btnCalcSchematic,SIGNAL(clicked()),SLOT(slotCalcSchematic()));
+
+ lblResult = new QLabel(tr("Calculation console"));
+ txtResult = new QTextEdit;
+
+
+ lblSch = new QLabel(tr("Filter topology"));
+ lblResp = new QLabel(tr("Filter type:"));
+ cbxResponse = new QComboBox;
+ QStringList lst3;
+ lst3<
addItems(lst3);
+ connect(cbxResponse,SIGNAL(currentIndexChanged(int)),this,SLOT(slotUpdateResponse()));
+ connect(cbxResponse,SIGNAL(currentIndexChanged(int)),this,SLOT(slotUpdateSchematic()));
+
+ cbxFilterType = new QComboBox;
+ QStringList lst;
+ lst<
addItems(lst);
+ connect(cbxFilterType,SIGNAL(currentIndexChanged(int)),this,SLOT(slotUpdateSchematic()));
+ this->slotSwitchParameters();
+
+ lblAFR = new QLabel(tr("General amplitude frequency response"));
+ lblTopology = new QLabel(tr("Filter topology preview (one stage)"));
+
+ QString s1 = ":/images/AFR.svg";
+ QSvgRenderer *ren = new QSvgRenderer(s1);
+ QSize sz = ren->defaultSize();
+ sz *= 1.1;
+ delete ren;
+ imgAFR = new QSvgWidget(s1);
+ imgAFR->setFixedSize(sz);
+ imgAFR->show();
+
+ s1 = ":/images/cauer.svg";
+ ren = new QSvgRenderer(s1);
+ sz = ren->defaultSize();
+ sz *= 0.65;
+ delete ren;
+
+ sch_pic = new QSvgWidget(s1);
+ sch_pic->setFixedSize(sz);
+ sch_pic->show();
+
+ top = new QHBoxLayout;
+ left = new QVBoxLayout;
+ center = new QVBoxLayout;
+ right = new QVBoxLayout;
+
+ //left->addWidget(lblInputData);
+ left->addWidget(lblA1);
+ left->addWidget(edtA1);
+ left->addWidget(lblA2);
+ left->addWidget(edtA2);
+ left->addWidget(lblF1);
+ left->addWidget(edtF1);
+ left->addWidget(lblF2);
+ left->addWidget(edtF2);
+ left->addWidget(lblRpl1);
+ left->addWidget(edtPassbRpl);
+ left->addWidget(lblKv);
+ left->addWidget(edtKv);
+ left->addWidget(lblOrder);
+ left->addWidget(edtOrder);
+ QHBoxLayout *l3 = new QHBoxLayout;
+ l3->addWidget(lblTyp);
+ l3->addWidget(cbxFilterFunc);
+ left->addLayout(l3);
+
+ left->addWidget(btnDefineTransferFunc);
+
+ QHBoxLayout *l1 = new QHBoxLayout;
+ l1->addWidget(lblResp);
+ l1->addWidget(cbxResponse);
+ left->addLayout(l1);
+ QHBoxLayout *l2 = new QHBoxLayout;
+ l2->addWidget(lblSch);
+ l2->addWidget(cbxFilterType);
+ left->addLayout(l2);
+ left->addWidget(btnCalcSchematic);
+ left->addStretch();
+
+ right->addWidget(lblAFR);
+ right->addWidget(imgAFR);
+ right->addWidget(lblTopology);
+ right->addWidget(sch_pic);
+ right->addStretch();
+
+ top->addLayout(left);
+ top->addLayout(center);
+ top->addLayout(right);
+
+ top1 = new QVBoxLayout;
+ top1->addLayout(top);
+ QSplitter *sp1 = new QSplitter;
+ top1->addWidget(sp1);
+ txtResult->setReadOnly(true);
+ top1->addWidget(txtResult);
+ txtResult->setMinimumHeight(180);
+
+ zenter = new QWidget;
+ this->setCentralWidget(zenter);
+ zenter->setLayout(top1);
+}
+
+QucsActiveFilter::~QucsActiveFilter()
+{
+
+}
+
+
+void QucsActiveFilter::slotCalcSchematic()
+{
+
+ FilterParam par;
+ par.Ap = edtA1->text().toFloat();
+ par.As = edtA2->text().toFloat();
+ par.Rp = edtPassbRpl->text().toFloat();
+ par.Fc = edtF1->text().toFloat();
+ par.Fs = edtF2->text().toFloat();
+ float G = edtKv->text().toFloat();
+ par.Kv = pow(10,G/20.0);
+
+ QStringList lst;
+ Filter::FilterFunc ffunc;
+
+ switch (cbxFilterFunc->currentIndex()) {
+ case 0 : ffunc = Filter::Butterworth;
+ break;
+ case 1 : ffunc = Filter::Chebyshev;
+ break;
+ case 2 : ffunc = Filter::InvChebyshev;
+ break;
+ case 3 : ffunc = Filter::Cauer;
+ break;
+ case 4 : ffunc = Filter::Bessel;
+ par.order = edtOrder->text().toInt();
+ break;
+ case 5 : ffunc = Filter::User;
+ break;
+ default: ffunc = Filter::NoFunc;
+ break;
+ }
+
+
+
+ switch (cbxResponse->currentIndex()) {
+ case 0 : ftyp = Filter::LowPass;
+ break;
+ case 1 : ftyp = Filter::HighPass;
+ break;
+ case 2 : ftyp = Filter::BandPass;
+ break;
+ case 3 : ftyp = Filter::BandStop;
+ break;
+ default: ftyp = Filter::NoFilter;
+ break;
+ }
+
+ QString s;
+ bool ok = false;
+
+ switch (cbxFilterType->currentIndex()) {
+ case 0 : {
+ if (((ffunc==Filter::InvChebyshev)||(ffunc==Filter::Cauer))) {
+ SchCauer cauer(ffunc,ftyp,par);
+ ok = cauer.calcFilter();
+ cauer.createPolesZerosList(lst);
+ cauer.createPartList(lst);
+ txtResult->setText(lst.join("\n"));
+ if (ok) {
+ cauer.createSchematic(s);
+ } else {
+ errorMessage(tr("Unable to implement filter with such parameters and topology \n"
+ "Change parapeters and/or topology and try again!"));
+ }
+ } else {
+ errorMessage(tr("Unable to use Cauer section for Chebyshev or Butterworth \n"
+ "frequency response. Try to use another topology."));
+ }
+ }
+
+ break;
+ case 1 : {
+ if (!((ffunc==Filter::InvChebyshev)||(ffunc==Filter::Cauer))) {
+ MFBfilter mfb(ffunc,ftyp,par);
+ if (ffunc==Filter::User) {
+ mfb.set_TrFunc(coeffA,coeffB);
+ }
+ ok = mfb.calcFilter();
+ mfb.createPolesZerosList(lst);
+ mfb.createPartList(lst);
+ txtResult->setText(lst.join("\n"));
+ if (ok) {
+ mfb.createSchematic(s);
+ } else {
+ errorMessage(tr("Unable to implement filter with such parameters and topology \n"
+ "Change parapeters and/or topology and try again!"));
+ }
+ } else {
+ errorMessage(tr("Unable to use MFB filter for Cauer or Inverse Chebyshev \n"
+ "frequency response. Try to use another topology."));
+ }
+ }
+ break;
+ case 2 : {
+ SallenKey sk(ffunc,ftyp,par);
+ if (ffunc==Filter::User) {
+ sk.set_TrFunc(coeffA,coeffB);
+ }
+ ok = sk.calcFilter();
+ sk.createPolesZerosList(lst);
+ sk.createPartList(lst);
+ txtResult->setText(lst.join("\n"));
+ if (ok) {
+ sk.createSchematic(s);
+ } else {
+ errorMessage(tr("Unable to implement filter with such parameters and topology \n"
+ "Change parapeters and/or topology and try again!"));
+ }
+ }
+ break;
+ case 3 : errorMessage(tr("Function will be implemented in future version"));
+ break;
+ default: break;
+ }
+
+ if (ok) {
+ txtResult->append(tr("\nFilter calculation was sucessfull"));
+ } else {
+ txtResult->append(tr("\nFilter calculation terminated with error"));
+ }
+
+ QClipboard *cb = QApplication::clipboard();
+ cb->setText(s);
+
+}
+
+void QucsActiveFilter::slotUpdateResponse()
+{
+ QString s = ":/images/AFR.svg";
+
+ switch (cbxResponse->currentIndex()) {
+ case 0 :
+ s = ":/images/AFR.svg";
+ ftyp = Filter::LowPass;
+ break;
+ case 1 : s = ":/images/high-pass.svg";
+ ftyp = Filter::HighPass;
+ break;
+ case 2 : ftyp = Filter::BandPass;
+ break;
+ case 3 : ftyp = Filter::BandStop;
+ break;
+ default: ftyp = Filter::NoFilter;
+ break;
+ }
+
+ QSvgRenderer *ren = new QSvgRenderer(s);
+ QSize sz = ren->defaultSize();
+ sz *= 1.1;
+ delete ren;
+
+ imgAFR->load(s);
+ imgAFR->setFixedSize(sz);
+}
+
+void QucsActiveFilter::slotUpdateSchematic()
+{
+ slotUpdateResponse();
+ QString s;
+ switch (cbxFilterType->currentIndex()) {
+ case 0 : s = ":images/cauer.svg";
+ break;
+ case 1 : if (ftyp==Filter::HighPass) {
+ s = ":/images/mfb-highpass.svg";
+ } else if (ftyp==Filter::LowPass) {
+ s = ":/images/mfb-lowpass.svg";
+ }
+ break;
+ case 2 : if (ftyp==Filter::HighPass) {
+ s = ":/images/sk-highpass.svg";
+ } else if (ftyp==Filter::LowPass) {
+ s = ":/images/sk-lowpass.svg";
+ }
+ break;
+ case 3 : s = ":/images/mfb-lowpass.svg";
+ break;
+ default:
+ break;
+ }
+
+ QSvgRenderer *ren = new QSvgRenderer(s);
+ QSize sz = ren->defaultSize();
+ sz *= 0.65;
+ delete ren;
+
+ sch_pic->load(s);
+ sch_pic->setFixedSize(sz);
+}
+
+void QucsActiveFilter::slotSwitchParameters()
+{
+ if (cbxFilterFunc->currentIndex()==0) {
+ edtA1->setEnabled(true);
+ edtPassbRpl->setEnabled(false);
+ } else {
+ edtA1->setEnabled(false);
+ edtPassbRpl->setEnabled(true);
+ }
+
+ if ((cbxFilterFunc->currentIndex()==3)||(cbxFilterFunc->currentIndex()==2)) {
+ cbxFilterType->setCurrentIndex(0);
+ cbxFilterType->setDisabled(true);
+ } else {
+ cbxFilterType->setDisabled(false);
+ }
+
+ if ((cbxFilterFunc->currentIndex())==4) {
+ edtOrder->setEnabled(true);
+ } else {
+ edtOrder->setEnabled(false);
+ }
+
+ if ((cbxFilterFunc->currentIndex()==5)||(cbxFilterFunc->currentIndex()==4)) {
+ btnDefineTransferFunc->setEnabled(true);
+ edtF2->setEnabled(false);
+ edtPassbRpl->setEnabled(false);
+ edtA1->setEnabled(false);
+ edtA2->setEnabled(false);
+ edtKv->setEnabled(false);
+ } else {
+ btnDefineTransferFunc->setEnabled(false);
+ edtF2->setEnabled(true);
+ edtPassbRpl->setEnabled(true);
+ edtA1->setEnabled(true);
+ edtA2->setEnabled(true);
+ edtKv->setEnabled(true);
+ }
+}
+
+void QucsActiveFilter::slotDefineTransferFunc()
+{
+
+ TransferFuncDialog *trfuncdlg = new TransferFuncDialog(coeffA,coeffB,this);
+ if (trfuncdlg->exec()) {
+ trfuncdlg->getCoeffs(coeffA,coeffB);
+ }
+ delete trfuncdlg;
+}
+
+void QucsActiveFilter::errorMessage(QString str)
+{
+ QMessageBox* msg = new QMessageBox(QMessageBox::Critical,tr("Active filter design"),
+ str,
+ QMessageBox::Ok);
+ msg->exec();
+ delete msg;
+}
diff --git a/qucs-activefilter/qucsactivefilter.h b/qucs-activefilter/qucsactivefilter.h
new file mode 100644
index 00000000..a1eb0d5b
--- /dev/null
+++ b/qucs-activefilter/qucsactivefilter.h
@@ -0,0 +1,112 @@
+/***************************************************************************
+ qucsactivefilter.h
+ ----------------
+ begin : Wed Apr 10 2014
+ copyright : (C) 2014 by Vadim Kuznetsov
+ email : ra3xdh@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef FILTERSINTEZ_H
+#define FILTERSINTEZ_H
+
+#include
+#include
+#include
+#include
+#include "filter.h"
+
+class QucsActiveFilter : public QMainWindow
+{
+ Q_OBJECT
+
+private:
+ QLabel *lblInputData;
+ QLabel *lblA1;
+ QLabel *lblA2;
+ QLabel *lblF1;
+ QLabel *lblF2;
+ QLabel *lblTyp;
+ QLabel *lblKv;
+ QLabel *lblRpl1;
+ QLabel *lblRpl2;
+ QLabel *lblResp;
+
+ QLabel *lblAFR;
+ QLabel *lblTopology;
+ QLabel *lblOrder;
+
+ QLineEdit *edtA1; // passband attenuation A1
+ QLineEdit *edtA2; // stopband attenuation A2
+ QLineEdit *edtF1; // passband cutoff frequency F1
+ QLineEdit *edtF2; // stopband cutoff frequency F2
+ QLineEdit *edtKv;
+ QLineEdit *edtPassbRpl;
+ QLineEdit *edtStopbRpl;
+ QLineEdit *edtOrder;
+
+ QComboBox *cbxFilterFunc;
+ QPushButton *btnCalcSchematic;
+ QPushButton *btnDefineTransferFunc;
+
+ QLabel *lblResult;
+ QTextEdit *txtResult;
+
+ QSvgWidget *imgAFR;
+ QLabel *lblSch;
+
+ /*QRadioButton *btnLowPass;
+ QRadioButton *btnHighPass;
+ QRadioButton *btnBandPass;
+ QRadioButton *btnBandStop;*/
+
+ QComboBox *cbxFilterType;
+ QComboBox *cbxResponse;
+
+ QPushButton *btnElements;
+ //QPushButton *btnPassive;
+
+ QHBoxLayout *top;
+ QVBoxLayout *left;
+ QVBoxLayout *center;
+ QVBoxLayout *right;
+ QVBoxLayout *top1;
+
+ QSvgWidget *sch_pic;
+
+ QWidget *zenter;
+
+ void errorMessage(QString s);
+
+ QVector< std::complex > Poles;
+
+ float Fc;
+ int Nfil;
+
+ QVector coeffB;
+ QVector coeffA;
+
+ Filter::FType ftyp;
+
+private slots:
+
+ void slotUpdateSchematic();
+ void slotUpdateResponse();
+ void slotCalcSchematic();
+ void slotSwitchParameters();
+ void slotDefineTransferFunc();
+
+public:
+ QucsActiveFilter(QWidget *parent = 0);
+ ~QucsActiveFilter();
+};
+
+#endif // FILTERSINTEZ_H
diff --git a/qucsactivefilter/qucsactivefilter.pro b/qucs-activefilter/qucsactivefilter.pro
similarity index 100%
rename from qucsactivefilter/qucsactivefilter.pro
rename to qucs-activefilter/qucsactivefilter.pro
diff --git a/qucs-activefilter/qucsactivefilter.qrc b/qucs-activefilter/qucsactivefilter.qrc
new file mode 100644
index 00000000..8d3ecb2a
--- /dev/null
+++ b/qucs-activefilter/qucsactivefilter.qrc
@@ -0,0 +1,12 @@
+
+
+ sk-highpass.svg
+ sk-lowpass.svg
+ mfb-lowpass.svg
+ mfb-highpass.svg
+ AFR.svg
+ cauer.svg
+ high-pass.svg
+ trfunc.png
+
+
diff --git a/qucs-activefilter/sallenkey.cpp b/qucs-activefilter/sallenkey.cpp
new file mode 100644
index 00000000..56921e44
--- /dev/null
+++ b/qucs-activefilter/sallenkey.cpp
@@ -0,0 +1,290 @@
+/***************************************************************************
+ sallenkey.cpp
+ ----------------
+ begin : Wed Apr 10 2014
+ copyright : (C) 2014 by Vadim Kuznetsov
+ email : ra3xdh@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include
+#endif
+
+#include "sallenkey.h"
+#include
+
+SallenKey::SallenKey(Filter::FilterFunc ffunc_, Filter::FType type_, FilterParam par) :
+ Filter(ffunc_, type_, par)
+{
+ Nr1 = 4;
+ Nc1 = 2;
+ Nop1 = 1;
+}
+
+
+void SallenKey::calcLowPass()
+{
+ float R1,R2,R3,R4,C1,C2;
+ float Wc = 2*M_PI*Fc;
+ float Nst = order/2 + order%2;
+ float Kv1 = pow(Kv,1.0/Nst);
+ qDebug()<calcFirstOrder();
+}
+
+
+void SallenKey::calcHighPass()
+{
+ float R1,R2,R3,R4,C1;
+ float Wc = 2*M_PI*Fc;
+
+ float Nst = order/2 + order%2;
+ float Kv1 = pow(Kv,1.0/Nst);
+
+ for (int k=1; k <= order/2; k++) {
+
+ float re = Poles.at(k-1).real();
+ float im = Poles.at(k-1).imag();
+ float B = -2.0*re;
+ float C = re*re + im*im;
+
+ qDebug()<\n";
+ s += "\n";
+ s += QString("<.AC AC1 1 30 410 0 61 0 0 \"lin\" 1 \"1 Hz\" 1 \"%1 kHz\" 1 \"501\" 1 \"no\" 0>\n").arg((10.0*Fc)/1000.0);
+ s += "<.DC DC1 1 280 410 0 61 0 0 \"26.85\" 0 \"0.001\" 0 \"1 pA\" 0 \"1 uV\" 0 \"no\" 0 \"150\" 0 \"no\" 0 \"none\" 0 \"CroutLU\" 0>\n";
+ s += "\n";
+ s += QString("\n").arg(20+dx);
+ s += QString("\n").arg(20+dx);
+ for (int i=1; i<=N2ord; i++) {
+ stage = Sections.at(i-1);
+ qDebug()<\n").arg(stage.N).arg(370+dx);
+ s += QString("\n").arg(270+dx);
+ s += QString("\n").arg(320+dx);
+ s += QString("\n").arg(3+(i-1)*N_R).arg(320+dx).arg(stage.R3,0,'f',3);
+ s += QString("\n").arg(2+(i-1)*N_C).arg(200+dx).arg(C2,0,'f',3).arg(suffix2);
+ s += QString("\n").arg(1+(i-1)*N_C).arg(100+dx).arg(C1,0,'f',3).arg(suffix1);
+ s += QString("\n").arg(2+(i-1)*N_R).arg(270+dx).arg(stage.R2,0,'f',3);
+ s += QString("\n").arg(1+(i-1)*N_R).arg(330+dx).arg(stage.R1,0,'f',3);
+ s += QString("\n").arg(4+(i-1)*N_R).arg(410+dx).arg(stage.R4,0,'f',3);
+ dx += 510;
+ }
+
+ if (N1stOrd!=0) {
+ qDebug()<\n";
+ s += "\n";
+ dx = 0;
+ s += QString("<%1 190 %2 230 \"\" 0 0 0 \"\">\n").arg(20+dx).arg(20+dx);
+ s += QString("<%1 190 %2 190 \"in\" %3 160 18 \"\">\n").arg(20+dx).arg(70+dx).arg(70+dx);
+ for (int i=1; i<=N2ord; i++) {
+ if (i!=1) {
+ s += QString("<%1 190 %2 190 \"\" 0 0 0 \"\">\n").arg(dx-20).arg(70+dx);
+ s += QString("<%1 190 %2 160 \"\" 0 0 0 \"\">\n").arg(dx-20).arg(dx-20);
+ s += QString("<%1 160 %2 160 \"\" 0 0 0 \"\">\n").arg(dx-20).arg(dx-50);
+ }
+ s += QString("<%1 70 %2 70 \"\" 0 0 0 \"\">\n").arg(360+dx).arg(460+dx);
+ if ((2*i)==order) {
+ s += QString("<%1 70 %2 160 \"out\" %3 90 51 \"\">\n").arg(460+dx).arg(460+dx).arg(490+dx);
+ } else {
+ s += QString("<%1 70 %2 160 \"\" 0 0 0 \"\">\n").arg(460+dx).arg(460+dx);
+ }
+ s += QString("<%1 160 %2 160 \"\" 0 0 0 \"\">\n").arg(410+dx).arg(460+dx);
+ s += QString("<%1 260 %2 260 \"\" 0 0 0 \"\">\n").arg(440+dx).arg(460+dx);
+ s += QString("<%1 160 %2 260 \"\" 0 0 0 \"\">\n").arg(460+dx).arg(460+dx);
+ s += QString("<%1 190 %2 210 \"\" 0 0 0 \"\">\n").arg(270+dx).arg(270+dx);
+ s += QString("<%1 190 %2 190 \"\" 0 0 0 \"\">\n").arg(230+dx).arg(270+dx);
+ s += QString("<%1 190 %2 190 \"\" 0 0 0 \"\">\n").arg(130+dx).arg(150+dx);
+ s += QString("<%1 190 %2 190 \"\" 0 0 0 \"\">\n").arg(150+dx).arg(170+dx);
+ s += QString("<%1 70 %2 190 \"\" 0 0 0 \"\">\n").arg(150+dx).arg(150+dx);
+ s += QString("<%1 70 %2 70 \"\" 0 0 0 \"\">\n").arg(150+dx).arg(300+dx);
+ s += QString("<%1 140 %2 190 \"\" 0 0 0 \"\">\n").arg(270+dx).arg(270+dx);
+ s += QString("<%1 140 %2 140 \"\" 0 0 0 \"\">\n").arg(270+dx).arg(340+dx);
+ s += QString("<%1 180 %2 260 \"\" 0 0 0 \"\">\n").arg(320+dx).arg(320+dx);
+ s += QString("<%1 180 %2 180 \"\" 0 0 0 \"\">\n").arg(320+dx).arg(340+dx);
+ s += QString("<%1 260 %2 260 \"\" 0 0 0 \"\">\n").arg(320+dx).arg(380+dx);
+ s += QString("<%1 260 %2 310 \"\" 0 0 0 \"\">\n").arg(320+dx).arg(320+dx);
+ dx += 510;
+ }
+
+ if (N1stOrd!=0) {
+ createFirstOrderWires(s,dx,160);
+ }
+
+ s += "\n";
+}
+
+void SallenKey::createLowPassSchematic(QString &s)
+{
+ int const N_R=4; // number of resisitors in 2-order Sallen-Key stage
+ int const N_C=2; // number of capacitors in 2-order Sallen-Key stage
+ RC_elements stage;
+ int dx = 0;
+ int N2ord = order/2; // number of 2-nd order stages
+ int N1stOrd = order%2; // number of 1-st order stages
+
+ s += "\n";
+ s += "\n";
+ s += QString("<.AC AC1 1 30 410 0 61 0 0 \"lin\" 1 \"1 Hz\" 1 \"%1 kHz\" 1 \"501\" 1 \"no\" 0>\n").arg((10.0*Fc)/1000.0);
+ s += "<.DC DC1 1 280 410 0 61 0 0 \"26.85\" 0 \"0.001\" 0 \"1 pA\" 0 \"1 uV\" 0 \"no\" 0 \"150\" 0 \"no\" 0 \"none\" 0 \"CroutLU\" 0>\n";
+ s += "\n";
+ s += QString("\n").arg(20+dx);
+ s += QString("\n").arg(20+dx);
+ for (int i=1; i<=N2ord; i++) {
+ stage = Sections.at(i-1);
+ qDebug()<\n").arg(stage.N).arg(370+dx);
+ s += QString("\n").arg(270+dx);
+ s += QString("\n").arg(320+dx);
+ s += QString("\n").arg(2+(i-1)*N_C).arg(330+dx).arg(C2,0,'f',3).arg(suffix2);
+ s += QString("\n").arg(1+(i-1)*N_C).arg(270+dx).arg(C1,0,'f',3).arg(suffix1);
+ s += QString("\n").arg(2+(i-1)*N_R).arg(200+dx).arg(stage.R2,0,'f',3);
+ s += QString("\n").arg(1+(i-1)*N_R).arg(100+dx).arg(stage.R1,0,'f',3);
+ s += QString("\n").arg(3+(i-1)*N_R).arg(320+dx).arg(stage.R3,0,'f',3);
+ s += QString("\n").arg(4+(i-1)*N_R).arg(410+dx).arg(stage.R4,0,'f',3);
+ dx += 510;
+ }
+
+ if (N1stOrd!=0) {
+ createFirstOrderComponentsLPF(s,Sections.last(),dx);
+ }
+
+ s += "\n";
+ s += "\n";
+ dx = 0;
+ s += QString("<%1 190 %2 230 \"\" 0 0 0 \"\">\n").arg(20+dx).arg(20+dx);
+ s += QString("<%1 190 %2 190 \"in\" %3 160 18 \"\">\n").arg(20+dx).arg(70+dx).arg(70+dx);
+ for (int i=1; i<=N2ord; i++) {
+ if (i!=1) {
+ s += QString("<%1 190 %2 190 \"\" 0 0 0 \"\">\n").arg(dx-20).arg(70+dx);
+ s += QString("<%1 190 %2 160 \"\" 0 0 0 \"\">\n").arg(dx-20).arg(dx-20);
+ s += QString("<%1 160 %2 160 \"\" 0 0 0 \"\">\n").arg(dx-20).arg(dx-50);
+ }
+ s += QString("<%1 70 %2 70 \"\" 0 0 0 \"\">\n").arg(360+dx).arg(460+dx);
+ if ((2*i)==order) {
+ s += QString("<%1 70 %2 160 \"out\" %3 90 51 \"\">\n").arg(460+dx).arg(460+dx).arg(490+dx);
+ } else {
+ s += QString("<%1 70 %2 160 \"\" 0 0 0 \"\">\n").arg(460+dx).arg(460+dx);
+ }
+ s += QString("<%1 160 %2 160 \"\" 0 0 0 \"\">\n").arg(410+dx).arg(460+dx);
+ s += QString("<%1 260 %2 260 \"\" 0 0 0 \"\">\n").arg(440+dx).arg(460+dx);
+ s += QString("<%1 160 %2 260 \"\" 0 0 0 \"\">\n").arg(460+dx).arg(460+dx);
+ s += QString("<%1 190 %2 210 \"\" 0 0 0 \"\">\n").arg(270+dx).arg(270+dx);
+ s += QString("<%1 190 %2 190 \"\" 0 0 0 \"\">\n").arg(230+dx).arg(270+dx);
+ s += QString("<%1 190 %2 190 \"\" 0 0 0 \"\">\n").arg(130+dx).arg(150+dx);
+ s += QString("<%1 190 %2 190 \"\" 0 0 0 \"\">\n").arg(150+dx).arg(170+dx);
+ s += QString("<%1 70 %2 190 \"\" 0 0 0 \"\">\n").arg(150+dx).arg(150+dx);
+ s += QString("<%1 70 %2 70 \"\" 0 0 0 \"\">\n").arg(150+dx).arg(300+dx);
+ s += QString("<%1 140 %2 190 \"\" 0 0 0 \"\">\n").arg(270+dx).arg(270+dx);
+ s += QString("<%1 140 %2 140 \"\" 0 0 0 \"\">\n").arg(270+dx).arg(340+dx);
+ s += QString("<%1 180 %2 260 \"\" 0 0 0 \"\">\n").arg(320+dx).arg(320+dx);
+ s += QString("<%1 180 %2 180 \"\" 0 0 0 \"\">\n").arg(320+dx).arg(340+dx);
+ s += QString("<%1 260 %2 260 \"\" 0 0 0 \"\">\n").arg(320+dx).arg(380+dx);
+ s += QString("<%1 260 %2 310 \"\" 0 0 0 \"\">\n").arg(320+dx).arg(320+dx);
+ dx += 510;
+ }
+
+ if (N1stOrd!=0) {
+ createFirstOrderWires(s,dx,160);
+ }
+
+ s += "\n";
+}
diff --git a/qucs-activefilter/sallenkey.h b/qucs-activefilter/sallenkey.h
new file mode 100644
index 00000000..21c54c14
--- /dev/null
+++ b/qucs-activefilter/sallenkey.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ sallenkey.h
+ ----------------
+ begin : Wed Apr 10 2014
+ copyright : (C) 2014 by Vadim Kuznetsov
+ email : ra3xdh@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef SALLENKEY_H
+#define SALLENKEY_H
+
+#include
+#include
+#include
+#include "filter.h"
+
+
+class SallenKey : public Filter
+{
+
+protected:
+
+ void calcHighPass();
+ void calcLowPass();
+ void createHighPassSchematic(QString &s);
+ void createLowPassSchematic(QString &s);
+
+public:
+ SallenKey(Filter::FilterFunc ffunc_, Filter::FType type_, FilterParam par);
+
+ //void createSchematic(QString &s);
+
+};
+
+#endif // SALLENKEY_H
diff --git a/qucs-activefilter/schcauer.cpp b/qucs-activefilter/schcauer.cpp
new file mode 100644
index 00000000..cd8c9e4b
--- /dev/null
+++ b/qucs-activefilter/schcauer.cpp
@@ -0,0 +1,233 @@
+/***************************************************************************
+ schcauer.cpp
+ ----------------
+ begin : Wed Apr 10 2014
+ copyright : (C) 2014 by Vadim Kuznetsov
+ email : ra3xdh@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+# include
+#endif
+
+#include "schcauer.h"
+
+SchCauer::SchCauer(Filter::FilterFunc ffunc_, Filter::FType type_, FilterParam par) :
+ Filter(ffunc_, type_, par)
+{
+ Nr1 = 5;
+ Nop1 = 3;
+ Nc1 = 2;
+}
+
+void SchCauer::calcLowPass()
+{
+ float R1,R2,R3,R4,R5,C1,C2;
+ float Wc = 2*M_PI*Fc;
+ float Nst = order/2 + order%2;
+ float Kv1 = pow(Kv,1.0/Nst);
+ //qDebug()<calcFirstOrder();
+}
+
+
+void SchCauer::calcHighPass()
+{
+ float R1,R2,R3,R4,R5,C1,C2;
+ float Wc = 2*M_PI*Fc;
+ float Nst = order/2 + order%2;
+ float Kv1 = pow(Kv,1.0/Nst);
+ //qDebug()<calcFirstOrder();
+}
+
+
+void SchCauer::createLowPassSchematic(QString &s)
+{
+ createGenericSchematic(s);
+}
+
+void SchCauer::createHighPassSchematic(QString &s)
+{
+ createGenericSchematic(s);
+}
+
+void SchCauer::createGenericSchematic(QString &s)
+{
+ RC_elements stage;
+ int dx = 0;
+ int N2ord = order/2; // number of 2-nd order stages
+ int N1stOrd = order%2; // number of 1-st order stages
+
+ s += "\n";
+ s += "\n";
+ s += "\n";
+ s += "<.DC DC1 1 40 510 0 61 0 0 \"26.85\" 0 \"0.001\" 0 \"1 pA\" 0 \"1 uV\" 0 \"no\" 0 \"150\" 0 \"no\" 0 \"none\" 0 \"CroutLU\" 0>\n";
+ s += "\n";
+ s += "<.AC AC1 1 320 510 0 61 0 0 \"lin\" 1 \"1 Hz\" 1 \"10 kHz\" 1 \"5001\" 1 \"no\" 0>\n";
+ s += "\n";
+
+ for (int i=1; i<=N2ord; i++) {
+ stage = Sections.at(i-1);
+ qDebug()<\n").arg(1+(i-1)*Nop1).arg(270+dx);
+ s += QString("\n").arg(2+(i-1)*Nop1).arg(300+dx);
+ s += QString("\n").arg(3+(i-1)*Nop1).arg(560+dx);
+ s += QString("\n").arg(1+(i-1)*Nc1).arg(330+dx).arg(C1,0,'f',3).arg(suffix1);
+ s += QString("\n").arg(2+(i-1)*Nc1).arg(450+dx).arg(C2,0,'f',3).arg(suffix2);
+ s += QString("\n").arg(1+(i-1)*Nr1).arg(180+dx).arg(stage.R1,0,'f',3);
+ s += QString("\n").arg(2+(i-1)*Nr1).arg(410+dx).arg(stage.R2,0,'f',3);
+ s += QString("\n").arg(3+(i-1)*Nr1).arg(440+dx).arg(stage.R3,0,'f',3);
+ s += QString("\n").arg(4+(i-1)*Nr1).arg(360+dx).arg(stage.R4,0,'f',3);
+ s += QString("\n").arg(5+(i-1)*Nr1).arg(190+dx).arg(stage.R5,0,'f',3);
+ s += QString("\n").arg(240+dx);
+ s += QString("\n").arg(250+dx);
+
+ dx += 580;
+ }
+
+ if (N1stOrd!=0) {
+ if (ftype==Filter::LowPass) {
+ createFirstOrderComponentsLPF(s,Sections.last(),dx+80);
+ } else if (ftype==Filter::HighPass) {
+ createFirstOrderComponentsHPF(s,Sections.last(),dx+80);
+ }
+
+ }
+
+ s += "\n";
+ s += "\n";
+ dx = 0;
+ s += "<80 220 140 220 \"in\" 120 170 0 \"\">\n";
+ s += "<80 220 80 260 \"\" 0 0 0 \"\">\n";
+
+ for (int i=1; i<=N2ord; i++) {
+ if (i!=1) {
+ s += QString("<%1 260 %2 260 \"\" 0 0 0 \"\">\n").arg(dx+30).arg(140+dx);
+ }
+ s += QString("<%1 370 %2 370 \"\" 0 0 0 \"\">\n").arg(500+dx).arg(610+dx);
+ s += QString("<%1 220 %2 220 \"\" 0 0 0 \"\">\n").arg(210+dx).arg(220+dx);
+ s += QString("<%1 280 %2 370 \"\" 0 0 0 \"\">\n").arg(500+dx).arg(500+dx);
+ s += QString("<%1 280 %2 280 \"\" 0 0 0 \"\">\n").arg(500+dx).arg(530+dx);
+ s += QString("<%1 260 %2 260 \"\" 0 0 0 \"\">\n").arg(600+dx).arg(610+dx);
+ s += QString("<%1 260 %2 370 \"\" 0 0 0 \"\">\n").arg(610+dx).arg(610+dx);
+ s += QString("<%1 240 %2 240 \"\" 0 0 0 \"\">\n").arg(440+dx).arg(480+dx);
+ s += QString("<%1 400 %2 400 \"\" 0 0 0 \"\">\n").arg(340+dx).arg(420+dx);
+ s += QString("<%1 380 %2 380 \"\" 0 0 0 \"\">\n").arg(220+dx).arg(260+dx);
+ s += QString("<%1 380 %2 380 \"\" 0 0 0 \"\">\n").arg(260+dx).arg(270+dx);
+ s += QString("<%1 150 %2 220 \"\" 0 0 0 \"\">\n").arg(220+dx).arg(220+dx);
+ s += QString("<%1 150 %2 150 \"\" 0 0 0 \"\">\n").arg(220+dx).arg(300+dx);
+ s += QString("<%1 240 %2 240 \"\" 0 0 0 \"\">\n").arg(310+dx).arg(380+dx);
+ s += QString("<%1 260 %2 290 \"\" 0 0 0 \"\">\n").arg(240+dx).arg(240+dx);
+ s += QString("<%1 220 %2 220 \"\" 0 0 0 \"\">\n").arg(220+dx).arg(240+dx);
+ s += QString("<%1 420 %2 420 \"\" 0 0 0 \"\">\n").arg(250+dx).arg(270+dx);
+ s += QString("<%1 420 %2 440 \"\" 0 0 0 \"\">\n").arg(250+dx).arg(250+dx);
+ if ((2*i)==order) {
+ s += QString("<%1 110 %2 260 \"out\" %3 160 101 \"\">\n").arg(610+dx).arg(610+dx).arg(540+dx);
+ } else {
+ s += QString("<%1 110 %2 260 \"\" 0 0 0 \"\">\n").arg(610+dx).arg(610+dx);
+ }
+ s += QString("<%1 110 %2 110 \"\" 0 0 0 \"\">\n").arg(470+dx).arg(610+dx);
+ s += QString("<%1 110 %2 150 \"\" 0 0 0 \"\">\n").arg(220+dx).arg(220+dx);
+ s += QString("<%1 110 %2 110 \"\" 0 0 0 \"\">\n").arg(220+dx).arg(410+dx);
+ s += QString("<%1 220 %2 220 \"\" 0 0 0 \"\">\n").arg(140+dx).arg(150+dx);
+ s += QString("<%1 220 %2 260 \"\" 0 0 0 \"\">\n").arg(140+dx).arg(140+dx);
+ s += QString("<%1 260 %2 380 \"\" 0 0 0 \"\">\n").arg(140+dx).arg(140+dx);
+ s += QString("<%1 380 %2 380 \"\" 0 0 0 \"\">\n").arg(140+dx).arg(160+dx);
+ s += QString("<%1 240 %2 240 \"\" 0 0 0 \"\">\n").arg(480+dx).arg(530+dx);
+ s += QString("<%1 240 %2 400 \"\" 0 0 0 \"\">\n").arg(480+dx).arg(480+dx);
+ s += QString("<%1 320 %2 400 \"\" 0 0 0 \"\">\n").arg(420+dx).arg(420+dx);
+ s += QString("<%1 320 %2 320 \"\" 0 0 0 \"\">\n").arg(390+dx).arg(420+dx);
+ s += QString("<%1 320 %2 380 \"\" 0 0 0 \"\">\n").arg(260+dx).arg(260+dx);
+ s += QString("<%1 320 %2 320 \"\" 0 0 0 \"\">\n").arg(260+dx).arg(330+dx);
+ s += QString("<%1 150 %2 150 \"\" 0 0 0 \"\">\n").arg(360+dx).arg(380+dx);
+ s += QString("<%1 150 %2 240 \"\" 0 0 0 \"\">\n").arg(380+dx).arg(380+dx);
+
+ dx +=580;
+ }
+
+ if (N1stOrd!=0) {
+ createFirstOrderWires(s,dx+80,260);
+ }
+
+ s += "\n";
+}
diff --git a/qucs-activefilter/schcauer.h b/qucs-activefilter/schcauer.h
new file mode 100644
index 00000000..3fece4ce
--- /dev/null
+++ b/qucs-activefilter/schcauer.h
@@ -0,0 +1,43 @@
+/***************************************************************************
+ schcauer.h
+ ----------------
+ begin : Wed Apr 10 2014
+ copyright : (C) 2014 by Vadim Kuznetsov
+ email : ra3xdh@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef SCHCAUER_H
+#define SCHCAUER_H
+
+#include
+#include
+#include
+#include "filter.h"
+
+class SchCauer : public Filter // Cauer 2-order section
+{
+
+private:
+ void createGenericSchematic(QString &s);
+
+protected:
+
+ void calcHighPass();
+ void calcLowPass();
+ void createHighPassSchematic(QString &s);
+ void createLowPassSchematic(QString &s);
+
+public:
+ SchCauer(Filter::FilterFunc ffunc_, Filter::FType type_, FilterParam par);
+};
+
+#endif // SCHCAUER_H
diff --git a/qucs-activefilter/sk-highpass.svg b/qucs-activefilter/sk-highpass.svg
new file mode 100644
index 00000000..0b52a241
--- /dev/null
+++ b/qucs-activefilter/sk-highpass.svg
@@ -0,0 +1,1129 @@
+
+
diff --git a/qucs-activefilter/sk-lowpass.svg b/qucs-activefilter/sk-lowpass.svg
new file mode 100644
index 00000000..c9ae3d21
--- /dev/null
+++ b/qucs-activefilter/sk-lowpass.svg
@@ -0,0 +1,1129 @@
+
+
diff --git a/qucs-activefilter/transferfuncdialog.cpp b/qucs-activefilter/transferfuncdialog.cpp
new file mode 100644
index 00000000..c551334c
--- /dev/null
+++ b/qucs-activefilter/transferfuncdialog.cpp
@@ -0,0 +1,157 @@
+/***************************************************************************
+ transferfuncdialog.cpp
+ ----------------
+ begin : Wed Apr 10 2014
+ copyright : (C) 2014 by Vadim Kuznetsov
+ email : ra3xdh@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+
+#include "transferfuncdialog.h"
+
+TransferFuncDialog::TransferFuncDialog(QVector &a, QVector &b, QWidget *parent) :
+ QDialog(parent)
+{
+ this->setWindowTitle(tr("Define filter transfer function"));
+
+ imgTrfuncEq = new QLabel;
+ imgTrfuncEq->setPixmap(QPixmap(":images/trfunc.png"));
+ //imgTrfuncEq->setScaledContents(true);
+
+
+
+ lblB = new QLabel(tr("Numenator b[i]="));
+ lblA = new QLabel(tr("Denomenator a[i]="));
+
+ QStringList indexes;
+ for (int i=0;i<50;i++) {
+ indexes<setColumnCount(head1.count());
+ tblA->setRowCount(50);
+ tblA->setHorizontalHeaderLabels(head1);
+ tblA->setVerticalHeaderLabels(indexes);
+ tblA->setFixedWidth(150);
+
+ if (!a.isEmpty()) {
+ long double num;
+ int i = a.count()-1;
+
+ foreach (num,a) {
+ QTableWidgetItem *it = new QTableWidgetItem(QString::number((double)num));
+ tblA->setItem(i,0,it);
+ i--;
+ }
+ }
+
+
+ tblB = new QTableWidget;
+ QStringList head2;
+ head2<setColumnCount(head2.count());
+ tblB->setRowCount(50);
+ tblB->setHorizontalHeaderLabels(head2);
+ tblB->setVerticalHeaderLabels(indexes);
+ tblB->setFixedWidth(150);
+
+ if (!b.isEmpty()) {
+ long double num;
+ int i = b.count()-1;
+
+ foreach (num,b) {
+ QTableWidgetItem *it = new QTableWidgetItem(QString::number((double)num));
+ tblB->setItem(i,0,it);
+ i--;
+ }
+ }
+
+ btnAccept = new QPushButton(tr("Accept"));
+ connect(btnAccept,SIGNAL(clicked()),this,SLOT(accept()));
+ connect(btnAccept,SIGNAL(clicked()),this,SLOT(slotCheckCoeffs()));
+ btnCancel = new QPushButton(tr("Cancel"));
+ connect(btnCancel,SIGNAL(clicked()),this,SLOT(reject()));
+
+ low1 = new QVBoxLayout;
+ low1->addWidget(lblB);
+ low1->addWidget(tblB);
+
+ low2 = new QVBoxLayout;
+ low2->addWidget(lblA);
+ low2->addWidget(tblA);
+
+ low3 = new QHBoxLayout;
+ low3->addWidget(btnAccept);
+ low3->addWidget(btnCancel);
+
+ top = new QHBoxLayout;
+ top->addLayout(low1);
+ top->addLayout(low2);
+
+ top1 = new QVBoxLayout;
+ top1->addWidget(imgTrfuncEq);
+ top1->addLayout(top);
+ top1->addLayout(low3);
+
+
+ this->setLayout(top1);
+
+}
+
+void TransferFuncDialog::getCoeffs(QVector &a, QVector &b)
+{
+ a.clear();
+ b.clear();
+
+ // bool a0 = false;
+
+ for (int i=tblA->rowCount()-1;i>=0;i--) {
+ QTableWidgetItem *itm = tblA->item(i,0);
+ if (itm!=0) {
+
+ //if (!a0) a0 = true;
+
+ QString str = itm->text();
+ //if ((str.isEmpty())) break;
+ bool ok;
+ long double n = (long double) str.toDouble(&ok);
+ if (ok) a.append(n);
+ }
+ //else if (a0) a.append(0.0);
+ }
+
+
+ //bool b0 = true;
+
+ for (int i=tblB->rowCount()-1;i>=0;i--) {
+ QTableWidgetItem *itm = tblB->item(i,0);
+ if (itm!=0) {
+
+ //if (!b0) b0 = true;
+
+ QString str = itm->text();
+ //if ((str.isEmpty())) break;
+ bool ok;
+ long double n = (long double) str.toDouble(&ok);
+ if (ok) b.append(n);
+ }
+ //else if (b0) b.append(0.0);
+ }
+}
+
+void TransferFuncDialog::slotCheckCoeffs()
+{
+
+}
diff --git a/qucs-activefilter/transferfuncdialog.h b/qucs-activefilter/transferfuncdialog.h
new file mode 100644
index 00000000..6410815d
--- /dev/null
+++ b/qucs-activefilter/transferfuncdialog.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+ transferfuncdialog.h
+ ----------------
+ begin : Wed Apr 10 2014
+ copyright : (C) 2014 by Vadim Kuznetsov
+ email : ra3xdh@gmail.com
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ ***************************************************************************/
+
+#ifndef TRANSFERFUNCDIALOG_H
+#define TRANSFERFUNCDIALOG_H
+
+#include
+#include
+
+class TransferFuncDialog : public QDialog
+{
+ Q_OBJECT
+
+private:
+ QLabel *lblA;
+ QLabel *lblB;
+ QLabel *imgTrfuncEq;
+ QTableWidget *tblA;
+ QTableWidget *tblB;
+
+ QPushButton *btnAccept;
+ QPushButton *btnCancel;
+
+ QHBoxLayout *top;
+ QVBoxLayout *top1;
+ QVBoxLayout *low1;
+ QVBoxLayout *low2;
+ QHBoxLayout *low3;
+
+public:
+ explicit TransferFuncDialog(QVector &a, QVector &b, QWidget *parent = 0);
+
+ void getCoeffs(QVector &a, QVector &b);
+
+signals:
+
+private slots:
+ void slotCheckCoeffs();
+
+public slots:
+
+};
+
+#endif // TRANSFERFUNCDIALOG_H
diff --git a/qucs-activefilter/trfunc.png b/qucs-activefilter/trfunc.png
new file mode 100644
index 00000000..2ecbb4e1
Binary files /dev/null and b/qucs-activefilter/trfunc.png differ