void nasolver<nr_type_t>::createCMatrix (void) { int N = countNodes (); int M = countVoltageSources (); circuit * vs; struct nodelist_t * n; nr_type_t val; // go through each voltage sources (second dimension) for (int r = 0; r < M; r++) { vs = findVoltageSource (r); // go through each node (first dimension) for (int c = 0; c < N; c++) { val = 0.0; n = nlist->getNode (c); for (auto ¤t: *n) { // is voltage source connected to node ? if (current->getCircuit () == vs) { val += MatVal (vs->getC (r, current->getPort ())); } } // put value into C matrix A->set (r + N, c, val); } } }
void nasolver<nr_type_t>::solve_pre (void) { // create node list, enumerate nodes and voltage sources #if DEBUG logprint (LOG_STATUS, "NOTIFY: %s: creating node list for %s analysis\n", getName (), desc.c_str()); #endif nlist = new nodelist (subnet); nlist->assignNodes (); assignVoltageSources (); #if DEBUG && 0 nlist->print (); #endif // create matrix, solution vector and right hand side vector int M = countVoltageSources (); int N = countNodes (); if (A != NULL) delete A; A = new tmatrix<nr_type_t> (M + N); if (z != NULL) delete z; z = new tvector<nr_type_t> (N + M); if (x != NULL) delete x; x = new tvector<nr_type_t> (N + M); #if DEBUG logprint (LOG_STATUS, "NOTIFY: %s: solving %s netlist\n", getName (), desc.c_str()); #endif }
void nasolver<nr_type_t>::storeSolution (void) { // cleanup solution previously solution.clear (); int r; int N = countNodes (); int M = countVoltageSources (); // store all nodes except reference node for (r = 0; r < N; r++) { struct nodelist_t * n = nlist->getNode (r); nr_type_t gr = x->get (r); qucs::naentry<nr_type_t> entry(gr, 0); solution.insert({{n->name, entry }}); } // store all branch currents of voltage sources for (r = 0; r < M; r++) { circuit * vs = findVoltageSource (r); int vn = r - vs->getVoltageSource () + 1; nr_type_t xg = x->get (r + N); qucs::naentry<nr_type_t> entry(xg, vn); solution.insert({{vs->getName (), entry}}); } }
void nasolver<nr_type_t>::recallSolution (void) { int r; int N = countNodes (); int M = countVoltageSources (); // store all nodes except reference node for (r = 0; r < N; r++) { struct nodelist_t * n = nlist->getNode (r); auto na = solution.find(n->name); if (na != solution.end()) if ((*na).second.current == 0) x->set (r, (*na).second.value); } // store all branch currents of voltage sources for (r = 0; r < M; r++) { circuit * vs = findVoltageSource (r); int vn = r - vs->getVoltageSource () + 1; auto na = solution.find(vs->getName ()); if (na != solution.end()) if ((*na).second.current == vn) x->set (r + N, (*na).second.value); } }
void e_trsolver::getsolution (double * lastsol) { int N = countNodes (); int M = countVoltageSources (); // copy solution for (int r = 0; r < N + M; r++) { lastsol[r] = real(x->get(r)); } }
void nasolver<nr_type_t>::saveBranchCurrents (void) { int N = countNodes (); int M = countVoltageSources (); circuit * vs; // save all branch currents of voltage sources for (int r = 0; r < M; r++) { vs = findVoltageSource (r); vs->setJ (r, x->get (r + N)); } }
void nasolver<nr_type_t>::createEVector (void) { int N = countNodes (); int M = countVoltageSources (); nr_type_t val; circuit * vs; // go through each voltage source for (int r = 0; r < M; r++) { vs = findVoltageSource (r); val = MatVal (vs->getE (r)); // put value into e vector z->set (r + N, val); } }
void nasolver<nr_type_t>::createDMatrix (void) { int M = countVoltageSources (); int N = countNodes (); circuit * vsr, * vsc; nr_type_t val; for (int r = 0; r < M; r++) { vsr = findVoltageSource (r); for (int c = 0; c < M; c++) { vsc = findVoltageSource (c); val = 0.0; if (vsr == vsc) { val = MatVal (vsr->getD (r, c)); } A->set (r + N, c + N, val); } } }
/* This function runs the AC noise analysis. It saves its results in the 'xn' vector. */ void acsolver::solve_noise (void) { int N = countNodes (); int M = countVoltageSources (); // save usual AC results tvector<nr_complex_t> xsave = *x; // create the Cy matrix createNoiseMatrix (); // create noise result vector if necessary if (xn == NULL) xn = new tvector<nr_double_t> (N + M); // temporary result vector for transimpedances tvector<nr_complex_t> zn = tvector<nr_complex_t> (N + M); // create the MNA matrix once again and LU decompose the adjoint matrix createMatrix (); A->transpose (); eqnAlgo = ALGO_LU_FACTORIZATION_CROUT; runMNA (); // ensure skipping LU decomposition updateMatrix = 0; convHelper = CONV_None; eqnAlgo = ALGO_LU_SUBSTITUTION_CROUT; // compute noise voltage for each node (and voltage source) for (int i = 0; i < N + M; i++) { z->set (0); z->set (i, -1); // modify right hand side appropriately runMNA (); // solve zn = *x; // save transimpedance vector // compute actual noise voltage xn->set (i, sqrt (real (scalar (zn * (*C), conj (zn))))); } // restore usual AC results *x = xsave; }
int nasolver<nr_type_t>::checkConvergence (void) { int N = countNodes (); int M = countVoltageSources (); nr_double_t v_abs, v_rel, i_abs, i_rel; int r; // check the nodal voltage changes against the allowed absolute // and relative tolerance values for (r = 0; r < N; r++) { v_abs = abs (x->get (r) - xprev->get (r)); v_rel = abs (x->get (r)); if (v_abs >= vntol + reltol * v_rel) return 0; if (!convHelper) { i_abs = abs (z->get (r) - zprev->get (r)); i_rel = abs (z->get (r)); if (i_abs >= abstol + reltol * i_rel) return 0; } } for (r = 0; r < M; r++) { i_abs = abs (x->get (r + N) - xprev->get (r + N)); i_rel = abs (x->get (r + N)); if (i_abs >= abstol + reltol * i_rel) return 0; if (!convHelper) { v_abs = abs (z->get (r + N) - zprev->get (r + N)); v_rel = abs (z->get (r + N)); if (v_abs >= vntol + reltol * v_rel) return 0; } } return 1; }
void nasolver<nr_type_t>::createMatrix (void) { /* Generate the A matrix. The A matrix consists of four (4) minor matrices in the form +- -+ A = | G B | | C D | +- -+. Each of these minor matrices is going to be generated here. */ if (updateMatrix) { createGMatrix (); createBMatrix (); createCMatrix (); createDMatrix (); } /* Adjust G matrix if requested. */ if (convHelper == CONV_GMinStepping) { int N = countNodes (); int M = countVoltageSources (); for (int n = 0; n < N + M; n++) { A->set (n, n, A->get (n, n) + gMin); } } /* Generate the z Matrix. The z Matrix consists of two (2) minor matrices in the form +- -+ z = | i | | e | +- -+. Each of these minor matrices is going to be generated here. */ createZVector (); }
/* The function computes the final noise results and puts them into the output dataset. */ void acsolver::saveNoiseResults (vector * f) { int N = countNodes (); int M = countVoltageSources (); for (int r = 0; r < N + M; r++) { // renormalise the results x->set (r, fabs (xn->get (r) * sqrt (kB * T0))); } // apply probe data circuit * root = subnet->getRoot (); for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) { if (!c->isProbe ()) continue; int np, nn; nr_double_t vp, vn; np = getNodeNr (c->getNode (NODE_1)->getName ()); vp = np > 0 ? xn->get (np - 1) : 0.0; nn = getNodeNr (c->getNode (NODE_2)->getName ()); vn = nn > 0 ? xn->get (nn - 1) : 0.0; c->setOperatingPoint ("Vr", fabs ((vp - vn) * sqrt (kB * T0))); c->setOperatingPoint ("Vi", 0.0); } saveResults ("vn", "in", 0, f); }
void nasolver<nr_type_t>::createNoiseMatrix (void) { int pr, pc, N = countNodes (); int M = countVoltageSources (); struct nodelist_t * n; nr_type_t val; int r, c, ri, ci; struct nodelist_t * nr, * nc; circuit * ct; // create new Cy matrix if necessary if (C != NULL) delete C; C = new tmatrix<nr_type_t> (N + M); // go through each column of the Cy matrix for (c = 0; c < N; c++) { nc = nlist->getNode (c); // go through each row of the Cy matrix for (r = 0; r < N; r++) { nr = nlist->getNode (r); val = 0.0; // sum up the noise-correlation of each connected circuit for (auto & currentnc: *nc) /* a = 0; a < nc->size(); a++ */ for (auto ¤tnr : *nr) /* b = 0; b < nr->size(); b++) */ if (currentnc->getCircuit () == currentnr->getCircuit ()) { ct = currentnc->getCircuit (); pc = currentnc->getPort (); pr = currentnr->getPort (); val += MatVal (ct->getN (pr, pc)); } // put value into Cy matrix C->set (r, c, val); } } // go through each additional voltage source and put coefficients into // the noise current correlation matrix circuit * vsr, * vsc; for (r = 0; r < M; r++) { vsr = findVoltageSource (r); for (c = 0; c < M; c++) { vsc = findVoltageSource (c); val = 0.0; if (vsr == vsc) { ri = vsr->getSize () + r - vsr->getVoltageSource (); ci = vsc->getSize () + c - vsc->getVoltageSource (); val = MatVal (vsr->getN (ri, ci)); } C->set (r + N, c + N, val); } } // go through each additional voltage source for (r = 0; r < M; r++) { vsr = findVoltageSource (r); // go through each node for (c = 0; c < N; c++) { val = 0.0; n = nlist->getNode (c); for (auto ¤tn: *n) /*i = 0; i < n->size(); i++ )*/ { // is voltage source connected to node ? if (currentn->getCircuit () == vsr) { ri = vsr->getSize () + r - vsr->getVoltageSource (); ci = currentn->getPort (); val += MatVal (vsr->getN (ri, ci)); } } // put value into Cy matrix C->set (r + N, c, val); } } // go through each voltage source for (c = 0; c < M; c++) { vsc = findVoltageSource (c); // go through each node for (r = 0; r < N; r++) { val = 0.0; n = nlist->getNode (r); for (auto & currentn: *n)/*i = 0; i < n->size(); i++)*/ { // is voltage source connected to node ? if (currentn->getCircuit () == vsc) { ci = vsc->getSize () + c - vsc->getVoltageSource (); ri = currentn->getPort (); val += MatVal (vsc->getN (ri, ci)); } } // put value into Cy matrix C->set (r, c + N, val); } } }
int nasolver<nr_type_t>::getM() { return countVoltageSources (); }
void nasolver<nr_type_t>::saveResults (const std::string &volts, const std::string &s, int saveOPs, qucs::vector * f) { int N = countNodes (); int M = countVoltageSources (); // add node voltage variables if (!volts.empty()) { for (int r = 0; r < N; r++) { std::string n = createV (r, volts, saveOPs); if(!n.empty()) { saveVariable (n, x->get (r), f); } } } // add branch current variables if (!amps.empty()) { for (int r = 0; r < M; r++) { std::string n = createI (r, amps, saveOPs); if (!n.empty()) { saveVariable (n, x->get (r + N), f); } } } // add voltage probe data if (!volts.empty()) { circuit * root = subnet->getRoot (); for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) { if (!c->isProbe ()) continue; if (!c->getSubcircuit().empty() && !(saveOPs & SAVE_ALL)) continue; if (volts != "vn") c->saveOperatingPoints (); std::string n = createOP (c->getName (), volts); saveVariable (n, nr_complex_t (c->getOperatingPoint ("Vr"), c->getOperatingPoint ("Vi")), f); } } // save operating points of non-linear circuits if requested if (saveOPs & SAVE_OPS) { circuit * root = subnet->getRoot (); for (circuit * c = root; c != NULL; c = (circuit *) c->getNext ()) { if (!c->isNonLinear ()) continue; if (!c->getSubcircuit ().empty() && !(saveOPs & SAVE_ALL)) continue; c->calcOperatingPoints (); for (auto ops: c->getOperatingPoints ()) { operatingpoint &p = ops.second; std::string n = createOP (c->getName (), p.getName ()); saveVariable (n, p.getValue (), f); } } } }