Sunday, November 29, 2020

Isolated dc-dc converters - understanding the flow of energy

I have been creating videos on dc-dc converters for close to year. The entire playlist of videos can be found at:

https://www.youtube.com/playlist?list=PL-_jTul4we2TUk7zANWQhGNc6kkJ4hg5J

Typically, when learning power electronics as either an undergraduate or in the early stages of a master's, dc-dc converters are presented one after the other with very little talk about possible links between them or how one could progress from one to the other. During the course of this lecture series, I have been trying to do exactly that - focus on how the converters differ from one another in terms of how the energy flows.

As I have been teaching power electronics, I find that using equations alone to describe the operation of a converter is quite inadequate. Power electronic converters are nonlinear and therefore, equations rarely help to understand how they behave. Equations and analysis can help in designing and optimizing their performance but to understand how they work, it is necessary to understand how energy flows between the different states of the converter and how that fits in with the purpose of the converter.

In the last few weeks, I have been gradually approaching the flyback converter topology. The reason I say I have been gradually approaching this topology is because rather than just present the topology and simulate it, I felt it is necessary to describe how this topology came into being. So, instead of using the opposing winding dot polarity that is characteristic and fundamental in a flyback converter, I use the normal transformer where both winding have a dot polarity at the same (upper) terminal.

The simulation shows what happens when the magnetizing current in the transformer is broken. I show how it is possible to connect a LC filter at the secondary winding to produce a filtered output voltage and additionally how a freewheel diode can be used to ensure the continuity of current through the filter inductor, the main problem arises with the magnetic energy in the transformer having nowhere to go during one stage of the converter operation.

With almost every topology of isolated converters, the main question arises about how to ensure the energy stored in a magnetic component (inductor or transformer) increases and decreases during a switching cycle. If the energy continuously increases which implies the peak current keeps increasing, eventually the inductor or transformer will saturate as the flux corresponding to the peak will be greater than the knee-point of the B-H curve. Additionally, the changes need to happen cyclically and gradually - an increase in current should be following by a decrease.

In general, this is what makes power electronics fascinating - how one can condition power without moving parts but just by ensuring a cyclical flow of power. This is true for any power electronic converter.

Tuesday, October 27, 2020

Fourth Udemy course and second book

 It has been a very long time since I blogged. Quite sadly, my project of writing automatic tests for the circuit simulator has not progressed for several months.

I am in the process of creating my fourth online course for Udemy. This course will cover the basics of control and operation of grid converters. It will start with basic grid topologies, computations performed on grids - peak voltage computation, RMS value computation, frequency estimation. A basic overview of the PWM strategy backed by Fourier series harmonic content of the inverter output voltages will be covered. In terms of control, there will be a coverage of the principle of designing a converter, frequency response plots and how to use these to design controllers. A basic current controller will be designed using this basic technique. The current controller will be a simple PI controller in synchronous reference frame.

My second book will soon be in print. This book is titled Digital Filter Design for Power Engineering Applications using Python: An open source guide. The book is being published by Springer International. Hopefully, the online version will be available in December.

There are a few changes long pending with the circuit simulator. These might be done sometime early in 2021.

Tuesday, June 16, 2020

Third Udemy course and the road ahead

It has been a while since I blogged. Quite a lot has happened in the meantime. I created three online courses that are available on the MOOC website Udemy. They are available in the following links:
Simulating Power Electronic Circuits using Python:
https://www.udemy.com/course/simulating-power-electronic-circuits-using-python/?couponCode=A8E5404EE6DD73D31530

Basics of Digital Signal Processing for Power Engineers:
https://www.udemy.com/course/basics-of-digital-signal-processing-for-power-engineers/?couponCode=0DEFA2CAD031AB8DEEEA

Simulation of Magnetics for Power Electronics using Python:
https://www.udemy.com/course/simulation-of-magnetics-for-power-electronics-using-python/?couponCode=F3803A3E81906B554A6A

I am currently writing a book based on the course material of my second course on digital signal processing. I hope the first draft of the book to be ready by the end of the month.

The next steps will be courses on different topics in power electronics. To begin with, there will be a course on control of single-phase grid connected converters. In this I will go into complete details of how to control the current injected by a single-phase converter that could potentially be used for interfacing a PV panel or a battery or for any other purpose.

I have several courses planned for the future. The eventual objective is to establish an online power electronics university with continuously expanding courses that tackle the latest breakthroughs in power electronics. The objective is to take complex research topics and break them up into courses with simulations for students to be able to learn on their own pace.

A few tentative topics will be as follows. Since, my Master's thesis was on active filters, one course could be on shunt and series active filters in distribution systems. The course will cover techniques of injection and also provide simulation cases with converter topologies and closed loop control strategies. Another potential course will be on UPS and the applications in distributed systems. Going further, I will examine parallel-connected UPS systems to form a microgrid.

Once, I tackle the topic of microgrids, I will then examine integration of renewable energy sources such as a solar PV and wind turbines. I will examine how co-ordinated control of renewable energy sources can result in a smart grid.

To get quick updates on this project, like or follow my Facebook page:
https://www.facebook.com/pythonpowerelectronics
Or follow me on Twitter:
https://twitter.com/pythonpoweretrx

Tuesday, May 5, 2020

Next course on simulation of magnetics

It has been a while since I blogged. Nowadays I am not doing much dev with respect to the circuit simulator. Most of my time is spent in writing my next book on using Python for digital filtering for power engineering and in creating my next course on simulation of transformers using Python Power Electronics. So this blog will be about my writing and my next video course.

The book on digital signal processing using Python is based on the Udemy course Basics of Digital Signal Processing for Power Engineers:
https://www.udemy.com/course/basics-of-digital-signal-processing-for-power-engineers/

While creating the course, I put together the course material (what I would be talking about) for every lecture as just a text file. The idea was to build a story for the course - lecture by lecture, section by section. At the end of the course, I found that the text file was close to 100 pages. This was without any diagrams, simulation results or additional. It seemed a waste to this let this course material be as is as the course itself has become a bestseller on Udemy. So, I started putting this text file together as a book and so far have written four chapters and 117 pages. Another two chapters are remaining after which I will write the introduction and conclusion. And then the hunt for a publisher.

My main objective behind publishing is to write books that are easy to read and break hard-core engineering down into simple understandable text. Another major feature of the book is that all references will be open links - primarily Wikipedia. I am a supported of Wikipedia and use Wikipedia links heavily in my online teaching as well.

