.. role:: math(raw) :format: html latex .. .. include:: Overview ======== Power Electronic Converter Blocks (pecblocks) use the output of detailed electromagnetic transient (EMT) simulations to produce generalized block diagram models of power electronic systems. The process uses deep learning with customized block architectures. The outputs are reduced-order models that meet specified accuracy requirements, while providing important advantages over the original EMT models: * Converter Block models have fewer nodes and can take longer time steps, resulting in shorter simulation times * Converter Block models are continuously differentiable, making them compatible with control design methods Models will run in both time domain and frequency domain. The scope includes not only the power electronic converter, but also the photovoltaic (PV) array, maximum power point tracking (MPPT), phase-lock loop (PLL) control, output filter circuits, battery storage if present, etc. The applications include but may not be limited to solar power inverters, energy storage converters, motor drives, and other power electronics equipment. Background ---------- For technical background on *pecblocks*, see `IEEE eGRID 2024 preprint (Table I corrections in red) <_static/paper.pdf>`_ |copy| 2024 IEEE. For a control systems application, see `SysDO 2024 preprint `_ For technical background on *dynoNet*, see `Forgione, Piga Paper `_ For technical background on grid-forming inverters, see `Rathnayake, et. al. `_ Installation ------------ To install the Python package:: pip install pecblocks Quick Start ----------- The package includes two examples. To download and run them: - Download the **Source Distribution** from `PyPi `_ - Unzip the *examples* directory from that archive to your local computer. There should be two subdirectories therein: - *examples/training* contains the files to train an example HWPV model - *examples/sdomain* contains the files to run a time-domain simulation of a trained HWPV model. Training a Model ^^^^^^^^^^^^^^^^ From the *examples/training* directory:: download train ucf3 The first command will download a 90-MB sample data file. The second command trains a model, which will take several minutes. Introductory information appears, then a progress log:: Epoch 1420 of 2000 | TrLoss 0.002372 | VldLoss 0.002475 | SensLoss 0.000000 | RMSE 0.0097 | Sigma 0.0000 The training loss (*TrLoss*) and validation loss (*VldLoss*) should decrease over time, and approach the same order of magnitude. The *RMSE* represents a root mean square error over all output channels. The goal is for *RMSE < 0.05* Even when the logged values are below *0.05*, some output channels may exceed *0.05*, so the log is just a general indicator of the fitting error. *SensLoss* and *Sigma* are zero in this example because no attempt is made to optimize the *dq-axis* sensitivities between AC voltages and currents. When training completes, the *examples/training/ucf3/summary.txt* file should look like this:: Dataset Summary: (Mean=Offset, Range=Scale) Column Min Max Mean Range G -0.000 999.995 811.581 999.995 Ud 0.800 1.200 1.011 0.400 Uq -0.499 0.501 -0.006 1.000 Vd 0.000 337.082 219.318 337.082 Vq -150.297 139.415 -6.328 289.712 GVrms -0.000 414899.656 253630.828 414899.656 Ctrl 0.000 1.000 0.748 1.000 Vdc 0.000 628.176 461.755 628.176 Idc 0.000 4.834 1.992 4.834 Id 0.000 5.783 2.681 5.783 Iq -2.635 2.342 -0.080 4.977 COL_Y ['Vdc', 'Idc', 'Id', 'Iq'] Train time: 1539.16, Recent loss: 0.002186, RMS Errors: 0.0030 0.0116 0.0111 0.0047 All four output channels have *RMSE < 0.05*. The loss plot in *examples/training/ucf3/ucf3_train_loss.pdf* should look like this: .. image:: assets/ucf3loss.png Then export the trained model for s-domain simulations:: export ucf3 Some important results of this export appear in *examples/training/ucf3/metrics.txt*. In the top section:: Read Model from: ./ucf3/ Export Model to: ./ucf3/ucf3_fhf.json idx_in [0, 1, 2, 3, 4, 5, 6] idx_out [7, 8, 9, 10] make_mimo_block iir H1s[0][0] Real Poles: [-114.2569614 -56.88678796] Freqs [Hz]: [] H1s[0][1] Real Poles: [-132.60159228 -58.71635642] Freqs [Hz]: [] H1s[0][2] Real Poles: [-98.54142517 -98.54142517] Freqs [Hz]: [9.63376790827413] H1s[0][3] Real Poles: [-95.95237076 -95.95237076] Freqs [Hz]: [4.705452200660855] H1s[1][0] Real Poles: [-135.80799026 -81.8345316 ] Freqs [Hz]: [] H1s[1][1] Real Poles: [-99.05355517 -99.05355517] Freqs [Hz]: [4.234559773533419] H1s[1][2] Real Poles: [-93.8685894 -93.8685894] Freqs [Hz]: [2.7041085997372196] H1s[1][3] Real Poles: [-98.32965601 -98.32965601] Freqs [Hz]: [8.50833798367145] H1s[2][0] Real Poles: [-118.25321707 -74.03952537] Freqs [Hz]: [] H1s[2][1] Real Poles: [-143.31944483 -26.50642794] Freqs [Hz]: [] H1s[2][2] Real Poles: [-92.25928336 -92.25928336] Freqs [Hz]: [7.307075566267579] H1s[2][3] Real Poles: [-126.34298102 -28.01220818] Freqs [Hz]: [] H1s[3][0] Real Poles: [-127.22251461 -62.11887925] Freqs [Hz]: [] H1s[3][1] Real Poles: [-102.89434604 -102.89434604] Freqs [Hz]: [3.9716432768384853] H1s[3][2] Real Poles: [-104.9091462 -104.9091462] Freqs [Hz]: [4.3754426482151345] H1s[3][3] Real Poles: [-126.92004256 -64.34811764] Freqs [Hz]: [] All of the *H1(s)* poles have negative real parts, so they are stable. Some of these poles are complex conjugate pairs, others are real and distinct pairs. Before using *H1(s)* in simulation, check that all of its poles are stable. In the bottom section of *examples/training/ucf3/metrics.txt*:: 1498,0.0031,0.0103,0.0086,0.0139 1499,0.0031,0.0099,0.0087,0.0126 Highest RMSE Cases Vdc Max RMSE= 0.0057 at Case 1435; 0 > 0.05 Idc Max RMSE= 0.0337 at Case 34; 0 > 0.05 Id Max RMSE= 0.0344 at Case 533; 0 > 0.05 Iq Max RMSE= 0.0202 at Case 515; 0 > 0.05 Total Error Summary Vdc RMSE= 0.0030 Idc RMSE= 0.0116 Id RMSE= 0.0111 Iq RMSE= 0.0047 We can see that none of the 1500 cases have *RMSE > 0.05*. Case 533 has the highest *RMSE* value for the output *Id*. For a Norton model, *Id* is probably the most important output channel. In the middle of the *metrics.txt* file, we can find some individual case results for the *RMSE* of each output channel:: 533,0.0030,0.0318,0.0344,0.0106 We can plot the fitting result for this worst case as follows:: python pv3_test.py ucf3_config.json 533 The result looks like: .. image:: assets/Case533.png *RMSE* values in the plot caption match those in *metrics.txt*, but the initial values are not exactly zero. The initialization can be improved for simulation, but the *RMSE* values then may not exactly match the values in *metrics.txt*. For more information, check the *usage* documentation from:: python pv3_test.py Simulating a Model ^^^^^^^^^^^^^^^^^^ From the *example/sdomain* directory:: go.bat or ./go.sh This runs a continous-time simulation of a trained HWPV model for a 100 kW, 480 V inverter. The grid resistance, *Rg*, begins at 2.3 ohms. The solar irradiance, *G*, ramps up between 1 and 2 seconds, the control mode changes to GFM at 2.5 seconds, and then *Rg* changes from 2.3 to 3.0 ohms at 5 seconds. The result looks like: .. image:: assets/BackwardEuler1.png For more information: * The model in *bal3_fhf.json* was pre-trained from over 23000 EMT simulations * The Python file *hwpv_pi.py* illustrates how to test an HWPV model, by application of control inputs, and simulating the effect of external grid resistance, *Rg*. * The Python file *hwpv_evaluator.py* implements discrete-time simulation or Euler integration of the model. * Initialization of the Backward Euler method is still under development. * When *Rg* changes suddenly, as in this example, the time step size is limited to maintain numerical stability. To alleviate this limit, a variable time step for the Euler method is under development. Example Repository ------------------ See `GitHub Examples directory `_