complex power_electronics::filter_voltage_impact_source(complex desired_I_out, complex desired_V_out){ if(desired_V_out == 0){ return complex(0,0); }else{ complex Is = filter_current_impact_source(desired_I_out, desired_V_out); complex Vs = desired_V_out + (Is * complex(Rsfilter_total,Xsfilter_total)); return Vs; } }
TIMESTAMP inverter::sync(TIMESTAMP t0, TIMESTAMP t1) { if (*NR_mode == false) { phaseA_V_Out = pCircuit_V[0]; //Syncs the meter parent to the generator. phaseB_V_Out = pCircuit_V[1]; phaseC_V_Out = pCircuit_V[2]; internal_losses = 1 - calculate_loss(Rtotal, Ltotal, Ctotal, DC, AC); //gl_verbose("inverter sync: internal losses are: %f", 1 - internal_losses); frequency_losses = 1 - calculate_frequency_loss(output_frequency, Rtotal,Ltotal, Ctotal); //gl_verbose("inverter sync: frequency losses are: %f", 1 - frequency_losses); switch(gen_mode_v) { case CONSTANT_PF: { VA_In = V_In * ~ I_In; //DC // need to differentiate between different pulses... VA_Out = VA_In * efficiency * internal_losses * frequency_losses; //losses = VA_Out * Rtotal / (Rtotal + Rload); //VA_Out = VA_Out * Rload / (Rtotal + Rload); if (number_of_phases_out == 4) //Triplex-line -> Assume it's only across the 240 V for now. { power_A = complex(VA_Out.Mag()*abs(power_factor),power_factor/abs(power_factor)*VA_Out.Mag()*sin(acos(power_factor))); if (phaseA_V_Out.Mag() != 0.0) phaseA_I_Out = ~(power_A / phaseA_V_Out); else phaseA_I_Out = complex(0.0,0.0); *pLine12 += -phaseA_I_Out; //Update this value for later removal last_current[3] = -phaseA_I_Out; //Get rid of these for now //complex phaseA_V_Internal = filter_voltage_impact_source(phaseA_I_Out, phaseA_V_Out); //phaseA_I_Out = filter_current_impact_out(phaseA_I_Out, phaseA_V_Internal); } else if (number_of_phases_out == 3) { power_A = power_B = power_C = complex(VA_Out.Mag()*abs(power_factor),power_factor/abs(power_factor)*VA_Out.Mag()*sin(acos(power_factor)))/3; if (phaseA_V_Out.Mag() != 0.0) phaseA_I_Out = ~(power_A / phaseA_V_Out); // /sqrt(2.0); else phaseA_I_Out = complex(0.0,0.0); if (phaseB_V_Out.Mag() != 0.0) phaseB_I_Out = ~(power_B / phaseB_V_Out); // /sqrt(2.0); else phaseB_I_Out = complex(0.0,0.0); if (phaseC_V_Out.Mag() != 0.0) phaseC_I_Out = ~(power_C / phaseC_V_Out); // /sqrt(2.0); else phaseC_I_Out = complex(0.0,0.0); pLine_I[0] += -phaseA_I_Out; pLine_I[1] += -phaseB_I_Out; pLine_I[2] += -phaseC_I_Out; //Update this value for later removal last_current[0] = -phaseA_I_Out; last_current[1] = -phaseB_I_Out; last_current[2] = -phaseC_I_Out; //complex phaseA_V_Internal = filter_voltage_impact_source(phaseA_I_Out, phaseA_V_Out); //complex phaseB_V_Internal = filter_voltage_impact_source(phaseB_I_Out, phaseB_V_Out); //complex phaseC_V_Internal = filter_voltage_impact_source(phaseC_I_Out, phaseC_V_Out); //phaseA_I_Out = filter_current_impact_out(phaseA_I_Out, phaseA_V_Internal); //phaseB_I_Out = filter_current_impact_out(phaseB_I_Out, phaseB_V_Internal); //phaseC_I_Out = filter_current_impact_out(phaseC_I_Out, phaseC_V_Internal); } else if(number_of_phases_out == 2) { OBJECT *obj = OBJECTHDR(this); node *par = OBJECTDATA(obj->parent, node); if (par->has_phase(PHASE_A) && phaseA_V_Out.Mag() != 0) { power_A = complex(VA_Out.Mag()*abs(power_factor),power_factor/abs(power_factor)*VA_Out.Mag()*sin(acos(power_factor)))/2;; phaseA_I_Out = ~(power_A / phaseA_V_Out); } else phaseA_I_Out = complex(0,0); if (par->has_phase(PHASE_B) && phaseB_V_Out.Mag() != 0) { power_B = complex(VA_Out.Mag()*abs(power_factor),power_factor/abs(power_factor)*VA_Out.Mag()*sin(acos(power_factor)))/2;; phaseB_I_Out = ~(power_B / phaseB_V_Out); } else phaseB_I_Out = complex(0,0); if (par->has_phase(PHASE_C) && phaseC_V_Out.Mag() != 0) { power_C = complex(VA_Out.Mag()*abs(power_factor),power_factor/abs(power_factor)*VA_Out.Mag()*sin(acos(power_factor)))/2;; phaseC_I_Out = ~(power_C / phaseC_V_Out); } else phaseC_I_Out = complex(0,0); pLine_I[0] += -phaseA_I_Out; pLine_I[1] += -phaseB_I_Out; pLine_I[2] += -phaseC_I_Out; //Update this value for later removal last_current[0] = -phaseA_I_Out; last_current[1] = -phaseB_I_Out; last_current[2] = -phaseC_I_Out; } else if(number_of_phases_out == 1) { if(phaseA_V_Out.Mag() != 0) { power_A = complex(VA_Out.Mag()*abs(power_factor),power_factor/abs(power_factor)*VA_Out.Mag()*sin(acos(power_factor))); phaseA_I_Out = ~(power_A / phaseA_V_Out); //complex phaseA_V_Internal = filter_voltage_impact_source(phaseA_I_Out, phaseA_V_Out); //phaseA_I_Out = filter_current_impact_out(phaseA_I_Out, phaseA_V_Internal); } else if(phaseB_V_Out.Mag() != 0) { power_B = complex(VA_Out.Mag()*abs(power_factor),power_factor/abs(power_factor)*VA_Out.Mag()*sin(acos(power_factor))); phaseB_I_Out = ~(power_B / phaseB_V_Out); //complex phaseB_V_Internal = filter_voltage_impact_source(phaseB_I_Out, phaseB_V_Out); //phaseB_I_Out = filter_current_impact_out(phaseB_I_Out, phaseB_V_Internal); } else if(phaseC_V_Out.Mag() != 0) { power_C = complex(VA_Out.Mag()*abs(power_factor),power_factor/abs(power_factor)*VA_Out.Mag()*sin(acos(power_factor))); phaseC_I_Out = ~(power_C / phaseC_V_Out); //complex phaseC_V_Internal = filter_voltage_impact_source(phaseC_I_Out, phaseC_V_Out); //phaseC_I_Out = filter_current_impact_out(phaseC_I_Out, phaseC_V_Internal); } else { gl_warning("None of the phases specified have voltages!"); phaseA_I_Out = phaseB_I_Out = phaseC_I_Out = complex(0.0,0.0); } pLine_I[0] += -phaseA_I_Out; pLine_I[1] += -phaseB_I_Out; pLine_I[2] += -phaseC_I_Out; //Update this value for later removal last_current[0] = -phaseA_I_Out; last_current[1] = -phaseB_I_Out; last_current[2] = -phaseC_I_Out; } else { throw ("The number of phases given is unsupported."); } return TS_NEVER; } break; case CONSTANT_PQ: { GL_THROW("Constant PQ mode not supported at this time"); /* TROUBLESHOOT This will be worked on at a later date and is not yet correctly implemented. */ gl_verbose("inverter sync: constant pq"); //TODO //gather V_Out for each phase //gather V_In (DC) from line -- can not gather V_In, for now set equal to V_Out //P_Out is either set or input from elsewhere //Q_Out is either set or input from elsewhere //Gather Rload if(parent_string = "meter") { VA_Out = complex(P_Out,Q_Out); } else if (parent_string = "triplex_meter") { VA_Out = complex(P_Out,Q_Out); } else { phaseA_I_Out = pLine_I[0]; phaseB_I_Out = pLine_I[1]; phaseC_I_Out = pLine_I[2]; //Erm, there's no good way to handle this from a "multiply attached" point of view. //TODO: Think about how to do this if the need arrises VA_Out = phaseA_V_Out * (~ phaseA_I_Out) + phaseB_V_Out * (~ phaseB_I_Out) + phaseC_V_Out * (~ phaseC_I_Out); } pf_out = P_Out/VA_Out.Mag(); //VA_Out = VA_In * efficiency * internal_losses; if (number_of_phases_out == 3) { power_A = power_B = power_C = VA_Out /3; phaseA_I_Out = (power_A / phaseA_V_Out); // /sqrt(2.0); phaseB_I_Out = (power_B / phaseB_V_Out); // /sqrt(2.0); phaseC_I_Out = (power_C / phaseC_V_Out); // /sqrt(2.0); phaseA_I_Out = ~ phaseA_I_Out; phaseB_I_Out = ~ phaseB_I_Out; phaseC_I_Out = ~ phaseC_I_Out; } else if(number_of_phases_out == 1) { if(phaseAOut) { power_A = VA_Out; phaseA_I_Out = (power_A / phaseA_V_Out); // /sqrt(2); phaseA_I_Out = ~ phaseA_I_Out; } else if(phaseBOut) { power_B = VA_Out; phaseB_I_Out = (power_B / phaseB_V_Out); // /sqrt(2); phaseB_I_Out = ~ phaseB_I_Out; } else if(phaseCOut) { power_C = VA_Out; phaseC_I_Out = (power_C / phaseC_V_Out); // /sqrt(2); phaseC_I_Out = ~ phaseC_I_Out; } else { throw ("none of the phases have voltages!"); } } else { throw ("unsupported number of phases"); } VA_In = VA_Out / (efficiency * internal_losses * frequency_losses); losses = VA_Out * (1 - (efficiency * internal_losses * frequency_losses)); //V_In = complex(0,0); // ////is there a better way to do this? //if(phaseAOut){ // V_In += abs(phaseA_V_Out.Re()); //} //if(phaseBOut){ // V_In += abs(phaseB_V_Out.Re()); //} //if(phaseCOut){ // V_In += abs(phaseC_V_Out.Re()); //}else{ // throw ("none of the phases have voltages!"); //} V_In = Vdc; I_In = VA_In / V_In; I_In = ~I_In; V_In = filter_voltage_impact_source(I_In, V_In); I_In = filter_current_impact_source(I_In, V_In); gl_verbose("Inverter sync: V_In asked for by inverter is: (%f , %f)", V_In.Re(), V_In.Im()); gl_verbose("Inverter sync: I_In asked for by inverter is: (%f , %f)", I_In.Re(), I_In.Im()); pLine_I[0] += phaseA_I_Out; pLine_I[1] += phaseB_I_Out; pLine_I[2] += phaseC_I_Out; //Update this value for later removal last_current[0] = phaseA_I_Out; last_current[1] = phaseB_I_Out; last_current[2] = phaseC_I_Out; return TS_NEVER; } break; case CONSTANT_V: { GL_THROW("Constant V mode not supported at this time"); /* TROUBLESHOOT This will be worked on at a later date and is not yet correctly implemented. */ gl_verbose("inverter sync: constant v"); bool changed = false; //TODO //Gather V_Out //Gather VA_Out //Gather Rload if(phaseAOut) { if (phaseA_V_Out.Re() < (V_Set_A - margin)) { phaseA_I_Out = phaseA_I_Out_prev + I_step_max/2; changed = true; } else if (phaseA_V_Out.Re() > (V_Set_A + margin)) { phaseA_I_Out = phaseA_I_Out_prev - I_step_max/2; changed = true; } else { changed = false; } } if (phaseBOut) { if (phaseB_V_Out.Re() < (V_Set_B - margin)) { phaseB_I_Out = phaseB_I_Out_prev + I_step_max/2; changed = true; } else if (phaseB_V_Out.Re() > (V_Set_B + margin)) { phaseB_I_Out = phaseB_I_Out_prev - I_step_max/2; changed = true; } else { changed = false; } } if (phaseCOut) { if (phaseC_V_Out.Re() < (V_Set_C - margin)) { phaseC_I_Out = phaseC_I_Out_prev + I_step_max/2; changed = true; } else if (phaseC_V_Out.Re() > (V_Set_C + margin)) { phaseC_I_Out = phaseC_I_Out_prev - I_step_max/2; changed = true; } else { changed = false; } } power_A = (~phaseA_I_Out) * phaseA_V_Out; power_B = (~phaseB_I_Out) * phaseB_V_Out; power_C = (~phaseC_I_Out) * phaseC_V_Out; //check if inverter is overloaded -- if so, cap at max power if (((power_A + power_B + power_C) > Rated_kVA) || ((power_A.Re() + power_B.Re() + power_C.Re()) > Max_P) || ((power_A.Im() + power_B.Im() + power_C.Im()) > Max_Q)) { VA_Out = Rated_kVA / number_of_phases_out; //if it's maxed out, don't ask for the simulator to re-call changed = false; if(phaseAOut) { phaseA_I_Out = VA_Out / phaseA_V_Out; phaseA_I_Out = (~phaseA_I_Out); } if(phaseBOut) { phaseB_I_Out = VA_Out / phaseB_V_Out; phaseB_I_Out = (~phaseB_I_Out); } if(phaseCOut) { phaseC_I_Out = VA_Out / phaseC_V_Out; phaseC_I_Out = (~phaseC_I_Out); } } //check if power is negative for some reason, should never be if(power_A < 0) { power_A = 0; phaseA_I_Out = 0; throw("phaseA power is negative!"); } if(power_B < 0) { power_B = 0; phaseB_I_Out = 0; throw("phaseB power is negative!"); } if(power_C < 0) { power_C = 0; phaseC_I_Out = 0; throw("phaseC power is negative!"); } VA_In = VA_Out / (efficiency * internal_losses * frequency_losses); losses = VA_Out * (1 - (efficiency * internal_losses * frequency_losses)); //V_In = complex(0,0); // ////is there a better way to do this? //if(phaseAOut){ // V_In += abs(phaseA_V_Out.Re()); //} //if(phaseBOut){ // V_In += abs(phaseB_V_Out.Re()); //} //if(phaseCOut){ // V_In += abs(phaseC_V_Out.Re()); //}else{ // throw ("none of the phases have voltages!"); //} V_In = Vdc; I_In = VA_In / V_In; I_In = ~I_In; gl_verbose("Inverter sync: I_In asked for by inverter is: (%f , %f)", I_In.Re(), I_In.Im()); V_In = filter_voltage_impact_source(I_In, V_In); I_In = filter_current_impact_source(I_In, V_In); //TODO: check P and Q components to see if within bounds if(changed) { pLine_I[0] += phaseA_I_Out; pLine_I[1] += phaseB_I_Out; pLine_I[2] += phaseC_I_Out; //Update this value for later removal last_current[0] = phaseA_I_Out; last_current[1] = phaseB_I_Out; last_current[2] = phaseC_I_Out; TIMESTAMP t2 = t1 + 10 * 60 * TS_SECOND; return t2; } else { pLine_I[0] += phaseA_I_Out; pLine_I[1] += phaseB_I_Out; pLine_I[2] += phaseC_I_Out; //Update this value for later removal last_current[0] = phaseA_I_Out; last_current[1] = phaseB_I_Out; last_current[2] = phaseC_I_Out; return TS_NEVER; } } break; case SUPPLY_DRIVEN: { GL_THROW("SUPPLY_DRIVEN mode for inverters not supported at this time"); } default: { pLine_I[0] += phaseA_I_Out; pLine_I[1] += phaseB_I_Out; pLine_I[2] += phaseC_I_Out; //Update this value for later removal last_current[0] = phaseA_I_Out; last_current[1] = phaseB_I_Out; last_current[2] = phaseC_I_Out; return TS_NEVER; } break; } if (number_of_phases_out == 4) { *pLine12 += phaseA_I_Out; //Update this value for later removal last_current[3] = phaseA_I_Out; } else { pLine_I[0] += phaseA_I_Out; pLine_I[1] += phaseB_I_Out; pLine_I[2] += phaseC_I_Out; //Update this value for later removal last_current[0] = phaseA_I_Out; last_current[1] = phaseB_I_Out; last_current[2] = phaseC_I_Out; } return TS_NEVER; } else { if (number_of_phases_out == 4) { *pLine12 += last_current[3]; } else { pLine_I[0] += last_current[0]; pLine_I[1] += last_current[1]; pLine_I[2] += last_current[2]; } return TS_NEVER; } }