/* Sync is called when the clock needs to advance on the bottom-up pass */ TIMESTAMP rectifier::sync(TIMESTAMP t0, TIMESTAMP t1) { V_Out = pCircuit_V[0]; I_Out = pLine_I[0]; gl_verbose("rectifier sync: V_Out from parent is: (%f , %f)", V_Out.Re(), V_Out.Im()); gl_verbose("rectifier sync: I_Out from parent is: (%f , %f)", I_Out.Re(), I_Out.Im()); internal_losses = 1 - calculate_loss(Rtotal, Ltotal, Ctotal, DC, AC); frequency_losses = 1 - calculate_frequency_loss(input_frequency, Rtotal,Ltotal, Ctotal); //TODO: consider installing duty or on-ratio limits switch(gen_mode_v){ case SUPPLY_DRIVEN: {//TODO //set V_Out for each phase //set V_In from line //set I_In from line //set RLoad for this time step if it isn't constant gl_verbose("rectifier sync: supply driven rectifier"); power_A_In = phaseA_V_In * phaseA_I_In; //AC power_B_In = phaseB_V_In * phaseB_I_In; power_C_In = phaseC_V_In * phaseC_I_In; VA_In = power_A_In + power_B_In + power_C_In; 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 == 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); }else if(number_of_phases_out == 1){ if(phaseA_V_Out != 0){ power_A = VA_Out; phaseA_I_Out = (power_A / phaseA_V_Out) / sqrt(2.0); }else if(phaseB_V_Out != 0){ power_B = VA_Out; phaseB_I_Out = (power_B / phaseB_V_Out) / sqrt(2.0); }else if(phaseC_V_Out != 0){ power_C = VA_Out; phaseC_I_Out = (power_C / phaseC_V_Out) / sqrt(2.0); }else{ throw ("none of the phases have voltages!"); } }else{ throw ("unsupported number of phases"); } */ I_Out = VA_Out / V_Out; I_Out = ~ I_Out; gl_verbose("rectifier sync: VA_Out is: (%f , %f)", VA_Out.Re(), VA_Out.Im()); gl_verbose("rectifier sync: V_Out is: (%f , %f)", V_Out.Re(), V_Out.Im()); gl_verbose("rectifier sync: I_Out is: (%f , %f)", I_Out.Re(), I_Out.Im()); gl_verbose("rectifier sync: losses is: (%f , %f)", losses.Re(), losses.Im()); gl_verbose("rectifier sync: supply driven about to exit"); return TS_NEVER; } break; case CONSTANT_PQ: {//TODO gl_verbose("rectifier sync: constant pq rectifier"); //P_Out is either set or input from elsewhere //Q_Out is either set or input from elsewhere //if the device is connected directly to the meter, then it is the lead node and must set the //power output for the rest of the branches if(parent_string == "meter"){ VA_Out = complex(P_Out,Q_Out); }else{ VA_Out = V_Out * (~I_Out); } gl_verbose("rectifier sync: VA_Out calculated from parent is: (%f , %f)", VA_Out.Re(), VA_Out.Im()); VA_In = VA_Out / (efficiency * internal_losses); losses = VA_Out * (1 - (efficiency * internal_losses)); //I_In = VA_In / V_In; gl_verbose("rectifier sync: VA_In calculated after losses is: (%f , %f)", VA_In.Re(), VA_In.Im()); if(number_of_phases_in == 3){ iterative_IV(VA_In, "D"); } if(number_of_phases_in == 1){ //divide up power by the number of phases, then assign that power to each phase VA_In = VA_In / number_of_phases_in; //assume balanced system: //TODO: I'm not sure if the sqrt(2) is necessary... it is supposed to account for RMS current but //it may already be in RMS current after dividing by voltage if(phaseAIn){ power_A_In = VA_In; iterative_IV(power_A_In,"A"); // phaseA_V_In = ((power_A_In * Xphase) + V_In_Set_A)^0.5; // phaseA_I_In = (power_A_In / phaseA_V_In); // } if(phaseBIn){ power_B_In = VA_In; iterative_IV(power_B_In,"B"); // phaseB_V_In = ((power_B_In * Xphase) + V_In_Set_B)^0.5; // phaseB_I_In = (power_B_In / phaseB_V_In); // } if(phaseCIn){ power_C_In = VA_In; iterative_IV(power_C_In,"C"); // phaseC_V_In = ((power_C_In * Xphase) + V_In_Set_C)^0.5; // phaseC_I_In = (power_C_In / phaseC_V_In); // } } gl_verbose("rectifier sync: VA_In is: (%f , %f)", VA_In.Re(), VA_In.Im()); gl_verbose("rectifier sync: power_A_In is: (%f , %f)", power_A_In.Re(), power_A_In.Im()); gl_verbose("rectifier sync: power_B_In is: (%f , %f)", power_B_In.Re(), power_B_In.Im()); gl_verbose("rectifier sync: power_C_In is: (%f , %f)", power_C_In.Re(), power_C_In.Im()); gl_verbose("rectifier sync: phaseA_V_In is: (%f , %f)", phaseA_V_In.Re(), phaseA_V_In.Im()); gl_verbose("rectifier sync: phaseB_V_In is: (%f , %f)", phaseB_V_In.Re(), phaseB_V_In.Im()); gl_verbose("rectifier sync: phaseC_V_In is: (%f , %f)", phaseC_V_In.Re(), phaseC_V_In.Im()); gl_verbose("rectifier sync: phaseA_I_In is: (%f , %f)", phaseA_I_In.Re(), phaseA_I_In.Im()); gl_verbose("rectifier sync: phaseB_I_In is: (%f , %f)", phaseB_I_In.Re(), phaseB_I_In.Im()); gl_verbose("rectifier sync: phaseC_I_In is: (%f , %f)", phaseC_I_In.Re(), phaseC_I_In.Im()); gl_verbose("rectifier sync: constant pq about to exit"); return TS_NEVER; } break; case CONSTANT_V: { gl_verbose("rectifier sync: constant v rectifier"); bool changed = false; //phaseA_V_In = V_Out; //phaseB_V_In = V_Out; //phaseC_V_In = V_Out; //TODO //Gather V_Out //Gather VA_Out //Gather Rload if (V_Out < (V_Set - margin)){ I_Out = I_out_prev + I_step_max / 2; changed = true; }else if (V_Out > (V_Set + margin)){ I_Out = I_out_prev - I_step_max / 2; changed = true; }else{ changed = false; } VA_Out = (~I_Out) * V_Out; if(VA_Out > Rated_kVA){ VA_Out = Rated_kVA; I_Out = VA_Out / V_Out; changed = false; } if(VA_Out < 0){ VA_Out = 0; I_Out = 0; changed = false; } /* if(phaseAOut){ if (phaseA_V_Out < (V_Set_A - margin)){ phaseA_I_Out = phaseA_I_Out_prev + I_step_max/2; changed = true; }else if (phaseA_V_Out > (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 < (V_Set_B - margin)){ phaseB_I_Out = phaseB_I_Out_prev + I_step_max/2; changed = true; }else if (phaseB_V_Out > (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 < (V_Set_C - margin)){ phaseC_I_Out = phaseC_I_Out_prev + I_step_max/2; changed = true; }else if (phaseC_V_Out > (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 rectifier 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(phaseAOut){ phaseA_I_Out = VA_Out / phaseA_V_Out; } if(phaseBOut){ phaseB_I_Out = VA_Out / phaseB_V_Out; } if(phaseCOut){ phaseC_I_Out = VA_Out / phaseC_V_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!"); } */ gl_verbose("rectifier sync: VA_Out requested from parent is: (%f , %f)", VA_Out.Re(), VA_Out.Im()); VA_In = VA_Out / (efficiency * internal_losses); losses = VA_Out * (1 - (efficiency * internal_losses)); gl_verbose("rectifier sync: VA_In after losses is: (%f , %f)", VA_In.Re(), VA_In.Im()); //after we export this current to the generator that is hooked up on the input, //we will expect that during the next timestep, the generator will give us a //new frequency of input power that it has adopted in order to meet the //requested current if(number_of_phases_in == 3){ iterative_IV(VA_In, "D"); } if(number_of_phases_in == 1){ VA_In = VA_In / number_of_phases_in; if(phaseAIn){ power_A_In = VA_In; iterative_IV(power_A_In,"A"); } if(phaseBIn){ power_B_In = VA_In; iterative_IV(power_B_In,"B"); } if(phaseCIn){ power_C_In = VA_In; iterative_IV(power_C_In,"C"); } } //TODO: check P and Q components to see if within bounds gl_verbose("rectifier sync: VA_In is: (%f , %f)", VA_In.Re(), VA_In.Im()); gl_verbose("rectifier sync: power_A_In is: (%f , %f)", power_A_In.Re(), power_A_In.Im()); gl_verbose("rectifier sync: power_B_In is: (%f , %f)", power_B_In.Re(), power_B_In.Im()); gl_verbose("rectifier sync: power_C_In is: (%f , %f)", power_C_In.Re(), power_C_In.Im()); gl_verbose("rectifier sync: phaseA_V_In is: (%f , %f)", phaseA_V_In.Re(), phaseA_V_In.Im()); gl_verbose("rectifier sync: phaseB_V_In is: (%f , %f)", phaseB_V_In.Re(), phaseB_V_In.Im()); gl_verbose("rectifier sync: phaseC_V_In is: (%f , %f)", phaseC_V_In.Re(), phaseC_V_In.Im()); gl_verbose("rectifier sync: phaseA_I_In is: (%f , %f)", phaseA_I_In.Re(), phaseA_I_In.Im()); gl_verbose("rectifier sync: phaseB_I_In is: (%f , %f)", phaseB_I_In.Re(), phaseB_I_In.Im()); gl_verbose("rectifier sync: phaseC_I_In is: (%f , %f)", phaseC_I_In.Re(), phaseC_I_In.Im()); gl_verbose("rectifier sync: constant v rectifier about to exit"); if(changed){ TIMESTAMP t2 = TS_NEVER; return t2; }else{ return TS_NEVER; } } break; default: break; return TS_NEVER; } return TS_NEVER; }
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; } }
/* Sync is called when the clock needs to advance on the bottom-up pass */ TIMESTAMP rectifier::sync(TIMESTAMP t0, TIMESTAMP t1) { V_Out = (*pCircuit_V).Re(); I_Out = (*pLine_I).Re(); gl_verbose("rectifier sync: V_Out from parent is: (%f , %f)", V_Out.Re(), V_Out.Im()); gl_verbose("rectifier sync: I_Out from parent is: (%f , %f)", I_Out.Re(), I_Out.Im()); internal_losses = 1 - calculate_loss(Rtotal, Ltotal, Ctotal, DC, AC); frequency_losses = 1 - calculate_frequency_loss(input_frequency, Rtotal,Ltotal, Ctotal); //TODO: consider installing duty or on-ratio limits //AC-DC voltage magnitude ratio rule double VInMag = V_Out.Mag() * PI / (3 * sqrt(6.0)); voltage_A = complex(VInMag,0); voltage_B = complex(-VInMag/2, VInMag * sqrt(3.0) / 2); voltage_C = complex(-VInMag/2, -VInMag * sqrt(3.0) / 2); switch(gen_mode_v){ case SUPPLY_DRIVEN: { complex S_A_In, S_B_In, S_C_In; //DC Voltage, controlled by parent object determines DC Voltage. S_A_In = voltage_A*(~(current_A)); S_B_In = voltage_B*(~(current_B)); S_C_In = voltage_C*(~(current_C)); power_A_In = S_A_In.Re(); power_B_In = S_B_In.Re(); power_C_In = S_C_In.Re(); /* power_A_In = voltage_A.Mag() * current_A.Mag(); //AC power_B_In = voltage_B.Mag() * current_B.Mag(); power_C_In = voltage_C.Mag() * current_C.Mag(); */ VA_In = power_A_In + power_B_In + power_C_In; VA_Out = VA_In * efficiency * internal_losses * frequency_losses; losses = VA_Out * Rtotal / (Rtotal + Rload); I_Out = ~(VA_Out / V_Out); //These values are completely real, but since parent object uses complex, use here as well and follow rule for complex conjugate *pLine_I=I_Out; gl_verbose("rectifier sync: VA_Out is: (%f , %f)", VA_Out.Re(), VA_Out.Im()); gl_verbose("rectifier sync: V_Out is: (%f , %f)", V_Out.Re(), V_Out.Im()); gl_verbose("rectifier sync: I_Out is: (%f , %f)", I_Out.Re(), I_Out.Im()); gl_verbose("rectifier sync: losses is: (%f , %f)", losses.Re(), losses.Im()); gl_verbose("rectifier sync: supply driven about to exit"); return TS_NEVER; } break; /* case CONSTANT_PQ: {//TODO gl_verbose("rectifier sync: constant pq rectifier"); //P_Out is either set or input from elsewhere //Q_Out is either set or input from elsewhere //if the device is connected directly to the meter, then it is the lead node and must set the //power output for the rest of the branches if(parent_string == "meter"){ VA_Out = complex(P_Out,Q_Out); }else{ VA_Out = V_Out * (~I_Out); } gl_verbose("rectifier sync: VA_Out calculated from parent is: (%f , %f)", VA_Out.Re(), VA_Out.Im()); VA_In = VA_Out / (efficiency * internal_losses); losses = VA_Out * (1 - (efficiency * internal_losses)); //I_In = VA_In / V_In; gl_verbose("rectifier sync: VA_In calculated after losses is: (%f , %f)", VA_In.Re(), VA_In.Im()); if(number_of_phases_in == 3){ iterative_IV(VA_In, "D"); } if(number_of_phases_in == 1){ //divide up power by the number of phases, then assign that power to each phase VA_In = VA_In / number_of_phases_in; //assume balanced system: //TODO: I'm not sure if the sqrt(2) is necessary... it is supposed to account for RMS current but //it may already be in RMS current after dividing by voltage if(phaseAIn){ power_A_In = VA_In; iterative_IV(power_A_In,"A"); // voltage_A = ((power_A_In * Xphase) + V_In_Set_A)^0.5; // current_A = (power_A_In / voltage_A); // } if(phaseBIn){ power_B_In = VA_In; iterative_IV(power_B_In,"B"); // voltage_B = ((power_B_In * Xphase) + V_In_Set_B)^0.5; // current_B = (power_B_In / voltage_B); // } if(phaseCIn){ power_C_In = VA_In; iterative_IV(power_C_In,"C"); // voltage_C = ((power_C_In * Xphase) + V_In_Set_C)^0.5; // current_C = (power_C_In / voltage_C); // } } gl_verbose("rectifier sync: VA_In is: (%f , %f)", VA_In.Re(), VA_In.Im()); gl_verbose("rectifier sync: power_A_In is: (%f , %f)", power_A_In.Re(), power_A_In.Im()); gl_verbose("rectifier sync: power_B_In is: (%f , %f)", power_B_In.Re(), power_B_In.Im()); gl_verbose("rectifier sync: power_C_In is: (%f , %f)", power_C_In.Re(), power_C_In.Im()); gl_verbose("rectifier sync: voltage_A is: (%f , %f)", voltage_A.Re(), voltage_A.Im()); gl_verbose("rectifier sync: voltage_B is: (%f , %f)", voltage_B.Re(), voltage_B.Im()); gl_verbose("rectifier sync: voltage_C is: (%f , %f)", voltage_C.Re(), voltage_C.Im()); gl_verbose("rectifier sync: current_A is: (%f , %f)", current_A.Re(), current_A.Im()); gl_verbose("rectifier sync: current_B is: (%f , %f)", current_B.Re(), current_B.Im()); gl_verbose("rectifier sync: current_C is: (%f , %f)", current_C.Re(), current_C.Im()); gl_verbose("rectifier sync: constant pq about to exit"); return TS_NEVER; } break; case CONSTANT_V: { gl_verbose("rectifier sync: constant v rectifier"); bool changed = false; //voltage_A = V_Out; //voltage_B = V_Out; //voltage_C = V_Out; //TODO //Gather V_Out //Gather VA_Out //Gather Rload if (V_Out < (V_Rated - margin)){ I_Out = I_out_prev + I_step_max / 2; changed = true; }else if (V_Out > (V_Rated + margin)){ I_Out = I_out_prev - I_step_max / 2; changed = true; }else{ changed = false; } VA_Out = (~I_Out) * V_Out; if(VA_Out > Rated_kVA){ VA_Out = Rated_kVA; I_Out = VA_Out / V_Out; changed = false; } if(VA_Out < 0){ VA_Out = 0; I_Out = 0; changed = false; } if(phaseAOut){ if (phaseA_V_Out < (V_Rated_A - margin)){ phaseA_I_Out = phaseA_I_Out_prev + I_step_max/2; changed = true; }else if (phaseA_V_Out > (V_Rated_A + margin)){ phaseA_I_Out = phaseA_I_Out_prev - I_step_max/2; changed = true; }else{changed = false;} }if (phaseBOut){ if (phaseB_V_Out < (V_Rated_B - margin)){ phaseB_I_Out = phaseB_I_Out_prev + I_step_max/2; changed = true; }else if (phaseB_V_Out > (V_Rated_B + margin)){ phaseB_I_Out = phaseB_I_Out_prev - I_step_max/2; changed = true; }else{changed = false;} }if (phaseCOut){ if (phaseC_V_Out < (V_Rated_C - margin)){ phaseC_I_Out = phaseC_I_Out_prev + I_step_max/2; changed = true; }else if (phaseC_V_Out > (V_Rated_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 rectifier 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(phaseAOut){ phaseA_I_Out = VA_Out / phaseA_V_Out; } if(phaseBOut){ phaseB_I_Out = VA_Out / phaseB_V_Out; } if(phaseCOut){ phaseC_I_Out = VA_Out / phaseC_V_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!"); } gl_verbose("rectifier sync: VA_Out requested from parent is: (%f , %f)", VA_Out.Re(), VA_Out.Im()); VA_In = VA_Out / (efficiency * internal_losses); losses = VA_Out * (1 - (efficiency * internal_losses)); gl_verbose("rectifier sync: VA_In after losses is: (%f , %f)", VA_In.Re(), VA_In.Im()); //after we export this current to the generator that is hooked up on the input, //we will expect that during the next timestep, the generator will give us a //new frequency of input power that it has adopted in order to meet the //requested current if(number_of_phases_in == 3){ iterative_IV(VA_In, "D"); } if(number_of_phases_in == 1){ VA_In = VA_In / number_of_phases_in; if(phaseAIn){ power_A_In = VA_In; iterative_IV(power_A_In,"A"); } if(phaseBIn){ power_B_In = VA_In; iterative_IV(power_B_In,"B"); } if(phaseCIn){ power_C_In = VA_In; iterative_IV(power_C_In,"C"); } } //TODO: check P and Q components to see if within bounds gl_verbose("rectifier sync: VA_In is: (%f , %f)", VA_In.Re(), VA_In.Im()); gl_verbose("rectifier sync: power_A_In is: (%f , %f)", power_A_In.Re(), power_A_In.Im()); gl_verbose("rectifier sync: power_B_In is: (%f , %f)", power_B_In.Re(), power_B_In.Im()); gl_verbose("rectifier sync: power_C_In is: (%f , %f)", power_C_In.Re(), power_C_In.Im()); gl_verbose("rectifier sync: voltage_A is: (%f , %f)", voltage_A.Re(), voltage_A.Im()); gl_verbose("rectifier sync: voltage_B is: (%f , %f)", voltage_B.Re(), voltage_B.Im()); gl_verbose("rectifier sync: voltage_C is: (%f , %f)", voltage_C.Re(), voltage_C.Im()); gl_verbose("rectifier sync: current_A is: (%f , %f)", current_A.Re(), current_A.Im()); gl_verbose("rectifier sync: current_B is: (%f , %f)", current_B.Re(), current_B.Im()); gl_verbose("rectifier sync: current_C is: (%f , %f)", current_C.Re(), current_C.Im()); gl_verbose("rectifier sync: constant v rectifier about to exit"); if(changed){ TIMESTAMP t2 = TS_NEVER; return t2; }else{ return TS_NEVER; } } break;*/ default: break; return TS_NEVER; } return TS_NEVER; }