def _assign_substation_voltage(substation, voltage): """ Função que atribui tensão à subestação e a define para todos os nós de carga""" substation.voltage = voltage for feeder in substation.feeders.values(): for node in feeder.load_nodes.values(): node.voltage = R(voltage.r, voltage.i) for section in feeder.sections.values(): section.flow = R(0.0, 0.0)
def config_objects(substation, positive_eq_impedance=0.0, zero_eq_impedance=0.0): """conifg_objects: configura os objetos da substecao para calculo de sc-circuito.""" substation.positive_impedance = positive_eq_impedance substation.zero_impedance = zero_eq_impedance substation.positive_equivalent_impedance = positive_eq_impedance substation.zero_equivalent_impedance = zero_eq_impedance for transformer in substation.transformers.values(): substation.sub_base = Base(transformer.secondary_voltage.m, transformer.power.m) break for feeder in substation.feeders.values(): for section in feeder.sections.values(): section.positive_impedance = ( section.conductor.rp + section.conductor.xp * 1j) * section.length section.zero_impedance = ( section.conductor.rz + section.conductor.xz * 1j) * section.length section.contact_resistence = 100.0 section.base = substation.sub_base section.positive_equivalent_impedance = section.positive_impedance / section.base.impedance section.zero_equivalent_impedance = section.zero_impedance / section.base.impedance section.flow = R(r=0.0, i=0.0) calc_equivalent_impedance(substation)
def _calc_line_to_groud_sc(section): sc1 = (3.0) * section.base.current / ( 2 * section.positive_equivalent_impedance + section.zero_equivalent_impedance) sc_current = R(sc1.real, sc1.imag) sc_current.base = section.base.current return sc_current
def _calc_line_to_ground_min_sc(section): sc1m = 3.0 * section.base.current / ( 2 * section.positive_equivalent_impedance + section.zero_equivalent_impedance + 3 * section.contact_resistence / section.base.impedance) sc_current = R(sc1m.real, sc1m.imag) sc_current.base = section.base.current return sc_current
def calc_power_flow(substation): # atribui a tensão de fase da barra da subestação a todos # os nós de carga da subestação f1 = P(13.8e3 / np.sqrt(3), 0.0) _assign_substation_voltage(substation, f1) for feeder in substation.feeders.values(): max_iterations = 50 converg_crt = 0.001 converg = 1e6 iter = 0 print('============================') print('Feeder {al} Sweep'.format(al=feeder.name)) nodes_converg = dict() for node in feeder.load_nodes.values(): nodes_converg[node.name] = 1e6 while iter <= max_iterations and converg > converg_crt: iter += 1 print('-------------------------') print('Iteration: {iter}'.format(iter=iter)) voltage_nodes = dict() for node in feeder.load_nodes.values(): voltage_nodes[node.name] = R(node.voltage.r, node.voltage.i) _feeder_sweep(feeder) for node in feeder.load_nodes.values(): nodes_converg[node.name] = abs(voltage_nodes[node.name].m - node.voltage.m) converg = max(nodes_converg.values()) print('Max. diferença de tensões: {conv}'.format(conv=converg)) # for atualiza os valores das tensões dos nós de carga para valores # de tensão de linha substation.voltage.m = substation.voltage.m * np.sqrt(3) nodes = list() for feeder in substation.feeders.values(): for node in feeder.load_nodes.values(): if node.name not in nodes: node.voltage.m = node.voltage.m * np.sqrt(3) nodes.append(node.name)
def _calc_three_phase_sc(section): sc3 = 1.0 * section.base.current / (section.positive_equivalent_impedance) sc_current = R(sc3.real, sc3.imag) sc_current.base = section.base.current return sc_current
def calc_line_to_line_sc(section): sc2 = (3**0.5) * section.base.current / ( 2 * section.positive_equivalent_impedance) sc_current = R(sc2.real, sc2.imag) sc_current.base = section.base.current return sc_current
def _feeder_sweep(feeder): """ Função que varre os feeders pelo método varredura direta/inversa""" # guarda os nós de carga na variável feeder_nodes feeder_nodes = feeder.load_nodes.values() # guarda a rnp dos nós de carga na variável feder_rnp feder_rnp = feeder.load_nodes_tree.rnp # guarda a árvore de cada nós de carga load_nodes_tree = feeder.load_nodes_tree.tree # variáveis para o auxílio na determinação do nó mais profundo max_depth = 0 # for percorre a rnp dos nós de carga tomando valores # em pares (profundidade, nó). for node_depth in feder_rnp.transpose(): # pega os nomes dos nós de carga. feeder_nodes_names = [node.name for node in feeder_nodes] # verifica se a profundidade do nó é maior do que a # profundidade máxima e se ele está na lista de nós do feeder. if (int(node_depth[0]) > max_depth) \ and (node_depth[1] in feeder_nodes_names): max_depth = int(node_depth[0]) # depth recebe a profundidae máxima determinada depth = max_depth # seção do cálculo das potências partindo dos # nós com maiores profundidades até o nó raíz while depth >= 0: # guarda os nós com maiores profundidades. nodes = [feeder.load_nodes[node_depth[1]] for node_depth in feder_rnp.transpose() if int(node_depth[0]) == depth] # decrementodo da profundidade. depth -= 1 # for que percorre os nós com a profundidade # armazenada na variável depth for node in nodes: # zera as potências para que na próxima # iteração não ocorra acúmulo. node.equivalent_power.r = 0.0 node.equivalent_power.i = 0.0 # armazena a árvore do nó de carga # armazenado na variável nó neighbors = load_nodes_tree[node.name] # guarda os pares (profundidade, nó) node_depth = [node_depth for node_depth in feder_rnp.transpose() if node_depth[1] == node.name] downstream_neighbors = list() # for que percorre a árvore de cada nó de carga for neighbor in neighbors: # verifica quem é neighbor do nó desejado. depth_neighbor = [n_depth for n_depth in feder_rnp.transpose() if n_depth[1] == neighbor] # verifica se a profundidade do neighbor é maior if int(depth_neighbor[0][0]) > int(node_depth[0][0]): # armazena os neighbors a jusante. downstream_neighbors.append( feeder.load_nodes[depth_neighbor[0][1]]) # verifica se não há neighbor a jusante, # se não houverem o nó de carga analisado # é o último do ramo. if downstream_neighbors == []: node.equivalent_power.r += node.power.r / 3.0 node.equivalent_power.i += node.power.i / 3.0 else: # soma a power da carga associada ao nó atual node.equivalent_power.r += node.power.r / 3.0 node.equivalent_power.i += node.power.i / 3.0 # acrescenta à potência do nó atual # as potências dos nós a jusante for downstream_node in downstream_neighbors: node.equivalent_power.r += downstream_node.equivalent_power.r node.equivalent_power.i += downstream_node.equivalent_power.i # chama a função busca_trecho para definir # quais sections estão entre o nó atual e o nó a jusante section = _search_section(feeder, node.name, downstream_node.name) # se o section não for uma instancia da classe # Section(quando há switch entre nós de cargas) # a impedância é calculada if not isinstance(section, Section): r1, x1 = section[0].calc_impedance() r2, x2 = section[1].calc_impedance() r, x = r1 + r2, x1 + x2 # se o section atual for uma instancia da classe section else: r, x = section.calc_impedance() # calculo das potências dos nós de carga a jusante. node.equivalent_power.r += r * (downstream_node.equivalent_power.m ** 2) / \ downstream_node.voltage.m ** 2 node.equivalent_power.i += x * (downstream_node.equivalent_power.m ** 2) / \ downstream_node.voltage.m ** 2 depth = 0 # seção do cálculo de atualização das tensões while depth <= max_depth: # salva os nós de carga a montante nodes = [feeder.load_nodes[col_depth_node[1]] for col_depth_node in feder_rnp.transpose() if int(col_depth_node[0]) == depth + 1] # percorre os nós para guardar a árvore do nó requerido for node in nodes: neighbors = load_nodes_tree[node.name] # guarda os pares (profundidade,nó) node_depth = [col_depth_node for col_depth_node in feder_rnp.transpose() if col_depth_node[1] == node.name] upstream_neighbors = list() # verifica quem é neighbor do nó desejado. for neighbor in neighbors: depth_neighbor = [n_depth for n_depth in feder_rnp.transpose() if n_depth[1] == neighbor] if int(depth_neighbor[0][0]) < int(node_depth[0][0]): # armazena os neighbors a montante. upstream_neighbors.append( feeder.load_nodes[depth_neighbor[0][1]]) # armazena o primeiro neighbor a montante upstream_node = upstream_neighbors[0] section = _search_section(feeder, node.name, upstream_node.name) # se existir switch, soma a resistência dos dois sections if not isinstance(section, Section): r1, x1 = section[0].calc_impedance() r2, x2 = section[1].calc_impedance() r, x = r1 + r2, x1 + x2 # caso não exista, a resistência é a do próprio section else: r, x = section.calc_impedance() v_mon = upstream_node.voltage.m p = node.equivalent_power.r q = node.equivalent_power.i # parcela de perdas p += r * (node.equivalent_power.m ** 2) / node.voltage.m ** 2 q += x * (node.equivalent_power.m ** 2) / node.voltage.m ** 2 v_jus = v_mon ** 2 - 2 * (r * p + x * q) + \ (r ** 2 + x ** 2) * (p ** 2 + q ** 2) / v_mon ** 2 v_jus = np.sqrt(v_jus) k1 = (p * x - q * r) / v_mon k2 = v_mon - (p * r - q * x) / v_mon ang = upstream_node.voltage.a * np.pi / 180.0 - np.arctan(k1 / k2) node.voltage.m = v_jus node.voltage.a = ang * 180.0 / np.pi print('Node Voltage {name}: {tens}'.format( name=node.name, tens=node.voltage.m * np.sqrt(3) / 1e3)) # calcula o flow de current passante node section z = R(r, x) current = (node.voltage - upstream_node.voltage) / z # se houver switchs, ou seja, há dois sections a mesma current # é atribuida if not isinstance(section, Section): section[0].flow = current section[1].flow = current else: section.flow = current depth += 1