The next online course is based on magnetics primarily simulating transformers. Though it is a well reported topic, my reason for digging into it was that in terms of implementation, transformers and magnetics in general are tackled fairly heuristically - mainly by just trial and error. The objective of the course is to bring this entire topic down to basic physics - Faraday's Law, Lenz's, Ampere's Law. In the future, my advanced courses will use magnetics particularly multi-winding transformers and therefore, this course is an introduction to that.

Gradually, the process of creating video courses is becoming far easier and quite enjoyable. The initial agony in filtering out noise from videos is now a thing I laugh about. A decent noise canceling mic is fairly important for recording. My very first course was recorded with a mobile phone headset. I had to wrap myself in a blanket to shield myself from noise as it picked up everything not just in the apartment but in the entire neighbourhood. I had Audacity setup for amplifying audio and removing whatever little noise that remains. I still end up with a minor background hum but I would not worry about that.

With that said, I would like to see how long it takes to record my next course. I have recorded and uploaded 3 hours and 48 minutes of video lectures already in 5 days. At this rate, if all goes well, I should be done by the end of May.

Sunday, February 23, 2020

Philosophy behind the video lectures

It has been a while since I last blogged. Since I am way too busy right now with creating my next Udemy course, I haven't had time to blog about code. So I thought I would blog about the video series that I have been now consistently adding to on a weekly basis. In case you haven't seen any of them, this is the YouTube channel.
https://www.youtube.com/channel/UCxVbKNK18A_a9Ohd0Kb7kNA

The idea for this came from listening to a few podcasts. Initially, I thought of creating a podcast for power electronics, but then realized that I wouldn't be able to convey much just through audio as I usually like to code along. So, I decided with a weekly video on some topic in power electronics. Initially, I used to spend a lot of time preparing them, and for that reason, could only create a new video once in several weeks. But then, I watered it down a bit, and just recorded myself as I casually simulated and now am able to keep my weekly routine.

The main reason for these lectures was to provide a consistent flow of content for someone who wants to learn power electronics but is too busy. The target audience is someone who works as an electrical engineer, would like to level up with their skills to move on to being a design engineer but just can't find the time and due to financial and/or family constraints can't take a few years off to go back and do another degree.

For this reason, these lectures have a bit of theory but the main aspect is that someone who is interested can just code along. All software are free and open source and you could install every software in any operating system that you use. So, the idea is that a student could learn more than just equations from these video lectures.

A part of my philosophy behind creating these videos is similar to Richard Feynman's philosophy of teaching. Pick a topic. Teach it as if you were teaching it to a child who was hearing about it for the first time. Look for where your message didn't go through. Go back and simplify it further.

I have taken many courses on Udemy. One of the problems with adult education is that adults already have responsibilities. The traditional approach to giving homework and expecting them to work on it on their own time will not have much effect as time is what is lacking. So now that I have launched my own courses, I realize the need to make things explicit. And this goes back to Feynman's approach to teaching.

Making these videos has given me to opportunity to get better gradually. And I am enjoying creating videos as it also helps me to relearn what I might have conveniently forgotten.

Wednesday, January 8, 2020

Testing node and branch methods

I have tested the methods in determining nodes and branches. What is left is the main method that calls these methods. The code can be found on:
https://bitbucket.org/shivkiyer/ppe_simulator/src/testing/
https://sourceforge.net/p/pythonpowerelec/code/ci/testing/tree/

And if you would like a full length course on simulating power electronics using Python, check out:
https://www.udemy.com/course/simulating-power-electronic-circuits-using-python/

Here is the code for the tests in command line and web app:



The tests work ok except for a few discrepancies. There is a case in the branch_advance method where an invalid jump does not throw an exception or even return an indication of an error, but rather returns the correct element. For example, while advancing to the right on a branch, the method checks if there is an element to the right of the current element and if that element has already been added to the temporary branch. Legally the advance should occur if the element on the right exists. There could be no jump executed in which case it is simply an element that exists to the right of the last element in the temporary branch. If a jump is executed, the jump direction should be to the right.

However, if the jump executed has a direction of up, down or right, there will be no exception and the element to the right of the current element will be returned. The only time an exception will be generated will be when the jump direction executed will be to the left. The reason this did not cause a major issue was because the methods related to the jump are fairly ok and do not produce wrong jump directions. But in principle, the code is wrong.

The check should be, according to the jump direction, is there an element in that direction? If there is no jump, we could follow some sequence of directions while searching for the next element.

Now that the methods have been tested, the next issue is to test the outer method determine_nodes_branches which calls these methods. At this point, the only was to test this outer method is manually by inputting different circuits. And that doesn't seem like a good way to test as the testing is not at all automatic and how many circuits can I come up with?

This brings me to the next crossroad. I need an automatic circuit builder. This is because things will get more complicated at the next step where I will have to test loops and loop manipulations. I need to generate loops automatically while also introducing errors and bugs in the loops automatically. So, the circuit builder will need to generate circuit topologies only while testing at every stage. For example, I need to start with a simple two node, three branch, two loop circuit and verify that that is generated. Then continuously add nodes and branches automatically to form new loops. The structure should not matter as long as there are a few random jump labels inserted every now and then.

This circuit builder seems very interesting and challenging. The next few blog posts will be dedicated to this.

Thursday, December 12, 2019

Testing jump labels

I finally wrote the first bunch of serious tests with respect to the way the simulator processes circuits. I grouped together a few tests that test the jump labels in a circuit under a class. The code can be found in my bitbucket and sourceforge repos:
https://bitbucket.org/shivkiyer/ppe_simulator/src/testing/
https://sourceforge.net/p/pythonpowerelec/code/ci/testing/tree/

Also, to get a full length course on power electronics simulations, check out my online course:
https://www.udemy.com/course/simulating-power-electronic-circuits-using-python/

The class in the command line interface is:



The functionalities that I am testing for specifically are:
  1. Check whether an element is a component (could also be a wire), a jump label or no connection at all.
  2. A jump must be the extreme element in a branch segment. If it has components on more than one side, that is a violation that throws an exception.
  3. Two jump labels cannot be adjacent to each other - that is a violation that throws an exception.
  4. A jump label cannot be next to a node - a violation that throws an exception.

Most of the tests could be accomplished by a simple assert statement. However, to check if a method throws an exception, I found this block to be most useful:

with pytest.raises(SystemExit):
    ...method...

So, the method or the block of code must throw an error or else the test fails. SystemExit could be replaced by other errors, but in this case, all I do is exit with an error code of 1 and so a SystemExit is all I can check for.

Conversely, if a method or block of code should not throw and error, the test can be written as:

