Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ac simulation #4076

Draft
wants to merge 45 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
c00d04f
Update Bug.md
failiz Feb 5, 2024
0d58769
fixes bug with u simbol. The u symbol should be replaced by a u in ng…
failiz Mar 8, 2023
115ba42
split different options of the spice circuit in sepate lines. Added i…
failiz Mar 12, 2023
600a144
towards transitoty simulations (still work in progress)
failiz Mar 13, 2023
7de4eb7
allow to change properties of the pulse and sinusoidal power supplies
failiz Mar 22, 2023
46bccb8
modified resources.xml to adapt to the new moduleIDs of the new power…
failiz Sep 20, 2023
fc03cb0
added number of cycles as a property to change in pulse power supplies
failiz Sep 20, 2023
be8fac1
fixed bug in loop, removed setElementId to show all the svg elements
failiz Sep 20, 2023
93eedcc
working towards the aligning the oscilloscope signals with the oscill…
failiz Sep 29, 2023
8db3f72
towards multiple oscilloscope in the simulation. Added offset marks t…
failiz Oct 3, 2023
5c2924f
if the negative terminal of a power supply is not connected and there…
failiz Oct 3, 2023
00abb32
handles the 4 channels and adds noise to the signals if the com probe…
failiz Oct 3, 2023
1a4378a
better name for a property
failiz Oct 3, 2023
af0c891
improved oscilloscope in sch view and added axis labels
failiz Oct 4, 2023
a36833f
added axis scale in the oscilloscope for the sch view
failiz Oct 5, 2023
105fd7b
added control of the horizontal simulation to the analysis without lo…
failiz Oct 5, 2023
af0414f
added handling of horizontal positions for multiple oscilloscopes
failiz Oct 6, 2023
433a51a
allow to introduce negative numbers in the properties of parts. This …
failiz Oct 7, 2023
dab2f73
Show the result of the simulation at the end time, not at the startin…
failiz Oct 7, 2023
6e2c3db
In sch view, added the name of the axes to the oscilloscope.
failiz Oct 10, 2023
47ac612
updated position of the labels and axes in the oscilloscope when simu…
failiz Oct 10, 2023
af9e5f6
added properties for the triangular wavegenerator
failiz Oct 10, 2023
b848df3
added some examples for the transitory analysis
failiz Oct 10, 2023
8e1440a
added 555 example
failiz Dec 4, 2023
082736d
Finish wiring of the BB view of the 555 example
failiz Dec 5, 2023
8e7dcd3
added two sketches as examples of the transient simulation
failiz Dec 5, 2023
3ed26cb
fixed oscilloscope text string (too many arguments)
failiz Dec 7, 2023
bfbacda
fixed bug when properties contain capital letters. If so, the propert…
failiz Dec 7, 2023
d258cf5
imprved handling of properties with capital letters
failiz Dec 7, 2023
7684fbd
improved simulation error dialog. Now, there is a scroll area for the…
failiz Dec 7, 2023
a10fdb5
show the right channel in the axis of the oscilloscope (SCH view)
failiz Dec 7, 2023
ef83cec
added properties of the transformer so that users can modifiy its pro…
failiz Dec 7, 2023
3dead91
fixed error when a property does not have symbol: If there is no symb…
failiz Dec 7, 2023
bcf5960
calculate the com voltage at the oscilloscope when there is a wire co…
failiz Dec 8, 2023
cccd30e
First implementation using an animation of the results of the simulat…
failiz Dec 9, 2023
2701e68
now all parts get voltages and currents depending on simulation time
failiz Dec 10, 2023
5d3fc49
Revert elcos
Feb 13, 2024
560f296
Added functionality to set sim frequency and save it to project.
Dec 15, 2023
a70ce54
added the simulation properties to the project properties menu
failiz Feb 18, 2024
4fa9783
added simulator message (sim time) at the top right corner when simul…
failiz Feb 20, 2024
9eb7edb
Added sawtooth generator and modified properties of the triangular si…
failiz Apr 6, 2024
1712697
changed ac poewer supply to sine, added generic pulse power supply an…
failiz Apr 7, 2024
234eb9a
make the transitory simulation not blocking. Results will be shown wh…
failiz Apr 7, 2024
1c56001
added exception for the oscilloscope as it does not have a pcb view
failiz Apr 7, 2024
39b0dad
Load analog code model to have access to current limiting devices for…
failiz May 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
now all parts get voltages and currents depending on simulation time
  • Loading branch information
