If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

# UCD3138A: formula for normalized pid values

Part Number: UCD3138A
Other Parts Discussed in Thread: UCD3138,

hi, I'm following guide form guide "UCD3138 Digital Controller Control Theory" in section 5.3 GUI Model Equations in Table 19: Normalized PID to Register PID you list formulas how to convert analog PID values to UCD3138A registers. The only missing part are formulas for normalization of analog PID values. Could you share them here?

• Thomasz, the purpose of that section seems to be to determine the characteristics of the filter, which don't really depend on the analog inputs and outputs.

The analog input is described elsewhere, but the range of the DAC is from 0 to 1.6 volts, with 1024 steps.  The EADC (Error ADC) is the input to the filter It has 6 bits of resolution, so 64 steps.  32 are negative, one is zero, and 31 are positive relative to the DAC, although the polarity can be switched by a control bit.

The step size can be switched to 1, 2, 4, and 8 mV nominal, but the input to the Filter always has a resolution of 1 mv.  There is a shifter between the EADC and the filter which shifts left at lower resolutions to keep the digital inputs the same.

The output of the filter goes to the DPWM.  It can be used to set frequency, duty cycle, or both at the same time (for LLC).

Since the input is 1.6 V, and the output is pulse width and frequency at 3.3 volts, there are generally components between the power supply, the EADC, and the DPWMs which do some level shifting.  These vary from system to system.

The magnitude of these signals doesn't affect the filter characteristics, which I think is what the normalization is for?

I'm not sure if I'm answering your question.  If not, please try to explain what you're trying to figure out as an end result.

• Thanks for explanation but it doesn't answer my question. It seems for me that table 19 already converts all resolutions and ranges. Also it looks like that table 19 should be used to convert analog PID values to UCD3138 registers. When I follow calculations form the pdf I've got different values for PID using table 18 and table 19. I paste python conde bellow.

```pi = 3.1415
fc = 10E3
fp1 = fc*10
fz1 = fc/10
fz2 = fc/10
wp1 = 2*pi*fp1
wz1 = 2*pi*fz1
wz2 = 2*pi*fz2
K0  = 125
Ts  = 1

Kp = K0*(wp1*wz1+wp1*wz2-wz1*wz2)/(wp1*wz1*wz2)
Ki = K0*Ts/2
Kd = 2*K0*(wp1-wz1)*(wp1-wz2)/wp1/wz1/wz2/(Ts*wp1+2)
Ts  = 5E-6
alpha = (2-Ts*wp1)/(2+Ts*wp1)

print('Kp analog eq(31) = %E' % Kp)
print('Ki analog eq(32) = %E' % Ki)
print('Kd analog eq(33) = %E' % Kd)
print('alpha eq(34) @fs=200kHz = %E\n' % alpha)

PRD = 1250
KCOMP = PRD
TDPWM = 1/200E3
NOS = 1
#table 18
Kp1 = K0*(PRD+1)*2**20*(fp1*(fz1+fz2)-fz1*fz2)/( 125*fp1*fz1*fz2*KCOMP )
Ki1 = pi*K0*((PRD+1)**2)*2**24*TDPWM/( 125*KCOMP*NOS )
Kd1 = K0*NOS*(PRD+1)*2**20*(fp1-fz1)*(fp1-fz2)/( 125*fp1*fz1*fz2*KCOMP*(16*pi*fp1*(PRD+1)*TDPWM+NOS) )
alpha1 = 256*(NOS-16*pi*fp1*(PRD+1)*TDPWM)/(16*pi*fp1*(PRD+1)*TDPWM+NOS)
#table 19
Kp2 = (PRD+1)*2**20*Kp/125/KCOMP
Ki2 = (PRD+1)*2**20*Ki/125/KCOMP
Kd2 = (PRD+1)*2**20*Kd/125/KCOMP
alpha2 = 256*alpha

print('Kp_table_18 = %E' % Kp1)
print('Kp_table_19 = %E' % Kp2)
print('Ki_table_18 = %E' % Ki1)
print('Ki_table_19 = %E' % Ki2)
print('Kd_table_18 = %E' % Kd1)
print('Kd_table_19 = %E' % Kd2)
print('alpha_table_18 = %E' % alpha1)
print('alpha_table_19 = %E\n' % alpha2)

print('Kp_table_18/Kp_table_19 = %E' % (Kp1/Kp2))
print('Ki_table_18/Ki_table_19 = %E' % (Ki1/Ki2))
print('Kd_table_18/Kd_table_19 = %E' % (Kd1/Kd2))
print('alpha_table_18/alpha_table_19 = %E' % (alpha1/alpha2))```