try:
    ...method...
except:
    pytest.fail('This should haved worked')


The class for the web app is a bit different:



The primary reason is that the web application does not exit with an error code when a violation takes place but merely displays the errors to the user on the web browser. So the check is for the result of the methods to be a non null list that would be an error message.

One major advantage of testing was that I found myself investigating code and thinking of possible ways that it could fail. It is a completely different form of coding as opposed to regular development where you are just trying to get the code to work. In testing, you are thinking of ways to break the code. This is a totally different aspect to development that can be fun if you look at it the right way.













Thursday, December 5, 2019

Tested basic spreadsheet operations


The first basic group of tests have been completed. These are tests related to reading circuit schematics and manipulating the elements of the spreadsheet. The latest code can be found in the testing branch in the repositories:


https://bitbucket.org/shivkiyer/ppe_simulator/src/testing/

https://sourceforge.net/p/pythonpowerelec/code/ci/testing/tree/


Most tests gave expected results. The major TODO in this area would be to make the spreadsheets more flexible. Currently, only CSV files can be read and the delimiter has to be a comma. For anyone who is not a hardcore developer, this might be an issue as very few people deal with CSV files on a regular basis. Spreadsheet files are usually .xlsx files or variants depending on the version of Office.

For now, I will continue on testing other parts of the simulator before making logical changes to the code.

Sunday, October 27, 2019

Unit testing of circuit schematic operations - Part I

After setting up the test environments for the command line and the web app in the previous post, I now get started with some serious testing. To begin with, the code for this can be found in the testing branch in either of these two repositories:
https://sourceforge.net/p/pythonpowerelec/code/ci/testing/tree/
https://bitbucket.org/shivkiyer/ppe_simulator/branch/testing

I expanded the testing of csv_element_2D method to the testing of csv_element_2D and csv_tuple_2D as these two methods quite often go hand in hand since one converts a tuple to a string cell position and the vice versa. Here is the code:

There are two types of tests. First, the manual tests are tests where I know there could be a problem and these are the borderline cases - when for example 1Z becomes 1AA or 9A becomes 10A etc. Manual tests can be limited unless you have a lot of time or the function is very complicated and only manual tests are possible. In this case, automatic tests are also possible. For automatic tests, I randomly generate tuples of x (row) and y (column) positions and convert them into string cell positions using csv_element_2D and then convert the resultant cell positions back into tuples using csv_tuple_2D. I chose 20 such iterations and made asserts for each case.

The method can be extended to the Django web app with minor modifications - only the assert statement of pytest will be replaced by assertEqual of TestCase.

Next comes the csv_reader method that takes in a file object which is the .csv file and returns a 2D matrix (lists embedded within a list) representation of the circuit. This is the code:

It is important to write the desired circuit contents to a file. Simply passing the string contents to csv_reader as the argument will not work. This is because when Python opens a file, it creates an iterable object and so you can iterate line by line. However, if I pass a string, the iteration will happen character by character which is not what we want.

I didn't bother with circuit components or circuit topology because what matters here is the reading of the .csv file. A few errors are expected:
  1. If the separator is anything other than a comma, the reading fails.
  2. If one line has an extra character, the reading fails. This is because the expected result is a 2D matrix. This might be ok in most cases, but it might be a good idea to put a catch block in case, some weird spreadsheet software passes through a schematic with unequal line lengths. This should result in a user readable error rather than a syntax error.
  3. The elements are scrubbed internally which means leading and trailing spaces are removed from the elements. This is ok.

Will need to spend some thought on this as spreadsheet software in general are a bit messy and the need to generate .csv files in a particular form may not be obvious to the normal user.

Sunday, October 20, 2019

Starting unit testing in Python Power Electronics

My work as a web developer has introduced me to the wonders of unit testing. No one likes writing tests and neither did I for a very long time. I relied on manual testing like many others. Until I started writing unit tests in Jasmine for my web apps. The number of scenarios that you can test makes your code way more reliable.

Another advantage of testing is that quite often there are changes you would like to make but don't want to make them right now as you might break the code that is working. And in the end these changes never happen as you get too busy with other stuff. Here, test driven development can solve the problem of this inertia. Even if you do not want to change the code itself, test suites can help to totally determine every potential lapse in a block of code that will take away the fear bit by bit of finally getting around to fixing them.

With these noble thoughts, I have finally got over my laziness and decided to write tests for the circuit simulator. As a start, Python comes with the in-built unittest module for writing tests. Django uses this and creates a class TestCase to test API end points. Besides this, Python also has the pytest module that needs to be separately installed.

So, I decided to write unit tests for the command line interface with pytest and for the web app using Django's TestCase class based on unittest. In the beginning, the code for these will be separate. However, with time, the plan will be have one set of tests and also at the same time have one set of code for both web apps.

So, the directory structure for the simulator is:

README
command_line
            --  circuit_solver.py
            --  circuit_elements.py
            --  circuit_exceptions.py
            --  LICENSE.txt
            --  matrix.py
            --  network_reader.py
            --  solver.py

web_app
            -- requirements.txt
            -- simulator_interface
                     -- LICENSE.txt
                     -- manage.py
                     -- simulation_collection
                     -- media_files
                     -- simulator_interface
                                 -- settings.py
                                 -- urls.py
                                 -- wsgi.py
                     -- simulations
                                 -- circuit_solver.py
                                 -- circuit_elements.py
                                 -- circuit_exceptions.py
                                 -- solver.py
                                 -- network_reader.py
                                 -- matrix.py
                                 -- admin.py
                                 -- views.py
                                 -- models.py
                                 -- tests.py


There may be a few more directories and files, but these are the major ones at least for testing. We will create a tests directory inside command_line directory and house the command line app tests there. We will remove the tests.py file inside the simulations directory  inside web_app/simulator_interface and create a tests directory for the web app tests.

To install pytest, just do:
pip install pytest

For the command line app, I decided to get started with testing by writing a very simple test for the function csv_element_2D:



This function takes a tuple/list that represents a row, column position and converts it to a string that represents the cell position. So, [0,0] will be "1A" on a spreadsheet. So, a test for this function in the the command_line app would be:



The test itself if very simple. We import the method from the file network_reader.py that has the method. The test function has to start with test_ for pytest to execute it. The asset method in pytest merely asserts that for the test to pass, the value returned by the function for a particular argument has to be equal to a certain value.

The challenge in getting this test to run was in pytest being able to find the file/module network_reader.py. For this the first block of code above the function had to be written. I had to extract the parent method and insert it into the python path so that Python will look in that directory for the module and import it.