failiz committed Feb 11, 2024
commit 2701e68d5d6f082758045338128a514f3794bc9b
104 changes: 53 additions & 51 deletions src/simulation/simulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -390,43 +390,43 @@ void Simulator::updateParts(QSet<ItemBase *> itemBases, int timeStep) {
QString family = part->family().toLower();

if (family.contains("capacitor")) {
updateCapacitor(part);
updateCapacitor(timeStep, part);
continue;
}
if (family.contains("diode")) {
updateDiode(part);
updateDiode(timeStep, part);
continue;
}
if (family.contains("led")) {
updateLED(part);
updateLED(timeStep, part);
continue;
}
if (family.contains("resistor")) {
updateResistor(part);
updateResistor(timeStep, part);
continue;
}
if (family.contains("multimeter")) {
updateMultimeter(part);
updateMultimeter(timeStep, part);
continue;
}
if (family.contains("dc motor")) {
updateDcMotor(part);
updateDcMotor(timeStep, part);
continue;
}
if (family.contains("line sensor") || family.contains("distance sensor")) {
updateIRSensor(part);
updateIRSensor(timeStep, part);
continue;
}
if (family.contains("battery") || family.contains("voltage source")) {
updateBattery(part);
updateBattery(timeStep, part);
continue;
}
if (family.contains("potentiometer") || family.contains("sparkfun trimpot")) {
updatePotentiometer(part);
updatePotentiometer(timeStep, part);
continue;
}
if (family.contains("oscilloscope")) {
updateOscilloscope(part, timeStep);
updateOscilloscope(timeStep, part);
continue;
}
}
Expand Down Expand Up @@ -593,12 +593,14 @@ void Simulator::removeSimItems(QList<QGraphicsItem *> items) {
* @param[in] defaultValue value to return on empty vector
* @returns the first vector element or the given default value
*/
double Simulator::getVectorValueOrDefault(const std::string & vecName, double defaultValue) {
double Simulator::getVectorValueOrDefault(unsigned long timeStep, const std::string & vecName, double defaultValue) {
auto vecInfo = m_simulator->getVecInfo(vecName);
if (vecInfo.empty()) {
if (vecInfo.empty()) {
return defaultValue;
} else {
return vecInfo[vecInfo.size()-1];
if (timeStep < 0 || timeStep >= vecInfo.size())
return defaultValue;
return vecInfo[timeStep];
}
}

Expand All @@ -608,7 +610,7 @@ double Simulator::getVectorValueOrDefault(const std::string & vecName, double de
* @param[in] c1 the second connector
* @returns the voltage between the connector c0 and c1
*/
double Simulator::calculateVoltage(ConnectorItem * c0, ConnectorItem * c1) {
double Simulator::calculateVoltage(unsigned long timeStep, ConnectorItem * c0, ConnectorItem * c1) {
int net0 = m_connector2netHash.value(c0);
int net1 = m_connector2netHash.value(c1);

Expand All @@ -621,12 +623,12 @@ double Simulator::calculateVoltage(ConnectorItem * c0, ConnectorItem * c1) {
if (net0 != 0) {
auto vecInfo = m_simulator->getVecInfo(net0str.toStdString());
if (vecInfo.empty()) return 0.0;
volt0 = vecInfo[0];
volt0 = vecInfo[timeStep];
}
if (net1 != 0) {
auto vecInfo = m_simulator->getVecInfo(net1str.toStdString());
if (vecInfo.empty()) return 0.0;
volt1 = vecInfo[0];
volt1 = vecInfo[timeStep];
}
return volt0-volt1;
}
Expand Down Expand Up @@ -767,13 +769,13 @@ double Simulator::getMaxPropValue(ItemBase *part, QString property) {
* @param[in] subpartName The name of the subpart. Leave it empty if there is only one spice line for the device. Otherwise, give the suffix of the subpart.
* @returns the power that a part is consuming/producing.
*/
double Simulator::getPower(ItemBase* part, QString subpartName) {
double Simulator::getPower(unsigned long timeStep, ItemBase* part, QString subpartName) {
//TODO: Handle devices that do not return the power
QString instanceStr = part->instanceTitle().toLower();
instanceStr.append(subpartName.toLower());
instanceStr.prepend("@");
instanceStr.append("[p]");
return getVectorValueOrDefault(instanceStr.toStdString(), 0.0);
return getVectorValueOrDefault(timeStep, instanceStr.toStdString(), 0.0);
}

/**
Expand All @@ -787,7 +789,7 @@ double Simulator::getPower(ItemBase* part, QString subpartName) {
* @param[in] subpartName The name of the subpart. Leave it empty if there is only one spice line for the device. Otherwise, give the suffix of the subpart.
* @returns the current that a part is consuming/producing.
*/
double Simulator::getCurrent(ItemBase* part, QString subpartName) {
double Simulator::getCurrent(unsigned long timeStep, ItemBase* part, QString subpartName) {
QString instanceStr = part->instanceTitle().toLower();
instanceStr.append(subpartName.toLower());

Expand Down Expand Up @@ -820,15 +822,15 @@ double Simulator::getCurrent(ItemBase* part, QString subpartName) {
break;

}
return getVectorValueOrDefault(instanceStr.toStdString(), 0.0);
return getVectorValueOrDefault(timeStep, instanceStr.toStdString(), 0.0);
}

/**
* Returns the current that flows through a transistor.
* @param[in] spicePartName The name of the spice transistor.
* @returns the current that the transistor is sinking/sourcing.
*/
double Simulator::getTransistorCurrent(QString spicePartName, TransistorLeg leg) {
double Simulator::getTransistorCurrent(unsigned long timeStep, QString spicePartName, TransistorLeg leg) {
if(spicePartName.at(0).toLower()!=QChar('q')) {
//TODO: Add tr()
throw QString("Error getting the current of a transistor. The device is not a transistor, its first letter is not a Q. Name: %1").arg(spicePartName);
Expand All @@ -848,7 +850,7 @@ double Simulator::getTransistorCurrent(QString spicePartName, TransistorLeg leg)
throw QString("Error getting the current of a transistor. The transistor leg or property is not recognized. Leg: %1").arg(leg);
}

return getVectorValueOrDefault(spicePartName.toStdString(), 0.0);
return getVectorValueOrDefault(timeStep, spicePartName.toStdString(), 0.0);
}

/**
Expand Down Expand Up @@ -1015,9 +1017,9 @@ void Simulator::removeItemsToBeSimulated(QList<QGraphicsItem*> & parts) {
* Updates and checks a diode. Checks that the power is less than the maximum power.
* @param[in] diode A part that is going to be checked and updated.
*/
void Simulator::updateDiode(ItemBase * diode) {
void Simulator::updateDiode(unsigned long timeStep, ItemBase * diode) {
double maxPower = getMaxPropValue(diode, "power");
double power = getPower(diode);
double power = getPower(timeStep, diode);
if (power > maxPower) {
drawSmoke(diode);
}
Expand All @@ -1028,15 +1030,15 @@ void Simulator::updateDiode(ItemBase * diode) {
* and updates the brightness of the LED in the breadboard view.
* @param[in] part An LED that is going to be checked and updated.
*/
void Simulator::updateLED(ItemBase * part) {
void Simulator::updateLED(unsigned long timeStep, ItemBase * part) {
LED* led = dynamic_cast<LED *>(part);
if (led) {
//Check if this an RGB led
QString rgbString = part->getProperty("rgb");

if (rgbString.isEmpty()) {
// Just one LED
double curr = getCurrent(part);
double curr = getCurrent(timeStep, part);
double maxCurr = getMaxPropValue(part, "current");

std::cout << "LED Current: " <<curr<<std::endl;
Expand All @@ -1050,9 +1052,9 @@ void Simulator::updateLED(ItemBase * part) {
}
} else {
// The part is an RGB LED
double currR = getCurrent(part, "R");
double currG = getCurrent(part, "G");
double currB = getCurrent(part, "B");
double currR = getCurrent(timeStep, part, "R");
double currG = getCurrent(timeStep, part, "G");
double currB = getCurrent(timeStep, part, "B");
double curr = std::max({currR, currG, currB});
double maxCurr = getMaxPropValue(part, "current");

Expand All @@ -1077,7 +1079,7 @@ void Simulator::updateLED(ItemBase * part) {
* and reverse voltage in electrolytic and tantalum capacitors (unidirectional capacitors).
* @param[in] part A capacitor that is going to be checked and updated.
*/
void Simulator::updateCapacitor(ItemBase * part) {
void Simulator::updateCapacitor(unsigned long timeStep, ItemBase * part) {
QString family = part->getProperty("family").toLower();

ConnectorItem * negLeg, * posLeg;
Expand All @@ -1090,7 +1092,7 @@ void Simulator::updateCapacitor(ItemBase * part) {
return;

double maxV = getMaxPropValue(part, "voltage");
double v = calculateVoltage(posLeg, negLeg);
double v = calculateVoltage(timeStep, posLeg, negLeg);
std::cout << "MaxVoltage of the capacitor: " << maxV << std::endl;
std::cout << "Capacitor voltage is : " << QString("%1").arg(v).toStdString() << std::endl;

Expand All @@ -1111,9 +1113,9 @@ void Simulator::updateCapacitor(ItemBase * part) {
* Updates and checks a resistor. Checks that the power is less than the maximum power.
* @param[in] part A resistor that is going to be checked and updated.
*/
void Simulator::updateResistor(ItemBase * part) {
void Simulator::updateResistor(unsigned long timeStep, ItemBase * part) {
double maxPower = getMaxPropValue(part, "power");
double power = getPower(part);
double power = getPower(timeStep, part);
std::cout << "Power: " << power <<std::endl;
if (power > maxPower) {
drawSmoke(part);
Expand All @@ -1125,10 +1127,10 @@ void Simulator::updateResistor(ItemBase * part) {
* for the two resistors "A" and "B".
* @param[in] part A potentiometer that is going to be checked and updated.
*/
void Simulator::updatePotentiometer(ItemBase * part) {
void Simulator::updatePotentiometer(unsigned long timeStep, ItemBase * part) {
double maxPower = getMaxPropValue(part, "power");
double powerA = getPower(part, "A"); //power through resistor A
double powerB = getPower(part, "B"); //power through resistor B
double powerA = getPower(timeStep, part, "A"); //power through resistor A
double powerB = getPower(timeStep, part, "B"); //power through resistor B
double power = powerA + powerB;
if (power > maxPower) {
drawSmoke(part);
Expand All @@ -1139,12 +1141,12 @@ void Simulator::updatePotentiometer(ItemBase * part) {
* Updates and checks a battery. Checks that there are no short circuits.
* @param[in] part A battery that is going to be checked and updated.
*/
void Simulator::updateBattery(ItemBase * part) {
void Simulator::updateBattery(unsigned long timeStep, ItemBase * part) {
double voltage = getMaxPropValue(part, "voltage");
double resistance = getMaxPropValue(part, "internal resistance");
double safetyMargin = 0.1; //TODO: This should be adjusted
double maxCurrent = voltage/resistance * safetyMargin;
double current = getCurrent(part); //current that the battery delivers
double current = getCurrent(timeStep, part); //current that the battery delivers
std::cout << "Battery: voltage=" << voltage << ", resistance=" << resistance <<std::endl;
std::cout << "Battery: MaxCurr=" << maxCurrent << ", Curr=" << current <<std::endl;
if (abs(current) > maxCurrent) {
Expand All @@ -1162,7 +1164,7 @@ bool Simulator::isSimulating()
* and that the current of the output is less than the maximum.
* @param[in] part A IR sensor that is going to be checked and updated.
*/
void Simulator::updateIRSensor(ItemBase * part) {
void Simulator::updateIRSensor(unsigned long timeStep, ItemBase * part) {
double maxV = getMaxPropValue(part, "voltage (max)");
double minV = getMaxPropValue(part, "voltage (min)");
double maxIout = getMaxPropValue(part, "max output current");
Expand All @@ -1184,16 +1186,16 @@ void Simulator::updateIRSensor(ItemBase * part) {
if(!gnd || !vcc || !out )
return;

double v = calculateVoltage(vcc, gnd); //voltage applied to the motor
double v = calculateVoltage(timeStep, vcc, gnd); //voltage applied to the motor
double i;
if (part->family().contains("line sensor")) {
//digital sensor (push-pull output)
QString spicename = part->instanceTitle().toLower();
spicename.prepend("q");
i = getTransistorCurrent(spicename, COLLECTOR); //voltage applied to the motor
i = getTransistorCurrent(timeStep, spicename, COLLECTOR); //voltage applied to the motor
} else {
//analogue sensor (modelled by a voltage source and a resistor)
i = getCurrent(part, "a"); //voltage applied to the motor
i = getCurrent(timeStep, part, "a"); //voltage applied to the motor
}
std::cout << "IR sensor Max Iout: " << maxIout << ", current Iout " << i << std::endl;
std::cout << "IR sensor Max V: " << maxV << ", current V " << v << std::endl;
Expand All @@ -1209,7 +1211,7 @@ void Simulator::updateIRSensor(ItemBase * part) {
* TODO: The number of arrows are proportional to the voltage applied.
* @param[in] part A DC motor that is going to be checked and updated.
*/
void Simulator::updateDcMotor(ItemBase * part) {
void Simulator::updateDcMotor(unsigned long timeStep, ItemBase * part) {
double maxV = getMaxPropValue(part, "voltage (max)");
double minV = getMaxPropValue(part, "voltage (min)");
std::cout << "Motor1: " << std::endl;
Expand All @@ -1222,7 +1224,7 @@ void Simulator::updateDcMotor(ItemBase * part) {
if(!terminal1 || !terminal2 )
return;

double v = calculateVoltage(terminal1, terminal2); //voltage applied to the motor
double v = calculateVoltage(timeStep, terminal1, terminal2); //voltage applied to the motor
if (abs(v) > maxV) {
drawSmoke(part);
return;
Expand Down Expand Up @@ -1279,7 +1281,7 @@ void Simulator::updateDcMotor(ItemBase * part) {
* Calculates the parameter to measure and updates the display of the multimeter.
* @param[in] part A multimeter that is going to be checked and updated.
*/
void Simulator::updateMultimeter(ItemBase * part) {
void Simulator::updateMultimeter(unsigned long timeStep, ItemBase * part) {
QString variant = part->getProperty("variant").toLower();
ConnectorItem * comProbe = nullptr, * vProbe = nullptr, * aProbe = nullptr;
QList<ConnectorItem *> probes = part->cachedConnectorItems();
Expand All @@ -1306,7 +1308,7 @@ void Simulator::updateMultimeter(ItemBase * part) {
}
if(comProbe->connectedToWires() && vProbe->connectedToWires()) {
std::cout << "Multimeter (v_dc) connected with two terminals. " << std::endl;
double v = calculateVoltage(vProbe, comProbe);
double v = calculateVoltage(timeStep, vProbe, comProbe);
updateMultimeterScreen(part, v);
}
return;
Expand All @@ -1317,7 +1319,7 @@ void Simulator::updateMultimeter(ItemBase * part) {
updateMultimeterScreen(part, "ERR");
return;
}
updateMultimeterScreen(part, getCurrent(part));
updateMultimeterScreen(part, getCurrent(timeStep, part));
return;
} else if (variant.compare("ohmmeter") == 0) {
std::cout << "Ohmmeter found. " << std::endl;
Expand All @@ -1326,8 +1328,8 @@ void Simulator::updateMultimeter(ItemBase * part) {
updateMultimeterScreen(part, "ERR");
return;
}
double v = calculateVoltage(vProbe, comProbe);
double a = getCurrent(part);
double v = calculateVoltage(timeStep, vProbe, comProbe);
double a = getCurrent(timeStep, part);
double r = abs(v/a);
std::cout << "Ohmmeter: Volt: " << v <<", Curr: " << a <<", Ohm: " << r << std::endl;
updateMultimeterScreen(part, r);
Expand All @@ -1340,7 +1342,7 @@ void Simulator::updateMultimeter(ItemBase * part) {
* Calculates the parameter to measure and updates the display of the multimeter.
* @param[in] part An oscilloscope that is going to be checked and updated.
*/
void Simulator::updateOscilloscope(ItemBase * part, int currTimeStep) {
void Simulator::updateOscilloscope(unsigned long timeStep, ItemBase * part) {
std::cout << "updateOscilloscope: " << std::endl;
ConnectorItem * comProbe = nullptr, * v1Probe = nullptr, * v2Probe = nullptr, * v3Probe = nullptr, * v4Probe = nullptr;
QList<ConnectorItem *> probes = part->cachedConnectorItems();
Expand Down Expand Up @@ -1423,7 +1425,7 @@ void Simulator::updateOscilloscope(ItemBase * part, int currTimeStep) {

//Draw the signal
QString pathId = QString("ch%1-path").arg(channel+1);
QString signalPath = generateSvgPath(v, vCom, currTimeStep, pathId, m_simStartTime, m_simStepTime, hPos, timeDiv, divisionSize/voltsDiv[channel], chOffsets[channel],
QString signalPath = generateSvgPath(v, vCom, timeStep, pathId, m_simStartTime, m_simStepTime, hPos, timeDiv, divisionSize/voltsDiv[channel], chOffsets[channel],
screenHeight, screenWidth, lineColor[channel], "20");
bbSvg += signalPath.arg(bbScreenOffsetX).arg(bbScreenOffsetY);
schSvg += signalPath.arg(schScreenOffsetX).arg(schScreenOffsetY);
Expand Down
30 changes: 15 additions & 15 deletions src/simulation/simulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -67,25 +67,25 @@ public slots:
QChar getDeviceType (ItemBase*);
double getMaxPropValue(ItemBase*, QString);
QString getSymbol(ItemBase*, QString);
double getVectorValueOrDefault(const std::string & vecName, double defaultValue);
double calculateVoltage(ConnectorItem *, ConnectorItem *);
double getVectorValueOrDefault(unsigned long timeStep, const std::string & vecName, double defaultValue);
double calculateVoltage(unsigned long, ConnectorItem *, ConnectorItem *);
std::vector<double> voltageVector(ConnectorItem *);
QString generateSvgPath(std::vector<double>, std::vector<double>, int, QString, double, double, double, double, double, double, double, double, QString, QString);
double getCurrent(ItemBase*, QString subpartName="");
double getTransistorCurrent(QString spicePartName, TransistorLeg leg);
double getPower(ItemBase*, QString subpartName="");
double getCurrent(unsigned long, ItemBase*, QString subpartName="");
double getTransistorCurrent(unsigned long timeStep, QString spicePartName, TransistorLeg leg);
double getPower(unsigned long, ItemBase*, QString subpartName="");

//Functions to update the parts
void updateCapacitor(ItemBase *);
void updateDiode(ItemBase *);
void updateLED(ItemBase *);
void updateMultimeter(ItemBase *);
void updateOscilloscope(ItemBase *, int);
void updateResistor(ItemBase *);
void updatePotentiometer(ItemBase *);
void updateDcMotor(ItemBase *);
void updateIRSensor(ItemBase *);
void updateBattery(ItemBase *);
void updateCapacitor(unsigned long, ItemBase *);
void updateDiode(unsigned long, ItemBase *);
void updateLED(unsigned long, ItemBase *);
void updateMultimeter(unsigned long, ItemBase *);
void updateOscilloscope(unsigned long, ItemBase *);
void updateResistor(unsigned long, ItemBase *);
void updatePotentiometer(unsigned long, ItemBase *);
void updateDcMotor(unsigned long, ItemBase *);
void updateIRSensor(unsigned long, ItemBase *);
void updateBattery(unsigned long, ItemBase *);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please set your editor to use single tabs, not fours spaces, for indentation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done:
image

bool m_simulating = false;
MainWindow *m_mainWindow;
Expand Down