Three Phase Standalone Inverter with L Filter

The circuit files for this case are in these two links:
circuit_files.zip
circuit_files.tar.gz

If you are here to know how to use control functions in the simulator, read this post and run the simulator with the circuit files in the above links. To start, as usual, run the file circuit_solver.py and enter the file standalone_inv as the circuit file. No need to add the .csv extension. The file standalone_inv.csv is in the links above. The parameter file standalone_inv_params.csv can also be found in the links above.








Now comes the part about controls. There are two control files in this simulation - one is the phase angle generator angle_gen.py and the other is the current controller currcont_3ph.py. The simulator asks for the control files and these two are entered as shown above. As before without the .py extension. A simulation can contain a single control file or multiple. The purpose of this example is to show how to use multiple control files and more importantly how to exchange signals between control files. This way, you can design cascaded control or embedded control functions.

The next part - the descriptor files. Every control file used in the simulation will have a descriptor file. In this case - angle_gen_desc.csv and currcont_3ph_desc.csv. The purpose of a descriptor file is to define the interface of the control file - the inputs, outputs, static variables, time events and storage variables. More on this:
  • Inputs: The inputs to a control file are from meters - ammeters and voltmeters.
  • Outputs: The outputs of a control file are to components that have controls.
  • Static variables: Typically any variable used within a function exists only within the function. Similarly, all variables that you use within a function will have a value only in a particular iteration of the function. If you want to access the variable in the next simulation run, you can't. To solve this problem, declare the variable in the descriptor file of the control function as a static variable. Now the value of the variable will be stored and will be available in the next simulation run.
  • Time events: A control function can run at a frequency different from the simulator. It can be slower or even faster. For this reason, you can define variables as time events and update them in your control code to choose when to run the control code. The simulator will arrange all the time events generated by all the control code in ascending order along with the user defined simulation time step and will choose the next simulation time to be the first in the list. So if a control code is slower than the simulation time, the simulator will run more or less at the simulation time steps. However, if the control code is faster or asynchronous to the simulation time step, the simulator could run at any time step the control function causes a change in its outputs.
  • Variable storage: There are two purposes of these. The first is if you want to debug a control code and want to check what are intermediate signals in the control code, you could use this to plot these variables. The other purpose is to link control functions together. The special property of the these are that a variable defined as VariableStorage can occur only once in all the control functions in a simulator. However, if defined in any of the control functions, they are available in all control functions. So, a variable defined as VariableStorage could be defined in one descriptor file and be accessed in another control function and also plotted at the same time. This way control signals can be passed between control code.

With the above background, time to go into details with actual code. First the angle_gen.py code.

import math
				
dt_sample = 100.0e-6
omega = 2*3.141*60.0

if t_clock>=t1:
	ph_angle += omega*dt_sample
	if (ph_angle > 2*math.pi):
		ph_angle = 0.0
	t1 = t1 + dt_sample
control_ph_angle = ph_angle
											

The above code can be described in the following way:
  • dt_sample=100.0e-6 implies that this control code should run every 100 microseconds.
  • The frequency of the signal is 60 Hz or 377 rad/s.
  • t_clock is a reserved variable in the simulator. It is available in every control function and provides the simulation time instant. When t_clock is greater than a defined time event t1, the block is executed.
  • The phase angle is generated as a sawtooth waveform with frequency of 60Hz. The phase angle is limited to 0 to 2pi.
  • At the end of the block, the time event t1 is incremented by dt_sample which is 100 microseconds. This way the block executes every 100 microseconds.
  • control_ph_angle is the "output" of the control function. Typically an output of a control function is fed to a controllable element. In this case, all that is done is a phase angle of a frequency is generated. Therefore, the phase angle is a signal that needs to be available to another control function and that is the current controller currcont_3ph.py.
The screenshot below shows the descriptor for angle_gen_desc.csv.






The control function does not have any inputs because there is no need for any. There are no outputs either as the function does not directly affect any controllable component. ph_angle is defined a static variable. This is because of the statement:
ph_angle += omega*dt_sample
This implies ph_angle uses its previous value to compute its current value. Therefore, the value of ph_angle has to be stored for future use and so it is defined as a static variable.
The next row is the definition of the time event t1. From the control code above, t1 is progressed by steps of 100 microseconds so that the control code runs every 100 microseconds when compared the simulation time instant. This could have been a static variable also. Except that time event has a special significance for the simulator. When t1 is updated in the control code, it generates a time event. There could be multiple time events generated in a control code. And there could be several control codes that generate several time events. What the simulator does is to arrange all these time events so that it knows the closest time event from the present instant of time. This is then combined with the next intended simulation time instant generated with the constant simulation time step. The simulator will choose the next simulation time instant to be closes time event or the next simulation time instant whichever is nearer. So time events are a way to control the run frequency of the simulator besides also deciding how often the control code is run.
The last row is the tricky part. The angle generator produces a phase angle that will be used by the current controller. Therefore the phase angle is not an Output. So to make the ph_angle available to the current controller or for that matter any other controller, it is defined as VariableStorage. This means the control variable is stored in a "global" space where it is available for all control functions. Since, this is similar to a global variable, a variable defined as VariableStorage cannot be defined in another control function. However, it can be used and also modified in another function. Since, it is a global variable, care should be taken while using this variable in control functions. To show how this is used, the current controller will be described next.
currcont_3ph.py:
  • There are two sample rates in this control code. One block runs every 100 microseconds (dt_sample). The other runs every 1 microsecond (dt_carr).
  • The ph_angle is obtained from VariableStorage control_ph_angle in line 14. As said before, any variable defined as VariableStorage can be accessed and changed in any control code. In this case it is merely accessed.
To know more about the interface of the control code, the screenshot of the descriptor file is:






For every control code that you specify, the simulator generates a template descriptor file for you to be able to edit. So you use that as a starting point or use the files provided in the link. The input can be any meter and there can be multiple inputs limited by as many meters there are in the circuit. The name of the input is as it appears in the circuit file. The next column asks you how you want to access the input in the control function. The variable specified is the variable by which the meter output will be made available to you. Lines 19 and 20 use the variables curr_a, curr_b and curr_c that are the meter outputs.

As for the outputs, there can be multiple outputs and these are also accessed by variable names linked with each control tag. Here it is essential that you get both the element name and the name of the control tag matched. Or else you will have an error when the simulator tries to access a control tag in an element that does not exist.

The definition of static variables is quite similar to the previous case. Try to read the control code and figure out how the control works. The current controller works at 100 microseconds while the pulse width modulator works at 1 microseconds. Try changing some of the control parameters or implement you own control along the same lines as above.

The results are:








From the control code, it can be seen that the current reference for the d axis has been set at 10Amps and q axis at 0Amps. The tracking can be seen from the figure.