#include "Electromechanical.h" Electromechanical::Electromechanical(std::vector elementList) { GetElementsFromList(elementList); SetEventTimeList(); } Electromechanical::~Electromechanical() {} void Electromechanical::SetEventTimeList() { // Fault for(auto it = m_busList.begin(), itEnd = m_busList.end(); it != itEnd; ++it) { Bus* bus = *it; auto data = bus->GetElectricalData(); if(data.stabHasFault) { m_eventTimeList.push_back(data.stabFaultTime); m_eventOccurrenceList.push_back(false); m_eventTimeList.push_back(data.stabFaultTime + data.stabFaultLength); m_eventOccurrenceList.push_back(false); } } // Switching for(auto it = m_powerElementList.begin(), itEnd = m_powerElementList.end(); it != itEnd; ++it) { PowerElement* element = *it; SwitchingData swData = element->GetSwitchingData(); for(unsigned int i = 0; i < swData.swTime.size(); ++i) { m_eventTimeList.push_back(swData.swTime[i]); m_eventOccurrenceList.push_back(false); } } } bool Electromechanical::HasEvent(double currentTime) { for(unsigned int i = 0; i < m_eventTimeList.size(); ++i) { if(!m_eventOccurrenceList[i]) { if(EventTrigger(m_eventTimeList[i], currentTime)) { m_eventOccurrenceList[i] = true; return true; } } } return false; } void Electromechanical::SetEvent(double currentTime) { // Fault for(auto it = m_busList.begin(), itEnd = m_busList.end(); it != itEnd; ++it) { Bus* bus = *it; auto data = bus->GetElectricalData(); if(data.stabHasFault) { int n = data.number; // Insert fault if(EventTrigger(data.stabFaultTime, currentTime)) { double r, x; r = data.stabFaultResistance; x = data.stabFaultReactance; if(x < 1e-5) x = 1e-5; m_yBus[n][n] += std::complex(1.0, 0.0) / std::complex(r, x); } // Remove fault else if(EventTrigger(data.stabFaultTime + data.stabFaultLength, currentTime)) { double r, x; r = data.stabFaultResistance; x = data.stabFaultReactance; if(x < 1e-5) x = 1e-5; m_yBus[n][n] -= std::complex(1.0, 0.0) / std::complex(r, x); } } } // SyncGenerator switching for(auto it = m_syncGeneratorList.begin(), itEnd = m_syncGeneratorList.end(); it != itEnd; ++it) { SyncGenerator* generator = *it; auto swData = generator->GetSwitchingData(); for(unsigned int i = 0; i < swData.swType.size(); ++i) { if(EventTrigger(swData.swTime[i], currentTime)) { // Remove machine (only connected machines) if(swData.swType[i] == SW_REMOVE && generator->IsOnline()) { generator->SetOnline(false); auto data = generator->GetPUElectricalData(m_powerSystemBase); int n = static_cast(generator->GetParentList()[0])->GetElectricalData().number; m_yBus[n][n] -= GetSyncMachineAdmittance(generator); } // Insert machine (only disconnected machines) if(swData.swType[i] == SW_INSERT && !generator->IsOnline() && generator->GetParentList().size() == 1) { if(generator->SetOnline(true)) { auto data = generator->GetPUElectricalData(m_powerSystemBase); int n = static_cast(generator->GetParentList()[0])->GetElectricalData().number; m_yBus[n][n] += GetSyncMachineAdmittance(generator); } } } } } // Load switching for(auto it = m_loadList.begin(), itEnd = m_loadList.end(); it != itEnd; ++it) { Load* load = *it; auto swData = load->GetSwitchingData(); for(unsigned int i = 0; i < swData.swType.size(); ++i) { if(EventTrigger(swData.swTime[i], currentTime)) { // Remove load (only connected loads) if(swData.swType[i] == SW_REMOVE && load->IsOnline()) { load->SetOnline(false); auto data = load->GetPUElectricalData(m_powerSystemBase); Bus* parentBus = static_cast(load->GetParentList()[0]); int n = parentBus->GetElectricalData().number; std::complex v = parentBus->GetElectricalData().voltage; m_yBus[n][n] -= std::complex(data.activePower, -data.reactivePower) / (v * v); } // Insert load (only disconnected load) if(swData.swType[i] == SW_INSERT && !load->IsOnline() && load->GetParentList().size() == 1) { if(load->SetOnline(true)) { auto data = load->GetPUElectricalData(m_powerSystemBase); Bus* parentBus = static_cast(load->GetParentList()[0]); int n = parentBus->GetElectricalData().number; std::complex v = parentBus->GetElectricalData().voltage; m_yBus[n][n] += std::complex(data.activePower, -data.reactivePower) / (v * v); } } } } } // Line switching for(auto it = m_lineList.begin(), itEnd = m_lineList.end(); it != itEnd; ++it) { Line* line = *it; auto swData = line->GetSwitchingData(); for(unsigned int i = 0; i < swData.swType.size(); ++i) { if(EventTrigger(swData.swTime[i], currentTime)) { // Remove line (only connected lines) if(swData.swType[i] == SW_REMOVE && line->IsOnline()) { line->SetOnline(false); auto data = line->GetElectricalData(); int n1 = static_cast(line->GetParentList()[0])->GetElectricalData().number; int n2 = static_cast(line->GetParentList()[1])->GetElectricalData().number; m_yBus[n1][n2] += 1.0 / std::complex(data.resistance, data.indReactance); m_yBus[n2][n1] += 1.0 / std::complex(data.resistance, data.indReactance); m_yBus[n1][n1] -= 1.0 / std::complex(data.resistance, data.indReactance); m_yBus[n2][n2] -= 1.0 / std::complex(data.resistance, data.indReactance); m_yBus[n1][n1] -= std::complex(0.0, data.capSusceptance / 2.0); m_yBus[n2][n2] -= std::complex(0.0, data.capSusceptance / 2.0); } // Insert line (only disconnected lines) if(swData.swType[i] == SW_INSERT && !line->IsOnline() && line->GetParentList().size() == 2) { if(line->SetOnline(true)) { auto data = line->GetElectricalData(); int n1 = static_cast(line->GetParentList()[0])->GetElectricalData().number; int n2 = static_cast(line->GetParentList()[1])->GetElectricalData().number; m_yBus[n1][n2] -= 1.0 / std::complex(data.resistance, data.indReactance); m_yBus[n2][n1] -= 1.0 / std::complex(data.resistance, data.indReactance); m_yBus[n1][n1] += 1.0 / std::complex(data.resistance, data.indReactance); m_yBus[n2][n2] += 1.0 / std::complex(data.resistance, data.indReactance); m_yBus[n1][n1] += std::complex(0.0, data.capSusceptance / 2.0); m_yBus[n2][n2] += std::complex(0.0, data.capSusceptance / 2.0); } } } } } // Transformer switching for(auto it = m_transformerList.begin(), itEnd = m_transformerList.end(); it != itEnd; ++it) { Transformer* transformer = *it; auto swData = transformer->GetSwitchingData(); for(unsigned int i = 0; i < swData.swType.size(); ++i) { if(EventTrigger(swData.swTime[i], currentTime)) { // Remove transformer (only connected transformers) if(swData.swType[i] == SW_REMOVE && transformer->IsOnline()) { transformer->SetOnline(false); auto data = transformer->GetElectricalData(); int n1 = static_cast(transformer->GetParentList()[0])->GetElectricalData().number; int n2 = static_cast(transformer->GetParentList()[1])->GetElectricalData().number; if(data.turnsRatio == 1.0 && data.phaseShift == 0.0) { m_yBus[n1][n2] -= -1.0 / std::complex(data.resistance, data.indReactance); m_yBus[n2][n1] -= -1.0 / std::complex(data.resistance, data.indReactance); m_yBus[n1][n1] -= 1.0 / std::complex(data.resistance, data.indReactance); m_yBus[n2][n2] -= 1.0 / std::complex(data.resistance, data.indReactance); } else { // Complex turns ratio double radPhaseShift = wxDegToRad(data.phaseShift); std::complex a = std::complex(data.turnsRatio * std::cos(radPhaseShift), -data.turnsRatio * std::sin(radPhaseShift)); // Transformer admitance std::complex y = 1.0 / std::complex(data.resistance, data.indReactance); m_yBus[n1][n1] -= y / std::pow(std::abs(a), 2.0); m_yBus[n1][n2] -= -(y / std::conj(a)); m_yBus[n2][n1] -= -(y / a); m_yBus[n2][n2] -= y; } } // Insert transformer (only disconnected transformers) if(swData.swType[i] == SW_INSERT && !transformer->IsOnline() && transformer->GetParentList().size() == 2) { if(transformer->SetOnline(true)) { auto data = transformer->GetElectricalData(); int n1 = static_cast(transformer->GetParentList()[0])->GetElectricalData().number; int n2 = static_cast(transformer->GetParentList()[1])->GetElectricalData().number; if(data.turnsRatio == 1.0 && data.phaseShift == 0.0) { m_yBus[n1][n2] += -1.0 / std::complex(data.resistance, data.indReactance); m_yBus[n2][n1] += -1.0 / std::complex(data.resistance, data.indReactance); m_yBus[n1][n1] += 1.0 / std::complex(data.resistance, data.indReactance); m_yBus[n2][n2] += 1.0 / std::complex(data.resistance, data.indReactance); } else { // Complex turns ratio double radPhaseShift = wxDegToRad(data.phaseShift); std::complex a = std::complex(data.turnsRatio * std::cos(radPhaseShift), -data.turnsRatio * std::sin(radPhaseShift)); // Transformer admitance std::complex y = 1.0 / std::complex(data.resistance, data.indReactance); m_yBus[n1][n1] += y / std::pow(std::abs(a), 2.0); m_yBus[n1][n2] += -(y / std::conj(a)); m_yBus[n2][n1] += -(y / a); m_yBus[n2][n2] += y; } } } } } } // Capacitor switching for(auto it = m_capacitorList.begin(), itEnd = m_capacitorList.end(); it != itEnd; ++it) { Capacitor* capacitor = *it; auto swData = capacitor->GetSwitchingData(); for(unsigned int i = 0; i < swData.swType.size(); ++i) { if(EventTrigger(swData.swTime[i], currentTime)) { // Remove capacitor (only connected capacitors) if(swData.swType[i] == SW_REMOVE && capacitor->IsOnline()) { capacitor->SetOnline(false); auto data = capacitor->GetPUElectricalData(m_powerSystemBase); int n = static_cast(capacitor->GetParentList()[0])->GetElectricalData().number; m_yBus[n][n] += std::complex(0.0, data.reactivePower); } // Insert capacitor (only disconnected capacitors) if(swData.swType[i] == SW_INSERT && !capacitor->IsOnline() && capacitor->GetParentList().size() == 1) { if(capacitor->SetOnline(true)) { auto data = capacitor->GetPUElectricalData(m_powerSystemBase); int n = static_cast(capacitor->GetParentList()[0])->GetElectricalData().number; m_yBus[n][n] -= std::complex(0.0, data.reactivePower); } } } } } // Capacitor switching for(auto it = m_inductorList.begin(), itEnd = m_inductorList.end(); it != itEnd; ++it) { Inductor* inductor = *it; auto swData = inductor->GetSwitchingData(); for(unsigned int i = 0; i < swData.swType.size(); ++i) { if(EventTrigger(swData.swTime[i], currentTime)) { // Remove inductor (only connected inductors) if(swData.swType[i] == SW_REMOVE && inductor->IsOnline()) { inductor->SetOnline(false); auto data = inductor->GetPUElectricalData(m_powerSystemBase); int n = static_cast(inductor->GetParentList()[0])->GetElectricalData().number; m_yBus[n][n] += std::complex(0.0, -data.reactivePower); } // Insert inductor (only disconnected inductors) if(swData.swType[i] == SW_INSERT && !inductor->IsOnline() && inductor->GetParentList().size() == 1) { if(inductor->SetOnline(true)) { auto data = inductor->GetPUElectricalData(m_powerSystemBase); int n = static_cast(inductor->GetParentList()[0])->GetElectricalData().number; m_yBus[n][n] -= std::complex(0.0, -data.reactivePower); } } } } } } bool Electromechanical::RunStabilityCalculation() { // Calculate the admittance matrix with the synchronous machines. if(!GetYBus(m_yBus, m_powerSystemBase, POSITIVE_SEQ, false, true)) { m_errorMsg = _("It was not possible to build the admittance matrix."); return false; } InsertSyncMachinesOnYBus(); // test double simTime = 10.0; double currentTime = 0.0; while(currentTime <= simTime) { if(HasEvent(currentTime)) { SetEvent(currentTime); } currentTime += m_timeStep; } return true; } void Electromechanical::InsertSyncMachinesOnYBus() { for(auto it = m_syncGeneratorList.begin(), itEnd = m_syncGeneratorList.end(); it != itEnd; ++it) { SyncGenerator* generator = *it; if(generator->IsOnline()) { auto data = generator->GetElectricalData(); int n = static_cast(generator->GetParentList()[0])->GetElectricalData().number; m_yBus[n][n] += GetSyncMachineAdmittance(generator); } } } bool Electromechanical::EventTrigger(double eventTime, double currentTime) { return (((eventTime - m_timeStep) < currentTime) && (eventTime >= currentTime)); } std::complex Electromechanical::GetSyncMachineAdmittance(SyncGenerator* generator) { auto data = generator->GetPUElectricalData(m_powerSystemBase); double k = 1.0; // Power base change factor. if(data.useMachineBase) { double oldBase = data.nominalPower * std::pow(1000.0f, data.nominalPowerUnit); k = m_powerSystemBase / oldBase; } double xd = 0.0; double xq = 0.0; double ra = data.armResistance * k; switch(GetMachineModel(generator)) { case SM_MODEL_1: case SM_MODEL_2: case SM_MODEL_3: { xd = data.transXd * k; xq = data.transXq * k; break; } case SM_MODEL_4: case SM_MODEL_5: { xd = data.subXd * k; xq = data.subXq * k; break; } } double xdq = 0.5 * (xd + xq); return std::complex(ra, -xdq) / std::complex(ra * ra + xd * xq, 0.0); }