PS in calculations and my simulations the PID is scaled such way that 1 at output of PID = 100% duty cycle. So P regulator with unity gain for 1mV error at input will give 0.001 duty cycle. When you translate it to ucd3138 filter: 1 LSB form front end (1mV error) will give you 0.001 duty cycle for P = 524.288 (for simple saw-tooth PWM, when KCOMP=PWM period). 1048.576 = 2^17/125 which makes some sense for equations from table 19.

PPS similar to PS, for 1kHz sampling rate the unity analog Ki gain scaling factor is 1.048576 (which Ki will make 0.001 duty cycle over 1s at sampling rate and 1 LSB (1mV) input error). Example from python uses 200 kSPS, so Ki scaling factor will be 1.048576/200.It means that Ki written to register should be 0.32768, which is of course not possible - it means that sampling rate should be smaller than pwm frequency

• Tomasz, your analysis makes sense for the P factor, since it is a straight through value.  With the Ki, it is probably also correct, because you're assuming that the error is a non-zero constant.  They you would expect Ki to increase to impossible values and be a function of time and sampling rate.  This is because it has history, so it accumulates.  If it gets a constant non-zero error, it will eventually overflow.

Of course in a real system, Ki is intended to adjust to some offset in the system, which needs to be in range.  So when the offset is matched, the error will probably switch to negative and the integrator will overshoot some and then match up to the offset.

• Hi Ian, I know that integrator will saturate over the time, this is just experimental way to get scaling factor. Could you tell me please correct description for variables from table 18, 19:

• PRD: PWM period register
• KCOMP: KCOMP value (in simple case KCOM = PRD)
• SC: ?? FILTERCTRL YN_SCALE ??
• NOS: ?? DPWMCTRL2: SAMPLE_TRIG1_OVERSAMPLE number of front end samples / pwm cycle ??
• TDPWM - ?? LSB pwm time: 1/250MHz/2^4 = 4ns/16 bits = 250 ps ??
• Tomasz, going through the filter everything is scaled so that the maximum is still one LSbit below 1.  They all have a sign bit as well.  The PRD register is 4 ns, and the value going to the PWM pulse width is 250 ps.

YN scale at 0 preserves everything at a nominal 1 maximum, but the shifting will shift it up or down at that point.

KCOMP is also scaled to 1.

Note that when the filter output is used for period, it is rounded to 4 ns because of the limitation of the period register.

The oversample is complex, you need to look at the Technical Reference Manual section for that.  I believe it explains how often the filter is triggered.  Note that if you try to trigger the filter too fast it will just ignore triggers that come in while the filter is still executing.  The maximum speed of the filter is around  2 MHz.  Of course, to add to the complexity, you can trigger with multiple DPWMs, which we do in our bridge topology EVMs.  Each side of the bridge provides at least one trigger.

• it took some digging, but I think that I've got answers:

1. table 19 seems to be fine, Output after clamping register normally would be (PRD+1)*2^(16-SC)*Kxn/125/KCOMP, but it lands directly in DPWM Filter_Duty which is compared to high resolution PRD, therefore it has to be shifted by additional 4 bits:  (PRD+1)*2^(20-SC)*Kxn/125/KCOMP
2. values used in table 18 and 19 are:
1. PRD: PWM period register (low resolution)
2. KCOMP: KCOMP value (in simple case KCOM = PRD)
3. SC: FILTERCTRL YN_SCALE
4. NOS: number of front end samples / pwm cycle - can be adjsted in multiple registers
5. TDPWM - LSB pwm time: 1/250MHz/2^4 = 4ns/16 bits = 250 ps - it is written in demo boards manuals
3. correct way to obtain PID coefficients:
1. calculate 2 pole 2 zero compensator, using UCD3138 Control Theory pdf, wp1 = wp2
2. get PID values form pdf using (31..34)
3. simulate using AC pid and 2p2z transfer functions and tune pid to fit 2p2z compensator as described in pdf, in example bellow I had to: Ki*2 and Kd*0.6 to match AC and phase plots
4. calculate ucd3138 PID register's values using table 19

Unfortunately the table 18 has a bug in calculations (and Table 17, most probably table 18 was calculated using Table 17):

