Home
General Guide
Register File
Boot Sequence
BLDC Motor FOC
Serial Comm Driver
Flash Driver
NVRAM Driver
RVDT Driver
Renesas
Microchip
Texas Instruments
Analog Devices
Mobile Devices
.NET Tips
Miscellaneous
Contact Us
Forum

RVDT / LVDT Driver

1 Introduction


Rotary Variable Differential Transformer (RVDT), and Linear Variable Differential Transformer (LVDT), are often used in absolute angular position or linear position measurement through appropriate gear box. As the principle of both transformers is very similar, RVDT is selected here for introduction. In principle, RVDT is an electromechanical transducer that provides modulated sinusoidal signals on secondary windings that are coupled from an excited primary winding.


2 Theory of Operation


This section will cover briefly the schematics, excitation, secondary voltages, and computation algorithm.


2.1 Schematics

Figure 2-1 RVDT Schematics


Figure 2-1 is RVDT schematics. The rotating core is of ferromagnetic material. Depending on gearbox, the rotational displacement can be converted to either angular or linear position displacement. VE is the excitation voltage; VA and VB are the secondary voltages. As the two secondary coils are connected in series opposition, the net induced voltage between terminals 3 and 6 is the difference of VA and VB.

2.2 Excitation


RVDT primary winding must be excited by a sinusoidal voltage with frequency and magnitude that match the specification of the device. The excitation voltage could be provided with an analog circuitry. However, it is often accomplished by using a DSP or MCU on-chip resources such as PWM module or Timer/Counter module to generate pseudo-sine or square wave, and then filtered through a band pass filter to get clean sine wave. Figure 2-2 shows a sample of excitation waves of 3 kHz by filtering a square wave from a DSP through a band pass filter.


Figure 2-2 Excitation Voltage Sample Waves


2.3 Output Voltage Waves


The primary winding is excited by a sinusoidal electric power typically with 5 – 10 VRMS and 1 – 10 kHz. The secondary outputs are modulated sinusoidal voltages at the same frequency and amplitude depending on the transformer ratio. Figure 2-3 shows a snapshot of excitation VE, secondary voltages VA and VB wave forms from a RVDT sensor.


Figure 2-3 Primary and Secondary Wave Forms


2.4 Demodulated Output Voltage


The induced voltages on the secondary windings are in AC forms, but the magnitudes of the AC voltages are in direct proportional to the angle position of the rotor. You may use either analog low pass filter or digital low pass filter to get the DC components, VA and VB, out of the AC voltages. Figure 2-4 shows the demodulated output voltage graph.


Figure 2-4 RVDT Demodulated Output Voltage Graph

2.5 Computation Algorithm


The DC components of the induced voltages of the secondary windings, VA and VB, vary linearly to the mechanical angle of the rotor, ө.



where G is the gain or sensitivity. With the designed gearbox ratio, the ө value can be converted to actual position value. Assuming gear ratio is RG, then, we have P = RG x ө.


where G' = G x RG.


3 Driver Code


According to the theory of operation, it is pretty simple to compute position once secondary winding voltages VA and VB values are retrieved from analog to digital conversion. Suppose VA and VB are retrieved from ADC software module, which is out of this driver, to compute position is as straight forward as below.


3.1 Data Structure


Below is the data structure for RVDT measurement.

typedef struct tRvdtDataStruct
{
    float Va;                      //secondary voltage Va
    float Vb;                      //secondary voltage Vb
    float Vsum;                 //sum of Va and Vb
    float Vdiff;                   //diff of Va and Vb
    float Position;             //current position
    float PosPrev;             //previous position
} RvdtDataStruct;

 

In RvdtDataStruct, there are six variables declared, which are secondary voltage Va, secondary voltage Vb, the sum of Va and Vb, the difference of Va and Vb, the current position, and the previous position. Vsum and Vdiff could be omitted in the data structure and declared as local variables in a function, however, they are declared here for the purpose of data monitoring. The previous position variable, PosPrev, is declared for the purpose that if any fault occurs, the position value is invalid, then the previous position is used for the current position.

In good practice, there shall also be status/fault checking implementation.