The test for the web app was a bit easier as I didn't have to struggle with path as much. The only challenge was I was trying to use pytest and it would not work as pytest for some reason could not find django module that is imported in the web app modules. The reason I can think of is in Django 2 onwards, the app needs to be loaded and therefore, django is not available until the app is working. For this, I had to go with the default Django TestCase class.



To run these tests. Inside command_line directory, just run the command:
pytest

There are several arguments that can be passed and I will investigate as time goes on. For the web app, inside the directory that contains manage.py, run:
python manage.py test simulations

The app name simulations is important because the tests directory with the test is inside the simulations app directory.


Friday, March 15, 2019

Second failed attempt at linear model of an LCL filter

In my previous blog post, I had described how trying to approximate a differential of Ldi/dt with a linear model is probably impossible. However, there was a flaw in the first linear model that I attempted between the filter capacitor voltage, the grid current and the grid voltage. I had chosen a case where the grid current were always in quadrature to the grid voltage and the filter capacitor voltage has the same template as the grid voltage.

So, to check out if the flaw would result in any improvement, I used a training model where the filter capacitor voltages were different from the grid voltages both by magnitude and by phase. The result was an equally flawed linear model.

vcf = -0.2091*igrid_ref + 1.1028*vgrid

As is evident, this model is even worse that the previous one. Because of the phase angle variation, the model has chosen a larger multiplying factor for the grid voltage of 1.1028 but has tried to compensate with a larger resistance of 0.2091 which is useless in the face of the multiplying factor to the grid voltage.

So, the conclusion is that trying to approximate a differential in this manner by a linear model using linear regression is quite useless. So, I need to step back and figure out what the major challenge with controlling the current through the grid inductor of a LCL filter is.

The transfer function between the inverter and the final grid current is a 3rd order polynomial. Physically, the challenge is in accurately regulating the filter capacitor voltage so as to regulate the grid current to a desired value. The simplest control that can be achieved in this case is controlling the current immediately at the output of the inverter. In that cases, the transfer function between the inverter current and the inverter voltage (or modulation index) is a first order polynomial.

The problem is that inverter output current and the grid current will differ by a current that flows through the filter capacitor. Again, the problem would boil to estimating the current flowing through the filter capacitor. So, to avoid any form of estimation either of current or of voltages, how do we achieve a closed loop control of the final grid current without any synchronous transformation?

The reason why I avoid synchronous transformation is that it transforms the grid current to dc values. This assumes that there are no harmonics are intended to be injected in the grid currents because if the converter is a harmonic filter and is expected to inject harmonics into the grid, the synchronous transformation will have to be performed for every harmonic.

So with these objectives laid out, I will find better ways to control the inverter with advanced concepts of machine learning.

Monday, March 11, 2019

Failed first attempt at linear model for inverter with LCL filter

In the previous blog post, I had attempted to create a linear model to predict the reference for the filter capacitor voltage such that the current injected into the grid will track it's reference. And when I saw the linear model, I had the feeling, it would probably not work. And it didn't.

The linear model that the LinearRegression module with scikit.linear_model gave me was:

vcf_ref = -0.01157 + 0.04176*igrid_ref + 1.0587*vgrid

Seems elegant and when I tried to fit it to the test set, I got a cluster that fell along a linear line. All this seemed wonderful as an application of machine learning to power electronics. But looking at it from a power electronics perspective, what did I get?

vcf_ref = vdc + Remu*igrid_ref + K*vgrid

Where vdc is a dc bias that apparently the linear model feels is needed. Though there should not be a dc bias needed in an ac system unless there is a dc component due to some severe unbalanced harmonic load, this dc bias is fairly small and can be neglected.

The Remu is actually what the linear model approximated the inductor as. The actual equation is:

vcf = vgrid + igrid*R + L* digrid/dt

The linear model has approximated (igrid*R + L* digrid/dt) by Remu (emulated resistance). And this Remu = 0.04176 which is very small given the fact that an inductor is being modeled by this resistor.

The next major problem is the 1.0587*vgrid. We are scaling the grid voltage by 5.8%. And compared to the other two factors, this is the major factor. So really, all that this linear model does to try to create a reference filter capacitor voltage is to scale up the grid voltage by 5.8%. And this is totally inadequate.

Suppose, the current injected into the grid will have to be in-phase with the grid voltage and this would be a requirement for many distributed energy resources. The filter capacitor voltage would need a phase advance with respect to the grid voltage. Or else, it would not be able to produce a grid current in phase with the grid voltage. Because the current through the inductor would be in quadrature and lagging behind the voltage drop across it.

With the above linear model, the filter capacitor voltage would be scaled up by 5% and so in phase with the grid voltage. The voltage drop across the grid inductor would be in phase with the grid voltage and therefore, the current injected into the grid would be lagging behind the grid voltage by 90 degrees. Which is not what we want.

My hypothesis is that what I need is a more detailed and accurate model for the differential operator. And that may need more complicated techniques that a LinearRegression. But before jumping to that, I would like to exhaust any possible solution that linear models have just to gain knowledge.

In all fairness, the linear model that I got from LinearRegression above was a flawed one. Because what I did to train the model was simplistic. To begin with, I had chosen the equilibrium point to be a modulation signal that was the grid voltage scaled by the dc bus:

m = vgrid/vdc

So, the filter capacitor voltage is very close to the grid voltage in magnitude and most importantly in phase as well. To this modulation signal, I had added a random disturbance.

m + mrand*sin(wt)

Here was the mistake - I was giving the random modulation signal perturbation the same phase as the modulation signal. And so, the filter capacitor voltage voltage only changes in magnitude.

And this is exactly why the linear model we ended up with has the major component that scales up the grid voltage by 5%. Because the linear model saw that in a vast majority of cases, that's all there was to it - the capacitor voltage scaled up by small amount and the grid current in quadrature with the grid voltage. So, the linear model assumed this was the ultimate truth and gave that very convenient equation.

So, my second attempt would be to train the linear model making sure that the filter capacitor voltage differed from the grid voltage by not just magnitude by also in phase.

So, check out these two current snapshots in the previous training case:




In both cases, the current is always 90 degrees lagging behind the grid voltage because filter capacitor voltage is in-phase with the grid voltage. So, the linear model thinks this is the norm, this is always how it is.

In contrast, now I am going to add two components to the random shuffle to the modulation index - an in-phase component and a quadrature component. So, the grid current will have a varying phase angle difference with the grid voltage. Below is an example. With this, I am going to try and retrain the linear model. Probably still won't work, but let's see how it changes.




