{
2-17-00 Change Log
Added Angle to VMag calculation
6-18-00 Added ability to do specify impedance in ohms or short circuit current
5-17-01 Moved Spectrum to Base class
2-10-09 Converted to 2-terminal voltage source
// define Property help values
PropertyHelp[1] := 'Name of bus to which the main terminal (1) is connected.'+CRLF+'bus1=busname'+CRLF+'bus1=busname.1.2.3';
PropertyHelp[2] := 'Base Source kV, usually phase-phase (L-L) unless you are making a positive-sequence model or 1-phase model'+
'in which case, it will be phase-neutral (L-N) kV.';
PropertyHelp[3] := 'er unit of the base voltage that the source is actually operating at.'+ CRLF +
'"pu=1.05"';
PropertyHelp[4] := 'hase angle in degrees of first phase: e.g.,Angle=10.3';
PropertyHelp[5] := 'Source frequency. Defaults to system default base frequency.';
PropertyHelp[6] := 'Number of phases. Defaults to 3.';
PropertyHelp[7] := 'MVA Short circuit, 3-phase fault. Default = 2000. ' +
'Z1 is determined by squaring the base kv and dividing by this value. '+
'For single-phase source, this value is not used.';
PropertyHelp[8] := 'MVA Short Circuit, 1-phase fault. Default = 2100. ' +
'The "single-phase impedance", Zs, is determined by squaring the base kV and dividing by this value. '+
'Then Z0 is determined by Z0 = 3Zs - 2Z1. For 1-phase sources, Zs is used directly. ' +
'Use X0R0 to define X/R ratio for 1-phase source.';
PropertyHelp[9] := 'ositive-sequence X/R ratio. Default = 4.';
PropertyHelp[10] := 'Zero-sequence X/R ratio.Default = 3.';
PropertyHelp[11] := 'Alternate method of defining the source impedance. ' + CRLF +
'3-phase short circuit current, amps. Default is 10000.';
PropertyHelp[12] := 'Alternate method of defining the source impedance. ' + CRLF +
'single-phase short circuit current, amps. Default is 10500.';
PropertyHelp[13] := 'Alternate method of defining the source impedance. ' + CRLF +
'ositive-sequence resistance, ohms. Default is 1.65.';
PropertyHelp[14] := 'Alternate method of defining the source impedance. ' + CRLF +
'ositive-sequence reactance, ohms. Default is 6.6.';
PropertyHelp[15] := 'Alternate method of defining the source impedance. ' + CRLF +
'Zero-sequence resistance, ohms. Default is 1.9.';
PropertyHelp[16] := 'Alternate method of defining the source impedance. ' + CRLF +
'Zero-sequence reactance, ohms. Default is 5.7.';
PropertyHelp[17] := '{pos*| zero | none} Maintain specified sequence for harmonic solution. Default is positive sequence. '+
'Otherwise, angle between phases rotates with harmonic.';
PropertyHelp[18] := 'Name of bus to which 2nd terminal is connected.'+CRLF+'bus2=busname'+CRLF+'bus2=busname.1.2.3' +
CRLF + CRLF +
'Default is Bus1.0.0.0 (grounded wye connection)';
ActiveProperty := NumPropsThisClass;
inherited DefineProperties; // Add defs of inherited properties to bottom of list
// Override help string
PropertyHelp[NumPropsThisClass+1] := 'Name of harmonic spectrum for this source. Default is "defaultvsource", which is defined when the DSS starts.';
End;
//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Function TVsource.NewObject(const ObjName:String):Integer;
Begin
// Make a new voltage source and add it to Vsource class list
With ActiveCircuit Do
Begin
ActiveCktElement := TVsourceObj.Create(Self, ObjName);
Result := AddObjectToList(ActiveDSSObject);
End;
End;
// Special handling for Bus 1
// Set Bus2 = Bus1.0.0.0
BEGIN
WITH ActiveVSourceObj DO BEGIN
SetBus(1, S);
// Default Bus2 to zero node of Bus1. (Grounded-Y connection)
// Strip node designations from S
dotpos := Pos('.',S);
IF dotpos>0 THEN S2 := Copy(S,1,dotpos-1)
ELSE S2 := Copy(S,1,Length(S)); // copy up to Dot
FOR i := 1 to Fnphases DO S2 := S2 + '.0'; // append series of ".0"'s
Begin
// continue parsing with contents of Parser
ActiveVSourceObj := ElementList.Active;
ActiveCircuit.ActiveCktElement := ActiveVSourceObj;
Result := 0;
WITH ActiveVSourceObj DO Begin
ParamPointer := 0;
ParamName := Parser.NextParam;
Param := Parser.StrValue;
WHILE Length(Param) > 0 DO Begin
IF Length(ParamName) = 0 THEN Inc(ParamPointer)
ELSE ParamPointer := CommandList.GetCommand(ParamName);
If (ParamPointer > 0) and (ParamPointer <= NumProperties) Then PropertyValue[ParamPointer] := Param;
CASE ParamPointer OF
0: DoSimpleMsg('Unknown parameter "' + ParamName + '" for Object "VSource.'+Name+'"', 320);
1: VSourceSetBus1(param); // special handling of Bus 1
2: kVBase := Parser.DblValue; // basekv
3: PerUnit := Parser.DblValue; // pu
4: Angle := Parser.DblValue; // Ang
5: SrcFrequency := Parser.DblValue; // freq
6: Begin
Nphases := Parser.Intvalue; // num phases
NConds := Fnphases; // Force Reallocation of terminal info
End;
7: MVAsc3 := Parser.DblValue; // MVAsc3
8: MVAsc1 := Parser.DblValue; // MVAsc1
9: X1R1 := Parser.DblValue; // X1/R1
10: X0R0 := Parser.DblValue; // X0/R0
11: Isc3 := Parser.DblValue;
12: Isc1 := Parser.DblValue;
13: R1 := Parser.DblValue;
14: X1 := Parser.DblValue;
15: R0 := Parser.DblValue;
16: X0 := Parser.DblValue;
17:Case Uppercase(Param)[1] of
'': ScanType := 1;
'Z': ScanType := 0;
'N': ScanType := -1;
ELSE
DoSimpleMsg('Unknown Scan Type for "' + Class_Name +'.'+ Name + '": '+Param, 321);
END;
18: SetBus(2, param);
ELSE
ClassEdit(ActiveVsourceObj, ParamPointer - NumPropsThisClass)
End;
// Set the Z spec type switch depending on which was specified.
CASE ParamPointer OF
7, 8 :ZSpecType := 1;
11, 12 :ZSpecType := 2;
13, 14, 15, 16 : ZSpecType := 3;
END;
//----------------------------------------------------------------------------
Function TVsource.MakeLike(Const OtherSource:String):Integer;
VAR
OtherVSource :TVSourceObj;
i :Integer;
Begin
Result := 0;
{See if we can find this line name in the present collection}
OtherVSource := Find(OtherSource);
IF OtherVSource<>Nil THEN
WITH ActiveVsourceObj DO Begin
IF Fnphases <> OtherVSource.Fnphases THEN Begin
Nphases := OtherVSource.Fnphases;
NConds := Fnphases; // Forces reallocation of terminal stuff
For i := 1 to ParentClass.NumProperties Do FPropertyValue := OtherVsource.FPropertyValue;
Result := 1;
End
ELSE DoSimpleMsg('Error in Vsource MakeLike: "' + OtherSource + '" Not Found.', 322);
End;
//----------------------------------------------------------------------------
Function TVsource.Init(Handle:Integer):Integer;
Begin
DoSimpleMsg('Need to implement TVsource.Init', -1);
Result := 0;
End;
//=============================================================================
Constructor TVsourceObj.Create(ParClass:TDSSClass; const SourceName:String);
Begin
Inherited create(ParClass);
Name := LowerCase(SourceName);
DSSObjType := ParClass.DSSClassType; //SOURCE + NON_PCPD_ELEM; // Don't want this in PC Element List
Nphases := 3;
Fnconds := 3;
Nterms := 2; // Now a 2-terminal device
Z := nil;
Zinv := nil;
{Basefrequency := 60.0;} // set in base class
MVAsc3 := 2000.0;
MVAsc1 := 2100.0;
ZSpecType := 1; // default to MVAsc
R1 := 1.65;
X1 := 6.6;
R0 := 1.9;
X0 := 5.7;
Isc3 := 10000.0;
Isc1 := 10540.0;
kVBase := 115.0;
X1R1 := 4.0;
X0R0 := 3.0;
PerUnit := 1.0;
SrcFrequency := BaseFrequency;
Angle := 0.0;
Scantype := 1;
Spectrum := 'defaultvsource';
InitPropertyValues(0);
Yorder := Fnterms * Fnconds;
RecalcElementData;
End;
//=============================================================================
Destructor TVsourceObj.Destroy;
Begin
Z.Free;
Zinv.Free;
Inherited Destroy;
End;
//=============================================================================
Procedure TVsourceObj.RecalcElementData;
VAR
Zs,Zm :Complex;
i,j :Integer;
Factor :Double;
Rs, Xs, Rm, Xm :Double;
Begin
IF Z <> nil THEN Z.Free;
IF Zinv <> nil THEN Zinv.Free;
// For a Source, nphases = ncond, for now
Z := TCmatrix.CreateMatrix(Fnphases);
Zinv := TCMatrix.CreateMatrix(Fnphases);
If FNPhases = 1 THEN Factor := 1.0 ELSE Factor := SQRT3;
Rs := 0.0;
Rm := 0.0;
Xs := 0.1;
Xm := 0.0;
{Calculate the short circuit impedance and make all other spec types agree}
CASE ZSpecType OF
1:Begin // MVAsc
X1 := Sqr(KvBase) / MVAsc3/Sqrt(1.0 + 1.0/Sqr(X1R1));
Xs := Sqr(KvBase) / MVAsc1/Sqrt(1.0 + 1.0/Sqr(X0R0)); // Approx
R1 := X1 / X1R1;
Xm := Xs - X1;
X0 := (Xs + 2.0 * Xm);
R0 := X0 / X0R0;
Isc3 := MVAsc3 * 1000.0 /(SQRT3 * kVBase);
Isc1 := MVAsc1 * 1000.0 /(Factor * kVBase);
IF Fnphases = 1 THEN Rs := Xs / X0R0
ELSE Rs := (2.0 * R1 + R0) / 3.0;
SpectrumObj := SpectrumClass.Find(Spectrum);
IF SpectrumObj=NIL Then Begin
DoSimpleMsg('Spectrum Object "' + Spectrum + '" for Device Vsource.'+Name+' Not Found.', 324);
End;
Var
Value :Complex;
i, j :Integer;
FreqMultiplier:Double;
Begin
// Build only YPrim Series
IF YPrimInvalid THEN Begin
IF YPrim_Series <> nil Then YPrim_Series.Free;
YPrim_Series := TcMatrix.CreateMatrix(Yorder);
IF YPrim <> nil Then YPrim.Free;
YPrim := TcMatrix.CreateMatrix(Yorder);
End
ELSE Begin
YPrim_Series.Clear;
YPrim.Clear;
End;
{ Put in Series RL Adjusted for frequency }
For i := 1 to Fnphases Do Begin
For j := 1 to Fnphases Do Begin
Value := Z.GetElement(i, j);
Value.im := Value.im * FreqMultiplier; {Modify from base freq}
Zinv.SetElement(i, j, value);
End;
End;
Zinv.Invert; {Invert in place}
If Zinv.InvertError>0 Then
Begin {If error, put in Large series conductance}
DoErrorMsg('TVsourceObj.CalcYPrim', 'Matrix Inversion Error for Vsource "' + Name + '"',
'Invalid impedance specified. Replaced with small resistance.', 325);
Zinv.Clear;
For i := 1 to Fnphases Do Zinv.SetElement(i, i, Cmplx(1.0/EPSILON, 0.0));
End;
// YPrim_Series.CopyFrom(Zinv);
For i := 1 to FNPhases do Begin
For j := 1 to FNPhases do Begin
Value := Zinv.GetElement(i, j);
YPrim_series.SetElement(i, j, Value);
YPrim_series.SetElement(i + FNPhases, j + FNPhases, Value);
YPrim_series.SetElemsym(i + FNPhases, j, CNegate(Value))
End;
End;
YPrim.CopyFrom(YPrim_Series);
{Now Account for Open Conductors}
{For any conductor that is open, zero out row and column}
Inherited CalcYPrim;
Var
i :Integer;
Vharm :Complex;
SrcHarmonic :Double;
Begin
TRY
{This formulation will theoretically handle voltage sources of any number of phases assuming they are
equally displaced in time.}
CASE Fnphases OF
1:Vmag := kVBase * PerUnit * 1000.0;
ELSE
Vmag := kVBase * PerUnit * 1000.0/2.0/Sin((180.0/Fnphases)*PI/180.0);
End;
WITH ActiveCircuit.Solution Do
IF IsHarmonicModel THEN Begin
SrcHarmonic := Frequency/SrcFrequency;
Vharm := CMulReal(SpectrumObj.GetMult(SrcHarmonic), Vmag); // Base voltage for this harmonic
RotatePhasorDeg(Vharm, SrcHarmonic, Angle); // Rotate for phase 1 shift
FOR i := 1 to Fnphases Do Begin
Vterminal^ := Vharm;
VTerminal^[i+Fnphases] := CZERO;
If (i < Fnphases) Then Begin
CASE ScanType of
1: RotatePhasorDeg(Vharm, 1.0, -360.0/Fnphases); // maintain pos seq
0: ; // Do nothing for Zero Sequence; All the same
Else
RotatePhasorDeg(Vharm, SrcHarmonic, -360.0/Fnphases); // normal rotation
END;
End;
End;
End ELSE Begin
If abs(Frequency - SrcFrequency) > EPSILON2 Then Vmag:=0.0; // Solution Frequency and Source Frequency don't match!
{NOTE: RE-uses VTerminal space}
FOR i := 1 to Fnphases DO Begin
CASE ScanType of
0: Vterminal^ := pdegtocomplex(Vmag, (360.0 + Angle) ); // all the same for zero sequence
Else
Vterminal^ := pdegtocomplex(Vmag, (360.0 + Angle - (i-1)* 360.0/Fnphases) );
END;
VTerminal^[i+Fnphases] := CZERO; // See comments in GetInjCurrents
End;
End;
EXCEPT
DoSimpleMsg('Error computing Voltages for Vsource.'+Name+'. Check specification. Aborting.', 326);
IF In_Redirect Then Redirect_Abort := TRUE;
END;
Begin
TRY
WITH ActiveCircuit.Solution
DO Begin
//FOR i := 1 TO (Nterms * NConds) DO Vtemp^ := V^[NodeRef^];
// This is safer 12/7/99
FOR i := 1 TO Yorder DO Vterminal^ := NodeV^[NodeRef^];
YPrim.MVMult(Curr, Vterminal); // Current from Elements in System Y
GetInjCurrents(ComplexBuffer); // Get present value of inj currents
// Add Together with yprim currents
FOR i := 1 TO Yorder DO Curr^ := Csub(Curr^, ComplexBuffer^);
End; {With}
EXCEPT
On E: Exception
Do DoErrorMsg(('GetCurrents for Element: ' + Name + '.'), E.Message,
'Inadequate storage allotted for circuit element.', 327);
End;
With ParentClass Do
For i := 1 to NumProperties Do
Begin
Writeln(F,'~ ',PropertyName^,'=',PropertyValue);
End;
If Complete Then Begin
Writeln(F);
Writeln(F,'BaseFrequency=',BaseFrequency:0:1);
Writeln(F,'VMag=',VMag:0:2);
Writeln(F,'Z Matrix=');
FOR i := 1 to Fnphases DO Begin
FOR j := 1 to i DO Begin
c := Z.GetElement(i,j);
Write(F, Format('%.8g +j %.8g ',[C.re, C.im ]));
End;
Writeln(F);
End;
End;
End;
//=============================================================================
procedure TVsourceObj.InitPropertyValues(ArrayOffset: Integer);
begin
//=============================================================================
function TVsourceObj.GetPropertyValue(Index: Integer): String;
begin
Case Index of
7 : Result := Format('%-.5g',[MVAsc3]);
8 : Result := Format('%-.5g',[MVAsc1]);
11 : Result := Format('%-.5g',[Isc3]);
12 : Result := Format('%-.5g',[Isc1]);
13 : Result := Format('%-.5g',[R1]);
14 : Result := Format('%-.5g',[X1]);
15 : Result := Format('%-.5g',[R0]);
16 : Result := Format('%-.5g',[X0]);
Else
Result := Inherited GetPropertyValue(Index);
End;
end;
S :='hases=1 ';
S := S + Format('BasekV=%-.5g ', [kVbase/SQRT3]);
S := S + Format('R1=%-.5g ', [R1]);
S := S + Format('X1=%-.5g ', [X1]);