diff --git a/src/simulation/simulator.cpp b/src/simulation/simulator.cpp index 9b5eea51d..3703e3143 100644 --- a/src/simulation/simulator.cpp +++ b/src/simulation/simulator.cpp @@ -390,43 +390,43 @@ void Simulator::updateParts(QSet 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; } } @@ -593,12 +593,14 @@ void Simulator::removeSimItems(QList 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]; } } @@ -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); @@ -619,10 +621,10 @@ double Simulator::calculateVoltage(ConnectorItem * c0, ConnectorItem * c1) { double volt0 = 0.0, volt1 = 0.0; if (net0 != 0) { - volt0 = getVectorValueOrDefault(net0str.toStdString(), 0.0); + volt0 = getVectorValueOrDefault(timeStep, net0str.toStdString(), 0.0); } if (net1 != 0) { - volt1 = getVectorValueOrDefault(net1str.toStdString(), 0.0); + volt1 = getVectorValueOrDefault(timeStep, net1str.toStdString(), 0.0); } return volt0-volt1; } @@ -763,13 +765,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); } /** @@ -783,7 +785,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()); @@ -816,7 +818,7 @@ double Simulator::getCurrent(ItemBase* part, QString subpartName) { break; } - return getVectorValueOrDefault(instanceStr.toStdString(), 0.0); + return getVectorValueOrDefault(timeStep, instanceStr.toStdString(), 0.0); } /** @@ -824,7 +826,7 @@ double Simulator::getCurrent(ItemBase* part, QString subpartName) { * @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); @@ -844,7 +846,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); } /** @@ -1011,9 +1013,9 @@ void Simulator::removeItemsToBeSimulated(QList & 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); } @@ -1024,7 +1026,7 @@ 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(part); if (led) { //Check if this an RGB led @@ -1032,7 +1034,7 @@ void Simulator::updateLED(ItemBase * part) { if (rgbString.isEmpty()) { // Just one LED - double curr = getCurrent(part); + double curr = getCurrent(timeStep, part); double maxCurr = getMaxPropValue(part, "current"); std::cout << "LED Current: " <getProperty("family").toLower(); ConnectorItem * negLeg, * posLeg; @@ -1086,7 +1088,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; @@ -1107,9 +1109,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 < maxPower) { drawSmoke(part); @@ -1121,10 +1123,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); @@ -1135,12 +1137,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 <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; @@ -1205,7 +1207,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; @@ -1218,7 +1220,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; @@ -1275,7 +1277,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 probes = part->cachedConnectorItems(); @@ -1302,7 +1304,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; @@ -1313,7 +1315,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; @@ -1322,8 +1324,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); @@ -1336,7 +1338,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 probes = part->cachedConnectorItems(); @@ -1419,7 +1421,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); diff --git a/src/simulation/simulator.h b/src/simulation/simulator.h index 612a0d5e4..5d98e0589 100644 --- a/src/simulation/simulator.h +++ b/src/simulation/simulator.h @@ -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 voltageVector(ConnectorItem *); QString generateSvgPath(std::vector, std::vector, 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 *); bool m_simulating = false; MainWindow *m_mainWindow;