A C implementation of the Phasor Measurment Unit Estimator (PMU Estimator) based on the Iterative Interpolated DFT Synchrophasor Estimation Algorithm.
Updates (with respect to version 1.6.4):
- Now it is possible to create independent instances of the pmu estimator which have their own configuration and state. This works both in the native C library and in the Python API.
previous updates (with respect to version 1.3.0):
- Performance evaluation by means of test2.c added to the /test directory.
- Python API now available (ver:1.6.3)! check in /python
- updated the library license (BSD 3-clause)
- Now the library supprots CMake Building!
- The inlined functions are now defined as preprocessor macros.
- the pmu_estimate() has an additional input argument, mid_fracsec which is the fraction of second relative to PPS of the mid point of the window, it is used t make the estimated phase correction.
- added a flag in the pmu configuration structure to specify whether the enhanced iterative interpolated dft should be applied or not.
- added two new config files aimed at specifying specific configurations for M-Class pmu and for P-Class pmu.
- fixed a bug in the pmu_estimate() function that caused the program to raise an error when the input signal window is passed as a static array.
- added two examples that shows how to use the library with CONFIG_FROM_STRUCT and also with CONFIG_FROM_INI.
- fixed bug of wrap_angle() low result accuracy.
- fixed bug in CmakeLists.txt that caused the library to raise an error when building with NUM_CHANLS not set.
- added library installation with cmake.
- now it's easily possible to stub the arithmetic functions with user implementations.
- added a test script and a Makefile to test the library with gprof.
- optimized the FFT function to work faster when input window is power of 2, and also added the -03 flag to GCC for optimized compiling.
- the library supports logging with different levels: 0 (no logging), 1 (only errors), 2 (errors and info logs), 3 (errors, info and debug logs).
- further optimized the pmu_estimate() function by optimizing wf() hanning FT function.
To build the library, first make sure that you have the following build tools are installed:
- CMake (VERSION 3.0 or higher)
- A C compiler, such as GCC
- Make
You can build the library either using CMake or by just running the build.sh provided in the root directory of the project.
run the following command from the root directory of the project:
(Linux: sudo chmod +x build.sh)
./build.sh
This will build both the static and shared libraries. The libraries will be placed in the /build directory along with the pmu_estimator.h header and the config.ini estimator configuration file. This will also install the libraries as it executes the cmake --install . command.
run the following commands from the root directory of the project:
mkdir build
cd build
cmake ..
then to build as a static library run:
make PmuEstimatorStatic
or to build as a shared library run:
make PmuEstimatorShared
the libraries will be placed in the /build.
use the following command to install the library from the /build directory:
cmake --install .
To set number of channels on which the pmu estimator will process with frames, NUM_CHANLS directive must be defined. The default value is NUM_CHANLS = 1. To set the value, you can use the -N option when running the ./build.sh command.for example, to set the number of channels to 4:
./build.sh -N 4
or add the -DNUM_CHANLS=4 with the cmake:
cmake -DNUM_CHANLS=4 ..
NOTE: if you set the number of channels different from the dimention of the input signal array passed to the pmu_estimate() function, you experience Segmentation Error.
To compile the library with logs enabled, the LOGGING_LEVEL directive must be defined and set to a logging level. To do so, you can use the -D option foollowed by the logging level wanted, when running the ./build.sh.
This are the available logging levels:
- LOGGING_LEVEL = 0 : No logging
- LOGGING_LEVEL = 1 : Only errors
- LOGGING_LEVEL = 2 : Errors and Info logs
- LOGGING_LEVEL = 3 : Errors, Info and Debug logs (which include also each step taken by the algorithm and the various algorithm variable values)
For example, to build with logging level 3, run:
./build.sh -D 3
or if you are building directly with cmake add the -DLOGGING_LEVEL=3 option:
cmake -DLOGGING_LEVEL=3 ..
func_stub.c is a header file that defines macros to stub out several data types and functions. In the file you can use the macros to either implement your own version of a function or to replace it with a version from an external library.
For example: if you want to implement your own version of the pmue_fft_r function, you can define a new function with the same name and signature, and then use the pmue_fft_r macro to replace the original function with your new implementation:
#define pmue_fft_r(in_ptr, out_ptr, out_len, n_bins) my_fft((in_ptr), (out_ptr), (out_len), (n_bins))
int_p my_fft(float_p* in_ptr, float_p complex_p* out_ptr , uint_p out_len, uint_p n_bins) {
//Your implementation of fft here
}
Note that if you want to use a function from an external library, you will need to link the library to your code during the compilation process.
In order to configure the program, the config.ini which can be found in config/config.ini file must be edited. otherwise pass config structure to the pmu_init() function.
To specify whether the program should use the config structure passed as argument or the one specified in the config.ini file do as follows:
for the config.ini file:
char filename[] = "config/config.ini";
pmu_init(&filename, CONFIG_FROM_INI);
for the config structure:
pmu_init(&config, CONFIG_FROM_STRUCT);
To build an example found in the examples directory, you can build it by running the following command from the /examples directory of the project:
make <name of the example>
or to build all examples simply run:
make
the executable will be placed in the /examples/build directory. then run the executable:
./build/<name of the example>
In the folder test you can find a test script that can be used to test and profile library with gprof. To run the test script, first change the configuration of the pmu estimator in the test.c file and also the number of test iterations for the pmu_estimate() function by setting the PERF_ITERATIONS directive constant, then run from the /test directory:
make test
this will build the test executable, now run:
make profile
this will run the test executable and generate a profile.txt which contain the profiling results. To clean the test directory run:
make clean
In order to evaluate the computation time in other words the wall time for the excecution of the pmu_estimate() function, you can customize the file test2.c in the /test directory. In the file you can set the number of iterations for the pmu_estimate() function by setting the PERF_ITERATIONS directive constant and other parameters as well. Then run the following command from the /test directory:
make test2
this will build the test executable, now run:
make benchmark
this will run the test executable and generate a pmu_perf.csv which contain the results. To clean the test directory run:
make clean
The library also comes with a python API that can be used to call the pmu_estimate() function from python. To use the API, first make sure that you have the following build tools are installed:
- CMake (VERSION 3.0 or higher)
- A C compiler, such as GCC
- Make
- Python3 (with ctypes)
Make sure that you have already built the library using the build.sh script or using cmake and also installed it, specifically the dynamic library. (See Building the library section for more details.)
Now install the library from source by running the following command from the root directory of the project:
pip install ./python
This will install the library as a python package. Now you can import the package and use it in your python code.
After installing the python package, you can take a loot and run the example found in the /python/examples directory by running the following command from the /python/examples directory:
python ./python/examples/example_usage.py