TLDR: LuenbergerPLL
is a C
routine designed for tracking sine waves in noisy environments using a particular Luenberger observer.
The LuenbergerPLL
routine serves as an efficient tool for tracking sine waves that are subject to various disturbances, providing clean values, amplitude, and phase. It can also be effectively utilized to extract signals in phasor form from measurements.
This problem frequently presents itself in the field of electrical engineering, particularly when working with alternating current (AC). For instance, when voltage or current measurements within an electrical circuit are required.
This repository hosts an implementation of an algorithm that is based on a specific version of the Luenberger observer. I developed this algorithm during my spare time with the goal of creating a tracker that is efficient, robust, easy to use, and simple to tune. All you need to know is the expected frequency of the sine wave and the uncertainty associated with it.
The Derivation section provides a detailed explanation of how this observer is derived. However, please be aware that if you're not familiar with Control Systems and Digital Signal Processing topics, it might be challenging to follow. Regardless, you can bypass that section and directly use the library which is designed to work right out of the box.
The library in this repository consists of two files: LPLL.h which you have to include in your source file and LPLL.c.
In the library, the following structure is defined:
struct LPLL_SS
{
double A[2][2];
double B[2];
double C[2][2];
double D[2];
};
This struct contains the discrete time filter parameters.
In addition, the library provides the following function:
struct LPLL_SS LPLL_filterDesign(double f0, double BW, double dt);
This function allows you to design a filter taking in as input the expected sine wave frequency
The designed filter is capable of tracking a sine wave based on its measurements. You can choose the bandwidth
Additionally, the library provides the following function:
void LPLL_step(const struct LPLL_SS *ss, double x[], double u, double y[])
This function allows you to filter the signal
The LPLL_step() function is designed to be called at each sampling time, which is every
double x[2] = { 0.0, 1.0 };
If you are interested in estimating the phase it's advisable to avoid the
You can see the LPLL_test as example.
We begin with the model of a generic vector rotating in the
We differentiate the state
In matrix form, defining an output
Note that the system parameters are independent of the variable
and the instantaneous phase is
Now, we can design an observer to estimate the two states. We choose a Luenberger Observer for reasons that will become clear later. We augment the evolution equation with the
We define the closed loop update matrix
To allow the observer to converge we must define a
for some
it can be shown that exists a particular basis where
Where
The analog filter model will be:
To obtain good observation performance in the discrete domain, we will discretize the fileter using the Bilinear Transform with prewarping at the
Where
In the matrix state space representation, this transform becomes:
where
The digital filter equations are
The reconstruction of the state of the rotating vector at the instant
otavePlotter.m provides an Octave script to plot the output of LPLL_test:
You can see that the observer converge to the sine wave and allow you to estimate the cleaned sin wave, the amplitude
In a steady-state circuit analysis using the Steinmetz transform, it's common to convert time domain sine wave signals in phasor form:
The LPLL filter allows you to estimate phasors. In fact you can derive
However, you don't know the initial phase
If we have two signals and one of the previous filter for each signal, we get a pair
When the identity is applied to the filter output, we obtain
Thus, we can observe that
The phasor form of the two signals will then be