Saturday, March 9, 2019

First attempt at a linear model for an LCL filter

In the previous blog post I described how I am trying to use machine learning to create a functional relationship between the grid voltage and the filter capacitor voltage with respect to the grid current for a dc-ac converter connected to an ac grid through an LCL filter.

So, if that is a bit of a mouthful, here is what it is in a flow:

Inverter - Inductor - Filter Capacitor - Inductor - Grid

The idea is can we determine how much the voltage across the filter capacitor  should be for a particular value of current injected into the grid? The grid voltage can be measured. So, we have:

1. Measured value of grid voltage
2. Reference of current injected into the grid

We need a reference for the voltage across the filter capacitor. Why? Because we have already succeeded in controlling the voltage across with a state feedback controller based on Linear Quadratic Controller.

I ran a free simulation. What that means is I adjusted the modulation index of the dc-ac converter to random values and checked what would be the values of grid voltage, grid current and filter capacitor. All this is for training a machine learning algorithm. And I showed in the previous blog post, the plot of this.

Now, to the next stage. Take the output file and convert it to a .csv file that Pandas can read. Pandas is a data processing package available in Python as part of the PyData library.

This is an extract of the DataFrame which is what you call a database in Pandas:


Time Ammeter_Lfinv Ammeter_Lfgrid Voltmeter_Cfilter Voltmeter_Vgrid inv1trainer_modsignal pwm_carr pwm_s1logic
0 0.00001 -2.968437 -0.003901 -0.095838 0.640844 2.368476e-17 0.200 0.0
1 0.00002 -5.663500 -0.014377 -0.309820 1.217527 2.368476e-17 0.400 0.0
2 0.00003 -8.951290 -0.037764 -0.734868 1.922236 4.946608e-03 0.602 0.0
3 0.00004 -11.932744 -0.070674 -1.276453 2.562736 4.946608e-03 0.800 0.0
4 0.00005 -14.905593 -0.116192 -1.964789 3.203073 9.874666e-03 1.000 0.0

Just the top 5 rows. The data frame has a total of 199999 rows. So that's quite a bit of data.

With this, we are now going to try to create a linear model. What we are trying to do is predict the voltage across the filter capacitor. This will be our output 'y'. The inputs are the grid current which we call x1 (input 1) and the grid voltage x2 (input 2). What we want is:

y = b0 + b1*x1 + b2*x2

If we can achieve this, we have a way to calculate the reference capacitor voltage for any given grid voltage and a reference grid current.

We use linear regression. Linear regression will build exactly the above model with data that we pass to it in order to generate the co-efficients b1 and b2 and the intercept b0. The theory behind it is fairly mathematically intense and maybe I will read about it in detail some day. But in short, linear regression generates these constants by trying to minimize the residual sum of squares for all the data points that we are using to train this model:

RSS = (y1 - b0 - b1*x1_1 - b2*x2_1)^2 + (y2 - b0 - b1*x1_2 - b2*x2_2)^2 + ... +
(yn - b0 - b1*x1_n - b2*x2_n)^2

When there are n samples. We have a total of 199999 samples. But we don't want to use all of them. We want to split them into a training set and a testing set. So, let's do a 70%-30% split - 70% of the data is for training and the rest we will use for testing.

I am using the LinearRegression package available with scikit-learn. As I am getting started with machine learning, I am going to try to keep this simple. I will have to add complexity as I go on. For now, this is a good start.

This is what I do:

y = df['Voltmeter_Cfilter']
x = df[['Ammeter_Lfgrid', 'Voltmeter_Vgrid']]
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3)
inv_model = LinearRegression()
inv_model.fit(x_train, y_train)

The next part is to check how accurate the model is with test data:

predictions = inv_model.predict(x_test)
plt.figure(figsize=(12,8))
sns.scatterplot(x=y_test, y=predictions)


And this is a scatter plot of the prediction of the capacitor voltage versus the actual voltage from the simulation. Most of the scatter lot is in a straight line which is a good sign. But the bad news is that there is some deviation and that deviation is of the order of magnitude of 50V. The filter capacitor and the grid are separated by a small inductor of the order of around 1 mH. Such a difference in voltage of 50V could produce huge spikes in the current.

The final equation turns out to be:

vcf = -0.01157 + 0.04176*igrid + 1.0587*vgrid

Even before trying to simulate this, I am pretty sure it won't work. But still this has been a good first step as I try to apply my rudimentary machine learning in power electronics. I hope as time goes by I will be able to apply more accurate models that can actually be of use.

Wednesday, March 6, 2019

Training a linear model to predict reference converter voltage

After the last post where I thought of mapping a function that links the grid current with the voltage across the filter capacitor:
vcf = f(ic)

Or, if I include the grid voltage as well:
vcf = f(ic, vgrid)

For now, let us try to create a linear model for this function f. And let us just use Python's in-built linear model function to achieve this. I will try to build some theory around it a little later if the results seem promising.

So, to create a linear model, the first step is to generate some training and testing data. For this I am running the simulation in open-loop. To begin with, let us consider a perfectly sinusoidal system without harmonics. So, the way I am doing this training is as follows.

The base case will be when we generate a modulation index which is such that the filter capacitor voltage will be approximately equal to the grid voltage.
m = vgrid/vdc

Where vdc is the dc bus voltage and that is needed to make sure the modulation index is between -1 and +1. From this state of equilibrium, I will add a random sinusoid. So, I created a random array:
numpy.random.rand(10)/10

This will have random floats between 0 and 0.1. I add to the modulation index:
m = vgrid/vdc + random[i]*math.sin(phase_angle)

The counter i will be initialized to 0 but every 0.1s, will be incremented to fetch the next random number. This is applied to PWM. The result is a waveform like this in which I have plotted - the grid voltage, the voltage across the filter capacitor and current injected into the grid. Every 0.1s, the current changes quite often drastically as the modulation signal has changed with the new random value.



A zoom between two changing values:


I am going to let this simulation run to it's limit of 1s. After that will extract the data into a Pandas data frame. And apply machine learning algorithms.

There is a very possibility that I am doing may not be current. We may need help in the control. But I feel this is a great way to learn about a system.

Monday, March 4, 2019

State feedback control of inverter with LCL filter - preliminary investigation

So before I discussed the control of a UPS which a dc-ac converter (single phase for now) with an LC filter at the output. The objective of the controller was to regulate the voltage across the filter capacitor. The state feedback controller was designed using Linear Quadratic Regulator (LQR) and in addition to that a correction was added to the reference to get rid of the steady state error.