1. the Kp and Ki (NOS=1, KCOMP=PRD) obtained using table 18 are 2*pi bigger than values calculated using method described above
2. Kd obtained using table 18 is different from Kp calculated using method described above, but there's no constant ratio like for Kp and Ki
3. alpha calculates using table 18 is ok

```pi = 3.1415
fc = 10E3
fp1 = fc*10
fz1 = fc/10
fz2 = fc/10
wp1 = 2*pi*fp1
wz1 = 2*pi*fz1
wz2 = 2*pi*fz2
K0  = 125
Ts  = 1

Kp = K0*(wp1*wz1+wp1*wz2-wz1*wz2)/(wp1*wz1*wz2)
Ki = K0*Ts/2
Kd = 2*K0*(wp1-wz1)*(wp1-wz2)/wp1/wz1/wz2/(Ts*wp1+2)
Ts  = 5E-6
alpha = (2-Ts*wp1)/(2+Ts*wp1)

print('Kp analog eq(31) = %f' % Kp)
print('Ki analog eq(32) = %f' % Ki)
print('Kd analog eq(33) = %f' % Kd)
print('alpha eq(34) @fs=200kHz = %f\n' % alpha)

PRD = 1250
KCOMP = PRD
TDPWM = 250E-12
NOS = 1
SC = 0
SmplRt = 200E3

#table 18
Kp1 = K0*(PRD+1)*2**(20-SC)*(fp1*(fz1+fz2)-fz1*fz2)/( 125*fp1*fz1*fz2*KCOMP )
Ki1 = pi*K0*(PRD+1)**2*2**(24-SC)*TDPWM/( 125*KCOMP*NOS )
Kd1 = K0*NOS*(PRD+1)*2**(20-SC)*(fp1-fz1)*(fp1-fz2)/( 125*fp1*fz1*fz2*KCOMP*(16*pi*fp1*(PRD+1)*TDPWM+NOS) )
alpha1 = 256*(NOS-16*pi*fp1*(PRD+1)*TDPWM)/(16*pi*fp1*(PRD+1)*TDPWM+NOS)
#table 19
Kp2 = (PRD+1)*2**(20-SC)*Kp/125/KCOMP
Ki2 = (PRD+1)*2**(20-SC)*Ki/SmplRt/125/KCOMP
Kd2 = (PRD+1)*2**(20-SC)*Kd*SmplRt/125/KCOMP
alpha2 = 256*alpha

print('Kp_table_18 = %f' % Kp1)
print('Kp_table_19 = %f' % Kp2)
print('Ki_table_18 = %f' % Ki1)
print('Ki_table_19 = %f' % Ki2)
print('Kd_table_18 = %f' % Kd1)
print('Kd_table_19 = %f' % Kd2)
print('alpha_table_18 = %f' % alpha1)
print('alpha_table_19 = %f\n' % alpha2)

print('Kp_table_18/Kp_table_19 = %f' % (Kp1/Kp2))
print('Ki_table_18/Ki_table_19 = %f' % (Ki1/Ki2))
print('Kd_table_18/Kd_table_19 = %f' % (Kd1/Kd2))
print('alpha_table_18/alpha_table_19 = %f' % (alpha1/alpha2))

#table17 check
#fz1t = NOS*((2048*(alpha1-256)*Kd1*Ki1+((alpha1+256)*Ki1+(alpha1-256)*Kp1)**2)**0.5+(alpha1+256)*Ki1-alpha1*Kp1+256*Kp1)/( 32*pi*(PRD+1)*TDPWM*(512*Kd1+(alpha1+256)*Kp1) )
#fz2t = -1*NOS*((2048*(alpha1-256)*Kd1*Ki1+((alpha1+256)*Ki1+(alpha1-256)*Kp1)**2)**0.5-(alpha1+256)*Ki1+alpha1*Kp1-256*Kp1)/( 32*pi*(PRD+1)*TDPWM*(512*Kd1+(alpha1+256)*Kp1) )
#K0t = 125*KCOMP*Ki1*NOS*2**(SC-24)/( pi*(PRD+1)**2*TDPWM)
#fp1t = -1*(alpha1-256)*NOS/( 16*pi*(alpha1+256)*(PRD+1)*TDPWM )
#print('fz1t = %f' % fz1t)
#print('fz2t = %f' % fz2t)
#print('K0t = %f' % K0t)
#print('fp1t = %f' % fp1t)```