Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

The code looks like it does the job that it advertises. Unfortunately if the case blows up towards the end, you might find that you get some weird looking Q values. Also, because you've arranged the voltages to begin at 0.8 (which is a very low voltage). You may find that it doesn't solve at all and wont produce a Q/V curve except at the strongest buses.

Here are two things I'd do to improve the results you are getting:

  1. Arrange the PU voltages from high to low, rather than from low to high. That way your script will plot more data points before blowing up at the very low voltages.
  2. Check the solution result and stop calculating values once it has blown up.

Here is a quick attempt at re-writing the code.

# PSS/E Saved case
import numpy as np
import matplotlib.pyplot as plt
import psspy

CASE = r"C:\Program Files\PTI\PSSE32\EXAMPLE\12TH_PLAN_MAR_2017R1.sav"
busno = 44999 # Fictitious generator bus
genid = 1
status = 1
pgen = 0.0 # Fict gen P output
Qlimit = 9999.0 # Fict. gen Q limit
pmax = 0.0 # Fict gen P limit
ireg = 44106 # Regulated bus for which QV curve is to be determined

#--------------------------------

def add_machine():
    psspy.plant_data(busno, intgar1=ireg)
    psspy.machine_data_2(
        busno,
        str(genid),
        intgar1=int(status),
        realar1=pgen,
        realar3=Qlimit,
        realar4=-Qlimit,
        realar5=pmax)

def get_mvar(i):
    """
    Changes the voltage set point at the synchronous machine
    solves the case
    returns the the new reactive power output of the sync machine.
    """
    psspy.plant_data(busno, realar1=i)
    ierr = psspy.fnsl()
    ierr, mvar = psspy.macdat(busno, str(genid), 'Q')
    return mvar

psspy.psseinit(12000)
psspy.case(CASE)
psspy.solution_parameters_3(intgar2=60) # set number of solution iterations.

psspy.bus_data_2(busno, intgar1=2, name='TEST')
psspy.branch_data(i=busno, j=ireg)
add_machine()

pu = [x for x in np.arange(1.2, 0.8, .05)]
varlist = [get_mvar(v) for v in pu]

print varlist
plt.plot(pu, varlist, '-o')
plt.xlabel('PU')
plt.ylabel('MVar')
plt.grid()
plt.show()

If I was spending more time on it, i'd even look at ways to pass arguments into add_machine rather than relying on global variables.

click to hide/show revision 2
Added youtube video

(edit) http://www.youtube.com/watch?v=oveciMGcOt4 Watch this: A live recording of how I rewrote the code

The code looks like it does the job that it advertises. Unfortunately if the case blows up towards the end, you might find that you get some weird looking Q values. Also, because you've arranged the voltages to begin at 0.8 (which is a very low voltage). You may find that it doesn't solve at all and wont produce a Q/V curve except at the strongest buses.

Here are two things I'd do to improve the results you are getting:

  1. Arrange the PU voltages from high to low, rather than from low to high. That way your script will plot more data points before blowing up at the very low voltages.
  2. Check the solution result and stop calculating values once it has blown up.

Here is a quick attempt at re-writing the code.

# PSS/E Saved case
import numpy as np
import matplotlib.pyplot as plt
import psspy

CASE = r"C:\Program Files\PTI\PSSE32\EXAMPLE\12TH_PLAN_MAR_2017R1.sav"
busno = 44999 # Fictitious generator bus
genid = 1
status = 1
pgen = 0.0 # Fict gen P output
Qlimit = 9999.0 # Fict. gen Q limit
pmax = 0.0 # Fict gen P limit
ireg = 44106 # Regulated bus for which QV curve is to be determined

#--------------------------------

def add_machine():
    psspy.plant_data(busno, intgar1=ireg)
    psspy.machine_data_2(
        busno,
        str(genid),
        intgar1=int(status),
        realar1=pgen,
        realar3=Qlimit,
        realar4=-Qlimit,
        realar5=pmax)

def get_mvar(i):
    """
    Changes the voltage set point at the synchronous machine
    solves the case
    returns the the new reactive power output of the sync machine.
    """
    psspy.plant_data(busno, realar1=i)
    ierr = psspy.fnsl()
    ierr, mvar = psspy.macdat(busno, str(genid), 'Q')
    return mvar

psspy.psseinit(12000)
psspy.case(CASE)
psspy.solution_parameters_3(intgar2=60) # set number of solution iterations.

psspy.bus_data_2(busno, intgar1=2, name='TEST')
psspy.branch_data(i=busno, j=ireg)
add_machine()

pu = [x for x in np.arange(1.2, 0.8, .05)]
varlist = [get_mvar(v) for v in pu]

print varlist
plt.plot(pu, varlist, '-o')
plt.xlabel('PU')
plt.ylabel('MVar')
plt.grid()
plt.show()

If I was spending more time on it, i'd even look at ways to pass arguments into add_machine rather than relying on global variables.

(edit) http://www.youtube.com/watch?v=oveciMGcOt4 Watch this: A live recording of how I rewrote the code