The next stage is to control a dc-ac converter with an LCL filter at the output with the objective of the controller being to regulate the current through the final inductor that connects the system to the grid. This is a problem that I have never been able to solve comprehensively and am now going to take another crack at it.

The difference between control of a UPS and the current control of an inverter with LCL filter is the sensitivity of the output with respect to the input. In the case of the UPS, the input is the output of the dc-ac converter which is a voltage in the case of a Voltage Source Converter (VSC). The output of the system is the voltage across the filter capacitor. These ratio of the output to the input is close to unity. And therefore, the controller was much easier to design, the behavior of the controller system much more predictable and the correction of the steady state error was fairly easy.

But, in the case of a dc-ac converter with LCL filter, the input is the converter voltage while the output of the system is the current through the final inductor.  The ratio of the output to the input is very low. Therefore, the controller is quite sensitive. Small changes in the modulation index can result in large changes in the output/grid current.

Suppose the filters were named as follows - Lf the inductor immediately after the converter, Cf the capacitor after Lf, and Lc the inductor that connects the system to the grid. The equation that defines the grid current is:

vf - ic*Rc - Lc*dic/dt - vgrid = 0

The difference in the voltage (vf - vgrid) is what defines the grid current. So, if the state feedback control law is:

m = k1*(if - ifref) + k2*(vf - vfref) + k3*(ic - icref)

The problem is with the second term. The second term will dominate the controller action because of the nature of inputs and quite interestingly the value of k2. I have been using Scilab again to design the state feedback gains and the results are quite interesting.

When the weighting giving to the state variables was Q = diag(0.1, 0.1, 1) which means low weightage to if and vf and high weightage to ic, the state feedback gains were:
k1=3.1852838, k2=4.3873536, k3=7.2589122

Given the magnitudes of vf with respect to if and ic, a value of k2 as above will result in dominating the control output. So, it turns out that the reference for vf becomes critical.

We know the reference for ic as that is the objective of control. It should be possible to do:

vfref = vgrid + Lc*dicref/dt

But you never want to use d/dt in control because it magnifies disturbance. For a sinusoidal fundamental harmonic reference icref, it could be possible to do a decomposition and peform:

vfref_real + j vfref_imag = vgrid + jwLc*(icref_real + icref_imag)

But then, the control cannot be applied to harmonic compensation. So, the question - can we map a function:

vfref = f(icref)

I have only considered using electrical network laws and their approximation so far to do something like the above. But now, with my limited forays into data science and linear regression, this seems like a ripe problem for machine learning. Can we fit a model that is reasonably accurate based on simulations from a vast number of cases? This is what I am going to try to do next - combine machine learning with power electronics!

This a simulation result of what I have achieved so far in terms of current control. As with the previous case - considerable error but most important stable response within a cycle.  A PI controller could take 6-8 cycles to stabilize in contrast. If we solve the problem of steady state error, we could have an incredibly robust controller!



Friday, January 25, 2019

Correcting the steady state error in LQR

So in the previous post I had posted on the state feedback control of a single phase UPS with the state feedback gain designed using Linear Quadratic Regulator (LQR). There were positives and negatives. The positive was that you didn't need synchronous transformation - the control was applied in stationary reference frame. The negative was that there was a steady state error. The main cause for the steady state error was the choice of reference for the inductor current. The reference for inductor current was assumed to be equal to the load current, but this neglects the current drawn by the filter capacitor.

The straightforward way to solve the steady state error issue would be to try to generate a more accurate reference for the inductor current. So, the equation for inductor current would be:

if = Iload + icap

To estimate the filter capacitor current icap, the reference output voltage which is the desired voltage across the filter capacitor can be used:

if = iload + Cf d vo_ref/dt

This can be done and has been done by many many researchers in the past. I too have tried to implement the above. The only tricky part is the d/dt. In control, you do not want to perform differential - never ever. For the simple reason that d/dt magnifies any noise that may be present in the system. So we find ways of generating the signal without d/dt.

Anyway, I have always been thinking - do we need to do this? We know there is an error. So, let's first analyze this error and figure out what it looks like. Assuming the desired reference output voltage is perfectly sinusoidal, this was the tracking performance we saw from the last post.



Next, let's plot the error.



The error between the desired reference output voltage and the actual output voltage is a sinusoidal waveform. Sinusoidal waveforms are nice - periodic, nice shape etc. Most importantly, a sinusoidal waveform is an indication that the reason for the error lies mainly with the choice of the magnitude. Why? If the error was let's say a constant, this would mean the reference and the actual waveforms will be criss-crossing each other. Because, the error is defined as v_ref - v_actual. If the error was some other weird shape, it means it is difficult to predict how the actual voltage tracks the reference. But with a sinusoidal waveform such as the one above, the reference always has a larger magnitude and the actual voltage will differ only by magnitude and not by phase angle. Try drawing some waveforms and check it out for yourself.

So, the next part - the solution. A sinusoidal waveform is nice because it can be defined by several parameters - peak, RMS, frequency etc. The frequency of the sinusoidal waveform will be the same as the system frequency. Well, this might be worth a check. But peak and RMS are related. And RMS is very convenient to calculate.

RMS = Integral ( sqrt(err*err/T) )

Here, T is the time period of the waveform and is also the time interval of integration. Now, there a few ways of doing the above integration. Some (and this includes me before) prefer to do a moving window integration. So, they collect some number of samples - 100, 1000 etc and keep moving the waveform across this window. And they calculate the sum of squares over this window (or array of values). This works. But quite inefficient from the perspective of implementation, if you were to implement in a DSP or FPGA.  You need an array of 1000 elements - not very nice.

A simpler way of doing this integration is to declare a timer for the time period T. Start the sum with 0. And add squares to this sum until the time period expires. At this point, use the sum to calculate RMS and reset the sum and also reset the time period. This is convenient to do using a DSP or FPGA. The result of this is:



And as you can see the RMS has been added to the waveform. It updates every 0.01 seconds. The larger this time period is, the better for accuracy of calculation of the RMS. But is bad for the performance of the controller as the RMS value will be of the previous state until the time interval expires.

So, now what of it? If we know the RMS value (or incidentally the peak value), we can now scale up the reference voltage by that value. The reason, we know this error is going to appear anyway. So, if vref if what we want and verr is the error we get, by manipulating vref to be:

vref' = vref + verr

And applying vref' to the state feedback, the error verr that will anyway result, will now produce a v_actual that is almost equal to v_ref. Check this out:




