From a297628c7a3ea9e3b10acb9200f4475e3ee4eba4 Mon Sep 17 00:00:00 2001 From: in3otd Date: Sat, 4 Jan 2020 08:18:09 +0100 Subject: [PATCH 1/5] Fix power probe power calculation The complex power was wrongly computed as S = V I and by flipping the sign of the reactive power instead of using S = V I*. --- qucs-core/src/components/wprobe.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/qucs-core/src/components/wprobe.cpp b/qucs-core/src/components/wprobe.cpp index c2aeb3f4c1..7e43cb4dca 100644 --- a/qucs-core/src/components/wprobe.cpp +++ b/qucs-core/src/components/wprobe.cpp @@ -65,8 +65,11 @@ void wprobe::saveOperatingPoints (void) { void wprobe::calcOperatingPoints (void) { //Reading the current and voltage values to calculate power values - nr_double_t VAr = real ((getV (NODE_3) - getV (NODE_4)) * getJ (NODE_1)); - nr_double_t VAi = -imag ((getV (NODE_3) - getV (NODE_4)) * getJ (NODE_1)); + nr_complex_t Vw = getV (NODE_3) - getV (NODE_4); + nr_complex_t Iw = getJ (VSRC_1); + nr_complex_t Sw = Vw * conj (Iw); + nr_double_t VAr = real (Sw); + nr_double_t VAi = imag (Sw); setOperatingPoint ("VAr", VAr); setOperatingPoint ("VAi", VAi); From d18bd68b82997866c38d57579219a8c2a63ee4dc Mon Sep 17 00:00:00 2001 From: in3otd Date: Sat, 4 Jan 2020 12:14:27 +0100 Subject: [PATCH 2/5] Fix wprobe ports assignment so that the voltage noise calculations are correct. --- qucs-core/src/components/wprobe.cpp | 19 +++++++++++-------- qucs-test | 2 +- qucs/qucs/components/wprobe.cpp | 8 ++++---- 3 files changed, 16 insertions(+), 13 deletions(-) diff --git a/qucs-core/src/components/wprobe.cpp b/qucs-core/src/components/wprobe.cpp index 7e43cb4dca..5d61851a72 100644 --- a/qucs-core/src/components/wprobe.cpp +++ b/qucs-core/src/components/wprobe.cpp @@ -39,14 +39,16 @@ wprobe::wprobe () : circuit (4) { setVoltageSources (1); } -//NODE 1 --> I+ -//NODE 2 --> I- -//NODE 3 --> V+ -//NODE 4 --> V- +// voltmeter nodes must be at nodes 1 and 2 as so it's assumed +// in saveNoiseResults() for noise calculations +//NODE 1 --> V+ +//NODE 2 --> V- +//NODE 3 --> I+ +//NODE 4 --> I- void wprobe::initDC (void) { allocMatrixMNA (); - voltageSource (VSRC_1, NODE_1, NODE_2); + voltageSource (VSRC_1, NODE_3, NODE_4); } void wprobe::initAC (void) { @@ -54,8 +56,9 @@ void wprobe::initAC (void) { } void wprobe::saveOperatingPoints (void) { - nr_double_t Vr = real (getV (NODE_3) - getV (NODE_4)); - nr_double_t Vi = imag (getV (NODE_3) - getV (NODE_4)); + nr_double_t Vr = real (getV (NODE_1) - getV (NODE_2)); + nr_double_t Vi = imag (getV (NODE_1) - getV (NODE_2)); + // operating points as for the vprobe setOperatingPoint ("Vr", Vr); setOperatingPoint ("Vi", Vi); //This section works just like a voltmeter } @@ -65,7 +68,7 @@ void wprobe::saveOperatingPoints (void) { void wprobe::calcOperatingPoints (void) { //Reading the current and voltage values to calculate power values - nr_complex_t Vw = getV (NODE_3) - getV (NODE_4); + nr_complex_t Vw = getV (NODE_1) - getV (NODE_2); nr_complex_t Iw = getJ (VSRC_1); nr_complex_t Sw = Vw * conj (Iw); nr_double_t VAr = real (Sw); diff --git a/qucs-test b/qucs-test index 2c34ef31cc..2b42d601d3 160000 --- a/qucs-test +++ b/qucs-test @@ -1 +1 @@ -Subproject commit 2c34ef31cc1ea00f0369e0e9dd5327895de6d8f3 +Subproject commit 2b42d601d39800daacbea023442446a29b8c595f diff --git a/qucs/qucs/components/wprobe.cpp b/qucs/qucs/components/wprobe.cpp index 899d331cdd..0e50e94eb7 100644 --- a/qucs/qucs/components/wprobe.cpp +++ b/qucs/qucs/components/wprobe.cpp @@ -51,16 +51,16 @@ wProbe::wProbe() Lines.append(new Line(-15, 8, -9, 8,QPen(Qt::red,2))); Lines.append(new Line( 9, 8, 15, 8,QPen(Qt::darkBlue,2))); -//Current Entries - Ports.append(new Port(-30, 0)); - Ports.append(new Port( 30, 0)); - //Voltage Entries Lines.append(new Line(-10, 14,-10, 20,QPen(Qt::darkBlue,2))); Lines.append(new Line( 10, 14, 10, 20,QPen(Qt::darkBlue,2))); Ports.append(new Port(-10, 20)); Ports.append(new Port( 10, 20)); +//Current Entries + Ports.append(new Port(-30, 0)); + Ports.append(new Port( 30, 0)); + //Letter V Lines.append(new Line(-3, 7 ,0, 13,QPen(Qt::darkBlue,2))); Lines.append(new Line( 0, 13, 3, 7,QPen(Qt::darkBlue,2))); From ab09147d15f263b327a2bac7197e09bbf46ef727 Mon Sep 17 00:00:00 2001 From: in3otd Date: Sat, 4 Jan 2020 13:21:05 +0100 Subject: [PATCH 3/5] Slightly refactor power probe to avoid using calcOperatingPoints(), which should be reserved for non-linear circuits. --- qucs-core/src/components/wprobe.cpp | 22 ++++++---------------- qucs-core/src/components/wprobe.h | 1 - qucs-core/src/nasolver.cpp | 8 +++++++- 3 files changed, 13 insertions(+), 18 deletions(-) diff --git a/qucs-core/src/components/wprobe.cpp b/qucs-core/src/components/wprobe.cpp index 5d61851a72..2c44e2cbd4 100644 --- a/qucs-core/src/components/wprobe.cpp +++ b/qucs-core/src/components/wprobe.cpp @@ -60,29 +60,19 @@ void wprobe::saveOperatingPoints (void) { nr_double_t Vi = imag (getV (NODE_1) - getV (NODE_2)); // operating points as for the vprobe setOperatingPoint ("Vr", Vr); - setOperatingPoint ("Vi", Vi); //This section works just like a voltmeter -} - -//For specific information regarding The Power triangle and Power factor: -//https://en.wikipedia.org/wiki/Power_factor#Definition_and_calculation + setOperatingPoint ("Vi", Vi); -void wprobe::calcOperatingPoints (void) { -//Reading the current and voltage values to calculate power values + // read current and voltage values to calculate power values nr_complex_t Vw = getV (NODE_1) - getV (NODE_2); nr_complex_t Iw = getJ (VSRC_1); nr_complex_t Sw = Vw * conj (Iw); - nr_double_t VAr = real (Sw); - nr_double_t VAi = imag (Sw); - setOperatingPoint ("VAr", VAr); - setOperatingPoint ("VAi", VAi); - - nr_double_t P = VAr; + // save P and Q instead of just S since operating points cannot hold complex values + nr_double_t P = real (Sw); + nr_double_t Q = imag (Sw); setOperatingPoint ("P", P); - - nr_double_t Q = VAi; setOperatingPoint ("Q", Q); //Power Factor calculation - setOperatingPoint ("PF", P/std::sqrt(P*P+VAi*VAi)); + setOperatingPoint ("PF", P/std::sqrt(P*P+Q*Q)); } void wprobe::initTR (void) { diff --git a/qucs-core/src/components/wprobe.h b/qucs-core/src/components/wprobe.h index 7dca2c2480..acef7aab5f 100644 --- a/qucs-core/src/components/wprobe.h +++ b/qucs-core/src/components/wprobe.h @@ -34,7 +34,6 @@ class wprobe : public qucs::circuit void initAC (void); void initTR (void); void saveOperatingPoints (void); - void calcOperatingPoints (void); }; #endif /* __WPROBE_H__ */ diff --git a/qucs-core/src/nasolver.cpp b/qucs-core/src/nasolver.cpp index e84c15521f..209ff2032a 100644 --- a/qucs-core/src/nasolver.cpp +++ b/qucs-core/src/nasolver.cpp @@ -1355,8 +1355,14 @@ void nasolver::saveResults (const std::string &volts, const std::stri circuit * root = subnet->getRoot (); for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) { + // FIXME: operating points are (ab)used in probes to hold probes data + // should be handled differently + // skip if not a probe if (!c->isProbe ()) continue; + // skip if saving subcircuit components data is not requested if (!c->getSubcircuit().empty() && !(saveOPs & SAVE_ALL)) continue; + // update probe internal values, if it's not a noise simulation + // values for noise simulation are in acsolver::saveNoiseResults() if (volts != "vn") c->saveOperatingPoints (); std::string n = createOP (c->getName (), volts); @@ -1364,7 +1370,7 @@ void nasolver::saveResults (const std::string &volts, const std::stri c->getOperatingPoint ("Vi")), f); //add watt probe data - c->calcOperatingPoints (); + // this is a big hack due to (ab)using the operating points for (auto ops: c->getOperatingPoints ()) { //It will only get values if none of the strings are 0 From 4d03a2bf8229703cc96a7d649866537339b1b116 Mon Sep 17 00:00:00 2001 From: in3otd Date: Sat, 4 Jan 2020 13:22:51 +0100 Subject: [PATCH 4/5] Move some power probe calculations --- qucs-core/src/components/wprobe.cpp | 2 -- qucs-core/src/nasolver.cpp | 40 ++++++++++++++--------------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/qucs-core/src/components/wprobe.cpp b/qucs-core/src/components/wprobe.cpp index 2c44e2cbd4..5c7fc2cd3d 100644 --- a/qucs-core/src/components/wprobe.cpp +++ b/qucs-core/src/components/wprobe.cpp @@ -71,8 +71,6 @@ void wprobe::saveOperatingPoints (void) { nr_double_t Q = imag (Sw); setOperatingPoint ("P", P); setOperatingPoint ("Q", Q); -//Power Factor calculation - setOperatingPoint ("PF", P/std::sqrt(P*P+Q*Q)); } void wprobe::initTR (void) { diff --git a/qucs-core/src/nasolver.cpp b/qucs-core/src/nasolver.cpp index 209ff2032a..31cfea0312 100644 --- a/qucs-core/src/nasolver.cpp +++ b/qucs-core/src/nasolver.cpp @@ -1369,28 +1369,26 @@ void nasolver::saveResults (const std::string &volts, const std::stri saveVariable (n, nr_complex_t (c->getOperatingPoint ("Vr"), c->getOperatingPoint ("Vi")), f); - //add watt probe data + // add watt probe data // this is a big hack due to (ab)using the operating points - for (auto ops: c->getOperatingPoints ()) - { - //It will only get values if none of the strings are 0 - //Once again most of this is adapted from Vprobe and Iprobe - operatingpoint &p = ops.second; - if (strcmp(p.getName(), "Vi") == 0) continue; - if (strcmp(p.getName(), "VAi") == 0) continue; - if (strcmp(p.getName(), "Vr") == 0) continue; - if (strcmp(p.getName(), "VAr") == 0) - { - std::string n = createOP(c->getName(), "S"); - saveVariable (n, nr_complex_t (c->getOperatingPoint ("VAr"), - c->getOperatingPoint ("VAi")), f); - continue; - } - - std::string n = createOP(c->getName(), p.getName()); - saveVariable(n, p.getValue(), f); - } - + // for specific information regarding The Power triangle and Power factor: + // https://en.wikipedia.org/wiki/Power_factor#Definition_and_calculation + if (c->hasOperatingPoint("P") && c->hasOperatingPoint("Q")) { + nr_double_t P = c->getOperatingPoint ("P"); + nr_double_t Q = c->getOperatingPoint ("Q"); + // save complex power + std::string n = createOP(c->getName(), "S"); + saveVariable (n, nr_complex_t (P, Q), f); + // save active power + n = createOP(c->getName(), "P"); + saveVariable(n, P, f); + // save reactive power + n = createOP(c->getName(), "Q"); + saveVariable(n, Q, f); + // save power factor + n = createOP(c->getName(), "PF"); + saveVariable(n, P / std::sqrt(P*P + Q*Q), f); + } } } From 8552ee12f84d3aef2b81707cc525f9b615719da0 Mon Sep 17 00:00:00 2001 From: in3otd Date: Sat, 4 Jan 2020 17:58:08 +0100 Subject: [PATCH 5/5] Update qucs-test pointer to get updated wattmeter test. --- qucs-test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qucs-test b/qucs-test index 2b42d601d3..26e15a566e 160000 --- a/qucs-test +++ b/qucs-test @@ -1 +1 @@ -Subproject commit 2b42d601d39800daacbea023442446a29b8c595f +Subproject commit 26e15a566e8f00c7baac720528d783335aad1d51