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
|