And you see the difference. After 0.01s, the peak error (RMS*1.414) is added to the desired reference. The result, the actual voltage now catches up with the desired reference that we wanted to begin with. And you see, the tracking is almost perfect, the error is close to zero - tough to see the waveforms apart.

The true test will come when the reference has harmonics - let's add a 5th harmonic component to the desired voltage output.


The tracking is way better than the first 0.01s when the raw state feedback was working. The errors are mainly at the parts where the d/dt of the desired voltage is very high. It is important to note at this point that a controller cannot overcome the design constraints of a system (in this case an inverter). Therefore the maximum d/dt that an inverter can achieve is limited by the choice of dc bus voltage, filter inductor and filter capacitor. So, are those errors the result of our control design or just the way the inverter is and whatever may be the answer, what do we do about it? This will be a future post.

For now, the state feedback controller has achieved both targets - very close tracking with negligible error and also hassle free control implementation - no synchronous transformations etc. Any waveform can be tracked - pure sinusoid or with harmonics.

Saturday, December 8, 2018

Linear Quadratic Regulator control of a single phase UPS with Scilab

So I am gradually getting used to Scilab. The documentation for Scilab is a bit scarce. The first link that I use as reference is the Scilab online help:
https://help.scilab.org/docs/6.0.1/en_US/index.html

Another link that's good for getting started with controls in Scilab is:
https://en.wikibooks.org/wiki/Control_Systems/Open_source_tools/Scilab

Anyway, to get started, I chose a problem that I spent a good amount of time during my PhD - control of a UPS. Typically, a UPS can be controlled with PI controllers in the synchronous reference frame, a topic that I have covered in a tutorial:
http://pythonpowerelectronics.com/contents/tutorials/tutorial7/post.html

Using multi-variable control has some significant advantages - you do not need to design multiple nested loops ensuring that the inner loop is super fast and the outer loop is reasonably fast. Here, there is a single loop. To begin with, a system, in the case, a single-phase UPS, which is an H-bridge inverter with an LC filter at the output, has to be represented in the state space form:

dx/dt = Ax + Bu
y = Cx + Du

Here, x is the state vector. y is the output. And u is the input. There is a very detailed theory behind state space analysis, and I would encourage you to read, if you need to know more. But, for this post, the state variables are those variables that have dynamics - inductor current and capacitor voltage. So,

x = [if Cf]

This is the code snippet for the entire LQR design:


To achieve a 120V RMS voltage output, I have chosen a 300V dc voltage bus (which is a bit of an overkill, but more on that later), a 1milli Henry inductor and a 200 micro Farad capacitor. I have written the dynamical equations at the top as comments and these can be expressed as state space equations with A, B, C, D matrices below that. I will be implementing the state feedback in discrete time and the sampling rate is 20 microseconds.

The first part - controllability of the system. For a system expressed in the state space form, the controllability matrix is:
[B AB]

Again, control theory. Without getting into details, the matrix B, AB, A^2B, .... define the space of vectors that can be achieved with a finite input. So, for a system with 2 states, B and AB, will map a state space. What this means is that the 2 vectors that are B and AB, will be like the x-axis and y-axis of this new space. In the 2 dimensional space, the x-axis and y-axis can be used to express any vector in 2 dimensions. And when any 2 vectors can be used to express any other vector in a 2 dimensional space, the 2 vectors are said to span the space. And if x-axis (1, 0) and y-axis (0,1) are put together as a matrix:
[0 1,
1 0]

This matrix has dimension 2 - which means 2 linearly independent vectors. Linearly independent vectors are vectors who cannot be projected on each other. Mathematically, of course, the definition is a bit more rigorous. A set of vectors v1, v2, ..., vn are linearly dependent if there exists a set of scalars a1, a2, ..., an such that:

a1*v1 + a2*v2 + .... + an*vn = 0

With all "a"s not being zero. If such a relation cannot be expressed, the vectors are linearly independent. Anyway, coming back to the matrix [B AB]. If this matrix has dimension 2 for our system of 2 state variables, the system is fully controllable. And if you try to execute the variable "controllability", you will find the rank is 2. Which means our UPS is fully controllable. And that is good news.

So, this means that there exists a feedback matrix K, which can be designed in various ways one of which is Linear Quadratic Regulator (LQR), such that the closed loop system:

u = K (xref - x)

Will be asymptotically stable. This means, when influenced by a disturbance, the system will return to a finite region around the reference (xref). And that is what we want.

The next part is to define the linear system for which I use the command syslin. This is a command for defining everything - state space representations, transfer functions etc. After that I define a matrix Q and a scalar (actually another matrix but since we have only one input, a scalar) R. These are for the function LQR. To obtain the state feedback matrix K from LQR, you need to solve the algebraic Riccatti equation. This equations takes inputs Q which are the weights giving to the state variables and R is the penalty on the control signal. Notice how I have given a much higher weight to the capacitor voltage vf (1) than the inductor current (if) as it is the capacitor voltage that we want to regulate. The penalty on the control R is 0.01 which is a number I chose by trial and error and I would recommend that you fiddle with Q and R too.

The result is the K matrix. The rest of the file I will talk about in a later blog post as that is a low pass filter I was trying to add after the controller but didn't work.

I take this K matrix and insert it into my simulator control code as:

mod_signal = (9.9966672*(volt_ref - volt_cf1) + 3.2144996*(curr_ref - curr_if1))/300.0

One important thing to note here is the factor 300 by which I divide the control signal. The control in this case is a modulation signal fed to a pulse width control. So it must be restricted between -1 and 1. However, the control as designed doesn't know about this and will try to spit out an actual value. So, to convert this actual value into a modulation signal, I divide it by the dc bus voltage.


This the result. The light blue line is the reference and the purple line is the actual voltage. To begin with, it doesn't track - there is a steady state error. I will address this in detail in a future blog. However, for now it is to do with the reference xref = [ifref vfref]. The reference for the voltage is easy, because we want to regulate it. But the reference for the inductor current is a bit tricky and for now I have assumed it to be the same as the output load current. Hence, the approximation. But, there is something very special with state feedback. Notice how quickly, the tracking begins - almost immediate. With PI control it would take several cycles to get even close. Also, there is no conversion from stationary reference frame to synchronous reference frame. So this is a great way to produce voltages that have harmonics. Check out the next plot.




To generate harmonic voltages with the regular method, you would need several reference frame transformations. Here, everything is instantaneous.

There are a couple of problems - the steady state error is the biggest glaring problem. Besides, a few others like a bit more ripple than expected. This topic is by no means over and there will be more blog posts to come.