//RVDT status data structure
typedef struct tRvdtStatusStruct
{
    union
    {
        struct
        {
            unsigned int rsvd :29;                    //assuming 32-bit CPU
            unsigned int HiLimitFault :1;          //position high limit fault
            unsigned int LoLimitFault :1;         //position low limit fault
            unsigned int SumFault :1;             //Vsum fault
        } Bits;
        unsigned int All;                               //status word
    } Status;                                              //status bits
    unsigned int SumFaultOnCounter;         //counter for sum fault on
    unsigned int SumFaultOffCounter;         //counter for sum fault off
    unsigned int HiLimitFaultOnCounter;     //counter for high limit fault on
    unsigned int HiLimitFaultOffCounter;     //counter for high limit fault off
    unsigned int LoLimitFaultOnCounter;    //counter for low limit fault on
    unsigned int LoLimitFaultOffCounter;    //counter for low limit fault off
} RvdtStatusStruct;

In the status data structure, three status bits, Vsum fault, position low limit fault, position high limit fault, are defined. Two fault counter registers are defined for each status bit. When the number of fault detects in an on-counter reaches certain times, the fault bit is set; on the other hand, when the number of faultless detects in an off-counter reaches certain times, the fault bit is cleared.


3.2 Sample Code

#include "PH_RvdtDrv.h"

/********************************************************************************************
member data
********************************************************************************************/

RvdtDataStruct rvdtData;
RvdtStatusStruct rvdtStatus;

/********************************************************************************************
private function prototypes
********************************************************************************************/

bool RVDT_ValidatePos(void);
bool RVDT_ValidateVsum(void);
bool RVDT_SetExcFreq();               //sets excitation frequency

/********************************************************************************************
extern function prototypes
********************************************************************************************/

extern int ADC_GetRvdtVa();          //extern ADC function that gets RVDT Va
extern int ADC_GetRvdtVb();          //extern ADC function that gets RVDT Vb

/*******************************************************************************************
* Function: RVDT_Init
*
* Desc: This function initializes RVDT data variables and sets excitation frequency
*
* Params: None
*
* Returns: bool
*
* Notes: None
*
*******************************************************************************************/

bool RVDT_Init(void)
{
    //init rvdtData
    rvdtData.Va = 0.0;
    rvdtData.Vb = 0.0;
    rvdtData.Vsum = 0.0;
    rvdtData.Vdiff = 0.0;
    rvdtData.Position = 0.0;
    rvdtData.PosPrev = RVDT_POS_MID_STROKE;

    //init rvdtStatus
    rvdtStatus.SumFaultOnCounter = 0;
    rvdtStatus.SumFaultOffCounter = 0;
    rvdtStatus.HiLimitFaultOnCounter = 0;
    rvdtStatus.HiLimitFaultOffCounter = 0;
    rvdtStatus.LoLimitFaultOnCounter = 0;
    rvdtStatus.LoLimitFaultOffCounter = 0;
    rvdtStatus.Status.All = 0;

    //set excitation
    return RVDT_SetExcFreq();
}

/*******************************************************************************************
* Function: RVDT_GetData
*
* Desc: This function computes and validates RDVT data
*
* Params: None
*
* Returns: None
*
* Notes:
*
*******************************************************************************************/

void RVDT_GetData(void)
{
    // declare variables for ADC values of Va and Vb
    int nVa, nVb;

    //get ADC values of Va and Vb
    nVa = ADC_GetRvdtVa();
    nVb = ADC_GetRvdtVb();

    //convert to voltage from ADC value
    rvdtData.Va = (float)(nVa * ADC_RVDT_COUNTS_2_VOLTS);
    rvdtData.Vb = (float)(nVb * ADC_RVDT_COUNTS_2_VOLTS);

    //calculate Vsum and Vdiff
    rvdtData.Vsum = rvdtData.Va + rvdtData.Vb;
    rvdtData.Vdiff = rvdtData.Va - rvdtData.Vb;

    if (RVDT_ValidateVsum())
    {
        rvdtData.Position = ((rvdtData.Vdiff / rvdtData.Vsum) * RVDT_POS_GAIN) + RVDT_POS_OFFSET;

        //validate position
        RVDT_ValidatePos();
    }
    else
    {
        //use previous position value if Vsum faults
        rvdtData.Position = rvdtData.PosPrev;
    }
}

