1 #ifndef _SIMULATOR_HPP_INC_
2 #define _SIMULATOR_HPP_INC_
5 #include "matplotlibcpp.h"
12 #include "MatlabEngine.hpp"
13 #include "MatlabDataArray.hpp"
56 matlabDesktop = matlab::engine::findMATLAB().size() > 0;
57 matlabEngine = matlab::engine::connectMATLAB();
58 elements.matlabEngine = matlabEngine;
64 std::regex transientRegex(R
"(^\.transient\((.+?),(.+?),(.+?)\)\s?$)");
65 std::regex graphRegex(R"(^\.graph\((.+?)\)\s?$)");
66 std::regex noDCRegex(R"(^\.nodc\s?$)");
67 std::regex outputFileRegex(R"(^\.outputFile\(\s*['"](.+?)['"]\s*\)\s?$)");
70 while (!netlist.eof()) {
71 std::getline(netlist, line);
123 if (line[1] ==
'V' && (line[2] ==
'P' || line[2] ==
'F')) {
125 if (line[2] ==
'F') {
127 "ERROR: Matlab not available at compile time");
140 if (line[1] ==
'N') {
143 }
else if (line[1] ==
'P') {
146 }
else if (line[1] ==
'M') {
147 if (line[2] ==
'N') {
151 std::cout <<
"Other Transistors not implemented yet"
155 std::cout <<
"Other Transistors not implemented yet"
166 std::regex_match(line, matches, transientRegex);
168 if (matches.size()) {
169 if constexpr (std::is_same_v<VT, double> ||
170 std::is_same_v<VT, float>) {
172 timestep = std::stod(matches.str(3));
176 static_assert(
"Unsupported Type");
181 std::regex_match(line, matches, graphRegex);
182 if (matches.size()) {
187 std::regex_match(line, matches, noDCRegex);
188 if (matches.size()) {
193 std::regex_match(line, matches, outputFileRegex);
194 if (matches.size()) {
199 std::cout <<
"Unsupported Directive" << std::endl;
235 auto simStartTime = std::chrono::high_resolution_clock::now();
236 for (
size_t nr = 0; nr < 35; nr++) {
248 auto simEndTime = std::chrono::high_resolution_clock::now();
249 auto timeTaken = std::chrono::duration_cast<std::chrono::nanoseconds>(
250 simEndTime - simStartTime)
254 std::cout <<
"DC OP in: " << timeTaken * 1e-6 <<
" ms (" << timeTaken
255 <<
" ns)" << std::endl;
266 constexpr VT convergedThreshold = 1e-12;
267 constexpr
size_t maxNR = 32;
271 auto simStartTime = std::chrono::high_resolution_clock::now();
272 for (
size_t n = 1; n <
steps; n++) {
274 for (nr = 0; nr < maxNR; nr++) {
283 maxDiff = std::max(maxDiff, singleVarDiff);
288 if (std::isnan(tempSoln(
k, 0))) {
289 std::cout <<
"Simulation Error: NaN found in solution"
295 if (maxDiff < convergedThreshold) {
303 std::cout <<
"NR terminated at: " << nr <<
" steps" << std::endl;
312 auto simEndTime = std::chrono::high_resolution_clock::now();
313 auto timeTaken = std::chrono::duration_cast<std::chrono::nanoseconds>(
314 simEndTime - simStartTime)
317 std::cout << timeTaken * 1e-6 <<
" ms (" << timeTaken <<
" ns)" << std::endl;
318 std::ofstream runtimeFile(
"RunTimes.txt", std::ofstream::app);
319 runtimeFile <<
netlistPath <<
" " << timeTaken << std::endl;
335 namespace plt = matplotlibcpp;
337 std::vector<double> timeVector(
steps);
338 std::vector<double> voltageNode(
steps);
339 for (
size_t n = 0; n <
steps; n++) {
344 plt::figure_size(1200, 780);
348 std::string filename =
"Node " + std::to_string(node) +
".png";
349 std::string filenameEps =
"Node " + std::to_string(node) +
".eps";
351 plt::save(filename.c_str());
352 plt::save(filenameEps.c_str());
364 namespace plt = matplotlibcpp;
365 plt::figure_size(1200, 780);
366 for (
auto node : nodeVec) {
368 std::vector<double> timeVector(
steps);
369 std::vector<double> voltageNode(
steps);
370 for (
size_t n = 0; n <
steps; n++) {
376 std::map<std::string, std::string> kwArgs;
377 kwArgs[
"label"] =
"Node " + std::to_string(node);
378 plt::plot(timeVector, voltageNode, kwArgs);
381 std::string name =
"Graph";
384 plt::save(name +
".png");
385 plt::save(name +
".eps");
395 matlab::data::ArrayFactory factory;
397 std::vector<std::string> varNames = {
"t"};
401 outputFile <<
"time";
407 varNames.emplace_back(std::string(
"n") + std::to_string(
i));
417 varNames.emplace_back(std::string(
"i") + std::to_string(
i));
423 auto sArray = factory.createStructArray({
solutionMat.
N, 1}, varNames);
426 outputFile << std::endl;
427 outputFile << std::setprecision(9) << n *
timestep;
430 sArray[n][varNames[0]] = factory.createArray({1, 1}, {n *
timestep});
434 outputFile <<
"\t" << std::setprecision(9) <<
solutionMat(
i, n);
437 sArray[n][varNames[
i + 1]] = factory
449 matlabEngine->setVariable(u
"solutionData", sArray,
450 matlab::engine::WorkspaceType::GLOBAL);
458 std::shared_ptr<matlab::engine::MATLABEngine> matlabEngine;
459 bool matlabDesktop =
false;
467 std::stringstream sstr(line);
473 while (!sstr.fail()) {
474 toGraph.emplace_back(nodeNum);
SourceType
The type of (voltage) source.
LineType
The first character of each line for each component type.
The main class to hold all of the relevant simulation data.
CircuitElements< VT > elements
A collection of all the circuit elements.
void simulate()
Where a lot of the magic starts. This is what runs the simulation.
Matrix< VT > scratchSpace
Preallocated space to prevent repeated allocations and deallocations. using during the leftDivide to ...
std::string outputFilePath
std::vector< std::vector< size_t > > nodesToGraph
Keeps track of the nodes to be graphed after simulation.
void printGraph(size_t node)
Outputs a single node's (or current's) time series to a graph, saving as both eps and png.
LUPair< VT > luPair
Preallocated space to prevent repeated allocations and deallocations.
void dataDump()
Simple function to dump the output of the simulator in a matlab table readable format.
SimulationEnvironment(std::string netlistPath)
Setup the simulation environment from a netlist.
void printMultipleOnGraph(std::vector< size_t > nodeVec, std::string suffix="")
Similar to printGraph, but instead can plot multiple series on the same graph.
Matrix< VT > solutionMat
Preallocated space to store the results in.
void parseGraph(std::string line)
Helper function to pull indices from graph netlist directive.
void setDCOpPoint()
a function to determine and set the DC operating point
plot(d.time, d.(nodeNum))
end if abs(real(dotprod))>rstoerst rstoerst
static void addToElements(const std::string &line, CircuitElements< T > &elements, size_t &numNodes, size_t &numCurrents, size_t &numDCCurrents)
static void addToElements(const std::string &line, CircuitElements< T > &elements, size_t &numNodes, size_t &numCurrents, size_t &numDCCurrents)
An ideal capacitor model.
static void addToElements(const std::string &line, CircuitElements< T > &elements, size_t &numNodes, size_t &numCurrents, size_t &numDCCurrents)
void updateDCStoredState(const Matrix< T > &solutionVector, size_t numCurrents)
Updates the components based on their DC value. Applies to dynamic and non-linear components.
std::vector< std::shared_ptr< Component< T > > > dynamicElements
A container to store the dynamic components.
std::vector< std::shared_ptr< Component< T > > > staticElements
A container to store the static components.
Stamp< T > staticStamp
Preallocated stamp. Used for caching between loop iterations. Static stamps will only be generated on...
bool staticStampIsFresh
A variable used to track if the cached stamp is current.
Stamp< T > & generateNonLinearStamp(const Matrix< T > &solutionMatrix, const size_t currentSolutionIndex, T timestep)
Obtains the dynamic stamp, then adds dynamic components to it.
std::vector< std::shared_ptr< Component< T > > > nonLinearElements
A container to store the Non-Linear components.
void setNewStampSize(size_t numNodes, size_t numCurrents, size_t numDCCurrents=0)
Updates the size of all stamps.
bool nonLinearStampIsFresh
A variable used to track if the cached stamp is current.
Stamp< T > & generateDCStamp(const Matrix< T > &solutionVector, size_t numCurrents)
Generates the complete DC stamp.
void updateTimeStep(const Matrix< T > &solutionMatrix, const size_t currentSolutionIndex, T timestep)
Updates the components at the end of each time step. Applies to dynamic and non-linear components.
static void addToElements(const std::string &line, CircuitElements< T > &elements, size_t &numNodes, size_t &numCurrents, size_t &numDCCurrents)
An ebbers moll diode model.
static void addToElements(const std::string &line, CircuitElements< T > &elements, size_t &numNodes, size_t &numCurrents, size_t &numDCCurrents)
static void addToElements(const std::string &line, CircuitElements< T > &elements, size_t &numNodes, size_t &numCurrents, size_t &numDCCurrents)
static void addToElements(const std::string &line, CircuitElements< T > &elements, size_t &numNodes, size_t &numCurrents, size_t &numDCCurrents)
static void addToElements(const std::string &line, CircuitElements< T > &elements, size_t &numNodes, size_t &numCurrents, size_t &numDCCurrents)
static void addToElements(const std::string &line, CircuitElements< T > &elements, size_t &numNodes, size_t &numCurrents, size_t &numDCCurrents)
static void addToElements(const std::string &line, CircuitElements< T > &elements, size_t &numNodes, size_t &numCurrents, size_t &numDCCurrents)
A DTIR based model of an s-parameter block.
static void addToElements(const std::string &line, CircuitElements< T > &elements, size_t &numNodes, size_t &numCurrents, size_t &numDCCurrents)
static void addToElements(const std::string &line, CircuitElements< T > &elements, size_t &numNodes, size_t &numCurrents, size_t &numDCCurrents)
A sinusoidal voltage source model.
A time series voltage source model.
static void addToElements(const std::string &line, CircuitElements< T > &elements, size_t &numNodes, size_t &numCurrents, size_t &numDCCurrents)