The code looks like it does the job that it advertises. Unfortunately if the case blows up towards the end, you might find that you get some weird looking Q values. Also, because you've arranged the voltages to begin at 0.8 (which is a very low voltage). You may find that it doesn't solve at all and wont produce a Q/V curve except at the strongest buses.

Here are two three things I'd do to improve the results you are getting:

  1. Arrange the PU voltages from high to low, rather than from low to high. That way your script will plot more data points before blowing up at the very low voltages.
  2. Check the solution result and stop calculating values once it has blown up.
  3. Split the calculation into two parts. Current PU -> high PU then Current PU -> low PU. This will help you reset the PSSE case so that you can calculate the two parts

Here is a quick attempt at re-writing the code.

# PSS/E Saved case
import numpy as np
import matplotlib.pyplot as plt
import psspy

CASE = r"C:\Program Files\PTI\PSSE32\EXAMPLE\12TH_PLAN_MAR_2017R1.sav"
busno = 44999 # Fictitious generator bus
genid = 1
status = 1
pgen = 0.0 # Fict gen P output
Qlimit = 9999.0 # Fict. gen Q limit
pmax = 0.0 # Fict gen P limit
ireg = 44106 # Regulated bus for which QV curve is to be determined

#--------------------------------

def add_machine():
    psspy.plant_data(busno, intgar1=ireg)
    psspy.machine_data_2(
        busno,
        str(genid),
        intgar1=int(status),
        realar1=pgen,
        realar3=Qlimit,
        realar4=-Qlimit,
        realar5=pmax)

def get_mvar(i):
    """
    Changes the voltage set point at the synchronous machine
    solves the case
    returns the the new reactive power output of the sync machine.
    """
    psspy.plant_data(busno, realar1=i)
    ierr = psspy.fnsl()
    ierr, mvar = psspy.macdat(busno, str(genid), 'Q')
    return mvar

psspy.psseinit(12000)
psspy.case(CASE)
psspy.solution_parameters_3(intgar2=60) # set number of solution iterations.

psspy.bus_data_2(busno, intgar1=2, name='TEST')
psspy.branch_data(i=busno, j=ireg)
add_machine()

pu = [x for x in np.arange(1.2, 0.8, .05)]
varlist = [get_mvar(v) for v in pu]

print varlist
plt.plot(pu, varlist, '-o')
plt.xlabel('PU')
plt.ylabel('MVar')
plt.grid()
plt.show()

If I was spending more time on it, i'd even look at ways to pass arguments into add_machine rather than relying on global variables.

click to hide/show revision 4
Account for waltterval's suggestion about the negative step size

(edit) http://www.youtube.com/watch?v=oveciMGcOt4 Watch this: A live recording of how I rewrote the code

The code looks like it does the job that it advertises. Unfortunately if the case blows up towards the end, you might find that you get some weird looking Q values. Also, because you've arranged the voltages to begin at 0.8 (which is a very low voltage). You may find that it doesn't solve at all and wont produce a Q/V curve except at the strongest buses.

Here are three things I'd do to improve the results you are getting:

  1. Arrange the PU voltages from high to low, rather than from low to high. That way your script will plot more data points before blowing up at the very low voltages.
  2. Check the solution result and stop calculating values once it has blown up.
  3. Split the calculation into two parts. Current PU -> high PU then Current PU -> low PU. This will help you reset the PSSE case so that you can calculate the two parts

Here is a quick attempt at re-writing the code.

# PSS/E Saved case
import numpy as np
import matplotlib.pyplot as plt
import psspy

CASE = r"C:\Program Files\PTI\PSSE32\EXAMPLE\12TH_PLAN_MAR_2017R1.sav"
busno = 44999 # Fictitious generator bus
genid = 1
status = 1
pgen = 0.0 # Fict gen P output
Qlimit = 9999.0 # Fict. gen Q limit
pmax = 0.0 # Fict gen P limit
ireg = 44106 # Regulated bus for which QV curve is to be determined

#--------------------------------

def add_machine():
    psspy.plant_data(busno, intgar1=ireg)
    psspy.machine_data_2(
        busno,
        str(genid),
        intgar1=int(status),
        realar1=pgen,
        realar3=Qlimit,
        realar4=-Qlimit,
        realar5=pmax)

def get_mvar(i):
    """
    Changes the voltage set point at the synchronous machine
    solves the case
    returns the the new reactive power output of the sync machine.
    """
    psspy.plant_data(busno, realar1=i)
    ierr = psspy.fnsl()
    ierr, mvar = psspy.macdat(busno, str(genid), 'Q')
    return mvar

psspy.psseinit(12000)
psspy.case(CASE)
psspy.solution_parameters_3(intgar2=60) # set number of solution iterations.

psspy.bus_data_2(busno, intgar1=2, name='TEST')
psspy.branch_data(i=busno, j=ireg)
add_machine()

pu = [x for x in np.arange(1.2, 0.8, .05)]
-0.05)]
varlist = [get_mvar(v) for v in pu]

print varlist
plt.plot(pu, varlist, '-o')
plt.xlabel('PU')
plt.ylabel('MVar')
plt.grid()
plt.show()

If I was spending more time on it, i'd even look at ways to pass arguments into add_machine rather than relying on global variables.