diff options
Diffstat (limited to 'Project/Electromechanical.cpp')
-rw-r--r-- | Project/Electromechanical.cpp | 317 |
1 files changed, 314 insertions, 3 deletions
diff --git a/Project/Electromechanical.cpp b/Project/Electromechanical.cpp index 85e10b4..191a1da 100644 --- a/Project/Electromechanical.cpp +++ b/Project/Electromechanical.cpp @@ -12,7 +12,7 @@ void Electromechanical::SetEventTimeList() // Fault for(auto it = m_busList.begin(), itEnd = m_busList.end(); it != itEnd; ++it) { Bus* bus = *it; - auto data = bus->GetEletricalData(); + auto data = bus->GetElectricalData(); if(data.stabHasFault) { m_eventTimeList.push_back(data.stabFaultTime); m_eventOccurrenceList.push_back(false); @@ -35,7 +35,7 @@ bool Electromechanical::HasEvent(double currentTime) { for(unsigned int i = 0; i < m_eventTimeList.size(); ++i) { if(!m_eventOccurrenceList[i]) { - if((m_eventTimeList[i] - m_timeStep) < currentTime && m_eventTimeList[i] >= currentTime) { + if(EventTrigger(m_eventTimeList[i], currentTime)) { m_eventOccurrenceList[i] = true; return true; } @@ -44,16 +44,327 @@ bool Electromechanical::HasEvent(double currentTime) return false; } -void Electromechanical::SetEvent(double currentTime) {} +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<double>(1.0, 0.0) / std::complex<double>(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<double>(1.0, 0.0) / std::complex<double>(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<Bus*>(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) { + generator->SetOnline(true); + auto data = generator->GetPUElectricalData(m_powerSystemBase); + int n = static_cast<Bus*>(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<Bus*>(load->GetParentList()[0]); + int n = parentBus->GetElectricalData().number; + std::complex<double> v = parentBus->GetElectricalData().voltage; + m_yBus[n][n] -= std::complex<double>(data.activePower, -data.reactivePower) / (v * v); + } + + // Insert load (only disconnected load) + if(swData.swType[i] == SW_INSERT && !load->IsOnline() && load->GetParentList().size() == 1) { + load->SetOnline(true); + auto data = load->GetPUElectricalData(m_powerSystemBase); + Bus* parentBus = static_cast<Bus*>(load->GetParentList()[0]); + int n = parentBus->GetElectricalData().number; + std::complex<double> v = parentBus->GetElectricalData().voltage; + m_yBus[n][n] += std::complex<double>(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<Bus*>(line->GetParentList()[0])->GetElectricalData().number; + int n2 = static_cast<Bus*>(line->GetParentList()[1])->GetElectricalData().number; + + m_yBus[n1][n2] += 1.0 / std::complex<double>(data.resistance, data.indReactance); + m_yBus[n2][n1] += 1.0 / std::complex<double>(data.resistance, data.indReactance); + + m_yBus[n1][n1] -= 1.0 / std::complex<double>(data.resistance, data.indReactance); + m_yBus[n2][n2] -= 1.0 / std::complex<double>(data.resistance, data.indReactance); + + m_yBus[n1][n1] -= std::complex<double>(0.0, data.capSusceptance / 2.0); + m_yBus[n2][n2] -= std::complex<double>(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->GetParentList()[0] && line->GetParentList()[1]) { + line->SetOnline(true); + auto data = line->GetElectricalData(); + + int n1 = static_cast<Bus*>(line->GetParentList()[0])->GetElectricalData().number; + int n2 = static_cast<Bus*>(line->GetParentList()[1])->GetElectricalData().number; + + m_yBus[n1][n2] -= 1.0 / std::complex<double>(data.resistance, data.indReactance); + m_yBus[n2][n1] -= 1.0 / std::complex<double>(data.resistance, data.indReactance); + + m_yBus[n1][n1] += 1.0 / std::complex<double>(data.resistance, data.indReactance); + m_yBus[n2][n2] += 1.0 / std::complex<double>(data.resistance, data.indReactance); + + m_yBus[n1][n1] += std::complex<double>(0.0, data.capSusceptance / 2.0); + m_yBus[n2][n2] += std::complex<double>(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<Bus*>(transformer->GetParentList()[0])->GetElectricalData().number; + int n2 = static_cast<Bus*>(transformer->GetParentList()[1])->GetElectricalData().number; + + if(data.turnsRatio == 1.0 && data.phaseShift == 0.0) { + m_yBus[n1][n2] -= -1.0 / std::complex<double>(data.resistance, data.indReactance); + m_yBus[n2][n1] -= -1.0 / std::complex<double>(data.resistance, data.indReactance); + + m_yBus[n1][n1] -= 1.0 / std::complex<double>(data.resistance, data.indReactance); + m_yBus[n2][n2] -= 1.0 / std::complex<double>(data.resistance, data.indReactance); + } else { + // Complex turns ratio + double radPhaseShift = wxDegToRad(data.phaseShift); + std::complex<double> a = std::complex<double>(data.turnsRatio * std::cos(radPhaseShift), + -data.turnsRatio * std::sin(radPhaseShift)); + + // Transformer admitance + std::complex<double> y = 1.0 / std::complex<double>(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->GetParentList()[0] && transformer->GetParentList()[1]) { + transformer->SetOnline(true); + auto data = transformer->GetElectricalData(); + + int n1 = static_cast<Bus*>(transformer->GetParentList()[0])->GetElectricalData().number; + int n2 = static_cast<Bus*>(transformer->GetParentList()[1])->GetElectricalData().number; + + if(data.turnsRatio == 1.0 && data.phaseShift == 0.0) { + m_yBus[n1][n2] += -1.0 / std::complex<double>(data.resistance, data.indReactance); + m_yBus[n2][n1] += -1.0 / std::complex<double>(data.resistance, data.indReactance); + + m_yBus[n1][n1] += 1.0 / std::complex<double>(data.resistance, data.indReactance); + m_yBus[n2][n2] += 1.0 / std::complex<double>(data.resistance, data.indReactance); + } else { + // Complex turns ratio + double radPhaseShift = wxDegToRad(data.phaseShift); + std::complex<double> a = std::complex<double>(data.turnsRatio * std::cos(radPhaseShift), + -data.turnsRatio * std::sin(radPhaseShift)); + + // Transformer admitance + std::complex<double> y = 1.0 / std::complex<double>(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<Bus*>(capacitor->GetParentList()[0])->GetElectricalData().number; + m_yBus[n][n] += std::complex<double>(0.0, data.reactivePower); + } + + // Insert capacitor (only disconnected capacitors) + if(swData.swType[i] == SW_INSERT && !capacitor->IsOnline() && capacitor->GetParentList().size() == 1) { + if(capacitor->GetParentList()[0]) { + capacitor->SetOnline(true); + auto data = capacitor->GetPUElectricalData(m_powerSystemBase); + int n = static_cast<Bus*>(capacitor->GetParentList()[0])->GetElectricalData().number; + m_yBus[n][n] -= std::complex<double>(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<Bus*>(inductor->GetParentList()[0])->GetElectricalData().number; + m_yBus[n][n] += std::complex<double>(0.0, -data.reactivePower); + } + + // Insert inductor (only disconnected inductors) + if(swData.swType[i] == SW_INSERT && !inductor->IsOnline() && inductor->GetParentList().size() == 1) { + if(inductor->GetParentList()[0]) { + inductor->SetOnline(true); + auto data = inductor->GetPUElectricalData(m_powerSystemBase); + int n = static_cast<Bus*>(inductor->GetParentList()[0])->GetElectricalData().number; + m_yBus[n][n] -= std::complex<double>(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<Bus*>(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<double> 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<double>(ra, -xdq) / std::complex<double>(ra * ra + xd * xq, 0.0); +} |