/*******************************************************************************************
* Function: RVDT_ValidateVsum
*
* Desc: This function checks if Vsum exceeds its limits
*
* Params: None
*
* Returns: bool
*
* Notes: None
*
*******************************************************************************************/
bool RVDT_ValidateVsum(void)
{
    // validate voltage sum
    if (rvdtData.Vsum == 0.0)
    {
        rvdtData.Status.Bits.SumFault = 1;
    }
    else if ( (rvdtData.Vsum > RVDT_SUM_LIMIT_HI) || (rvdtData.Vsum < RVDT_SUM_LIMIT_LO) )
    {
        // increment persistance counter if out of range
        rvdtData.SumFaultOnCounter++;

       // limit persistance counter if out of range and latch fault
       if (rvdtData.SumFaultOnCounter > RVDT_FAULT_ON_COUNT_MAX)
       {
           rvdtData.SumFaultOnCounter = 0;
           rvdtData.SumFaultOffCounter = RVDT_FAULT_OFF_COUNT_MAX;
           rvdtData.Status.Bits.SumFault = 1;
       }
    }
    else
    {
        // decrement persistance counter if it has been set
        if (rvdtData.Status.Bits.SumFault == 1)
        {
            if (rvdtData.SumFaultOffCounter > 0)
            {
                rvdtData.SumFaultOffCounter--;
            }
            else
            {
                rvdtData.Status.Bits.SumFault = 0;
            }
        }
    }

    return (!rvdtData.Status.Bits.SumFault);
}


/*******************************************************************************************
* Function: RVDT_ValidatePos
*
* Desc: This function checks if position value exceeds low and high limits
*
* Params: None
*
* Returns: bool
*
* Notes: None
*
*******************************************************************************************/
bool RVDT_ValidatePos(void)
{
    // validate position high limit
    if (rvdtData.Position > RVDT_POS_LIMIT_HI)
    {
        // Increment persistance counter if out of range
        rvdtData.HiLimitFaultOnCounter++;

        // Limit persistance counter if out of range and latch fault
        if (rvdtData.HiLimitFaultOnCounter > RVDT_FAULT_ON_COUNT_MAX)
        {
            rvdtData.HiLimitFaultOnCounter = 0;
            rvdtData.HiLimitFaultOffCounter = RVDT_FAULT_OFF_COUNT_MAX;
            rvdtData.Status.Bits.HiLimitFault = 1;
        }
    }
    else
    {
        if (rvdtData.Status.Bits.HiLimitFault == 1)
        {
            if(rvdtData.HiLimitFaultOffCounter > 0)
            {
                rvdtData.HiLimitFaultOffCounter--;
            }
            else
            {
                rvdtData.Status.Bits.HiLimitFault = 0;
            }
        }
    }

    //validate low limit
    if (rvdtData.Position < RVDT_POS_LIMIT_LO)
    {
        // Increment persistance counter if out of range
        rvdtData.LoLimitFaultOnCounter++;

        // Limit persistance counter if out of range and latch fault
        if (rvdtData.LoLimitFaultOnCounter > RVDT_FAULT_ON_COUNT_MAX)
        {
            rvdtData.LoLimitFaultOnCounter = 0;
            rvdtData.LoLimitFaultOffCounter = RVDT_FAULT_OFF_COUNT_MAX;
            rvdtData.Status.Bits.LoLimitFault = 1;
        }
    }
    else
    {
        if (rvdtData.Status.Bits.LoLimitFault == 1)
        {
            if (rvdtData.LoLimitFaultOffCounter > 0)
            {
                rvdtData.LoLimitFaultOffCounter--;
            }
            else
            {
                rvdtData.Status.Bits.LoLimitFault = 0;
            }
        }
    }

    //check if any fault bit was set
    if (rvdtData.Status.All == 0)
    {
        //update PosPrev if the current position is valid
        rvdtData.PosPrev = rvdtData.Position;
    }
    else
    {
        //use the previous position value
        rvdtData.Position = rvdtData.PosPrev;
    }
}


4 Source Code


The complete source code can be downloaded here.


ES_RvdtDrv.c
ES_RvdtDrv.h