Stay tuned for updates. I'll be back!

Sunday, September 2, 2018

Implementing class based views and class hierarchy

So finally I managed to migrate the function based views in the Django code to class based views. This has resulted in significant decrease in code repetition and the code is now much more readable and maintainable.

To start, I needed to create a class hierarchy. The base class in SimulationData which extracts the simulation model instance, reads the circuit files and processes them. The next layer is ListControlVariables that inherits SimulationData and extracts control files and their variables.

The class SimulationData is:


The methods of the class perform functions like retrieving the simulation model instance, getting the circuit schematic model instances, checking if there are errors in reading the circuit files, processing the simulation circuit files and updating the database.

A few are obvious like getting the simulation model instance or circuit files model instances. Some not so obvious. When the circuit schematics are processed, they are checked for errors. These errors are both errors like component not found, unmatching jump labels etc. Also, connectivity errors are found - broken branches, jumps next to nodes etc. This checking is done almost every time because the simulator uses the "component_objects" dictionary of Python objects to contain information about every component found in the circuit. This is essential because different types of components have different classes - example resistors have Resistor class while voltage sources have VoltageSource class. Every time a class is found, it is instantiated and added to component_objects. So component_objects is the key to processing circuit components. By having the process_circuit_schematics() method in the SimulationData class, it is available to all other classes that inherit it.

Another non-obvious class method in update_db(). The database contains every circuit component in its records. And the details include the cell position of the circuit component and the polarity if any. These can always change as a user can move the components around in the schematic spreadsheet. The update_db() method updates the information in the schematic with the database.

The SimulationData class is the base class as the above methods are needed for every simulation. The next layer in the class hierarchy is the control class which is called ListControlVariables class. This is because there may be some simulations that don't have control. However, to figure out how a control function works, the circuit files will need to be processed and this means control needs SimulationData. ListControlVariables is as below:


This class provides method to perform repeated tasks with respect to control files. Extracting the control file model instance. Providing a list of all special variables in the control file as context variables.

With these two classes implemented the amount of times the process circuit schematic code was written to get back the dictionary of component_objects or that of components_found has decreased. Moreover, with component_objects and component_founds class attributes rather than regular variables, the function call is much less cumbersome as compared to before.

The next blog post will describe how class based views for listing circuit items will be created.

Sunday, August 19, 2018

Class Based Views in the Django app

The past few releases have seen small to significant changes in the Django web app. And every time I made these changes, the one thing that struck me is how awful the Django code is. At the time I was creating the web app for the circuit simulator, I was just getting into web development and I had little knowledge of best practices, what a REST API was and of course the look and feel of a good website. I just wanted something that could be run off a server.

Now that I have been designing websites for a while and also had positions of full stack web developer, I realize I need to change the code. To begin with in the Django app, I used function based views which results in a lot of redundant and repeated code. I need to convert this to class based views to be able to reuse code and implement DRY.

The next is that for some reason, I wanted to have the minimum number of links in the app. No reason for doing so. But because I had just one link /new-simulation/ for the entire simulation editing and running to see the results, I have incredibly complex and difficult to maintain code in the function view that serves this URL. As an example, for all purposes, I have used submit buttons that have different values or submit buttons with hidden fields to pass information back to the view function. In reality, the only time you need to use a submit button is while submitting a form. To access any other information, only a GET request is needed. To pass information between URL and view function, there are much more convenient methods such as URL parameters. This will result in a several links for each operation performed. But so what? URLs can be plentiful. the views that serve them need to be most efficient.

Next, the look and feel of the app. When I started, I didn't know any frontend development. Now I regularly code in JavaScript and use CSS, Bootstrap and sometimes even combine all these in a frontend framework like Angular. So, I need to bring in Bootstrap and custom CSS pages into this web app for the circuit simulator to make it much more visually appealing.

The migration to Django class based views has started. It is progressing page by page and might be done in another 2 weeks. The front end changes will take another week at most. In a month, a much better web app should be available which I hope will have more engineers using it.

As before, to get regular updates on the project, follow my Facebook page:
https://www.facebook.com/pythonpowerelectronics

And to learn how to use the simulator or access other tutorials, check out my YouTube channel:
https://www.youtube.com/channel/UCxVbKNK18A_a9Ohd0Kb7kNA

Thursday, July 26, 2018

Importing and exporting parameters in the Django web app

The main reason for creating the Django based web app was to have a single interface for most tasks related to simulating circuits. For example, in the command line interface, you would need to do the following:

1. Create circuit schematics in a spreadsheet.
2. Launch the circuit simulator in command line with "python circuit_solver.py"
3. Enter the simulation parameters in circuit_inputs.csv.
4. Enter the component parameters in the parameter spreadsheets.
5. Enter the control variables in the control descriptors.
6. When the simulation is running, run separate plot commands in either matplotlib or gnuplot to view results.

There are a few steps that are fundamental and unlikely to change. Those are circuits will be designed in circuit schematics with a spreadsheet software and saved as .csv files and control functions will have to be written in text files as .py files. But the command line needs a lot of back and forth between spreadsheets and also plotting the output needs a whole new set of commands and the need to learn gnuplot or matplotlib.

The Django web app simplified that. Only circuit schematics and control functions are still independent. All other parameters and commands can be given in the web interface by clicking on buttons and filling forms. Much more convenient without needing to go back and forth. However, the problem came while transferring simulations. Because now the simulation is stored in a SQLITE database and copy pasting the database will transfer the entire simulation collection rather than just what you want. What is needed is a way to extract the simulation as a set of simple files that can be zipped and copied or emailed.

What I have now added to the Django app has been an export button and an import button. After creating your simulation and checking that it runs the way you expect it to, you can click on export buttons on every circuit component parameters edit page and export all the parameters of that circuit schematic as a .csv file. Additionally, when you want to recreate a simulation in another computer or transfer it to someone else, you need to send the .csv files and use the import button to upload the parameter spreadsheet and copy the parameters to the database. The same process can be performed for control functions as well.

These features are available in version 2.0.7 for Python 2 and in version 4.0.3 for Python 3.
http://pythonpowerelectronics.com/contents/softwaredownloads.html

I am already finding this tool useful in maintaining simulations in all my computers and creating and arranging libraries of simulations. Try it out and let me know if you have any questions or comments. To know more about installing the software, check out my You Tube video:
https://www.youtube.com/watch?v=JRKUenYBIA4&t=9s
https://www.youtube.com/watch?v=jM28A2MD8u4&t=41s