This thread has been locked.

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.

Converting control coefficients to Q notation



Hello,

I am using an F2812 DSP to implement a digitally controlled voltage mode buck converter. I designed my controller in the s-domain and used a bilinear transformation to generate the z-function and accompanying difference equation.

I am having some issues figuring out how to implement the controller, and I don't thoroughly understand how to implement the Q notation even after reading many of TI's links and code examples (the coefficients are normally already converted to integers with no explanation of how).

To start, I have a 12 bit ADC. After truncating the 4 LSB, I can then left shift the result to create a Q15 number that will vary between 0 and 1 (actually -1 and 1, but it will never be below zero). I can then feed in a reference that is also scaled on a per-unit fashion (Q15) to get a pu error signal that varies between -1 and 1 (Q15). I then feed this error signal into a 2-pole, 3-zero controller,

H(z)= 8.246z^3-8.101z^2-8.245z-8.102

            z^3-2.474z^2+1.99z-0.5157

How do I turn these coefficients into an integer that will ensure that the output of H(z) (call it u) also varies between 0 and 1?

How do I then scale u so that a value of 1 corresponds to a full period, aka 3750 clock cycles? Or more practically, saturate u at 0.95 and have it correspond to 3560 clock cycles?

Thanks for the help!

  • Hi Nick,

    I would try it the following way:
    Convert your coefficients into an adequate Q format (for example q27 +/-16), then convert your error signal into the same q type. Calculate the compensator, you will get a q27. saturate the value to your needs, convert it into a q15 again -> there you are. Scaling must be done in addition... but as far as I know this depends on your HW too...
    Hope this helps.

    Best regards

    Andreas

  • You will be able to manage all these steps easily by utilizing IQ math functions (http://focus.ti.com/lit/sw/sprc990/sprc990.pdf) . Please download the IQmath library and the documentation to get familiar with the function calls. In short, IQ functions will let you implement fixed point math with less effort.

  • Thank you both for your responses. I understand that I need to select a proper Q format, but I don't know HOW to select a proper Q format. Say that I could select any Q format from Q15 to Q31 while maintaining excellent resolution. Which one should I select?

    For example, it appears that several code examples from TI use Q15 for the ADC and REF values. When they say Q15, however, they seem to be using Q16-15; that is, 1 sign bit, 16 integer bits, and 15 decimal bits with the 16 integer bits all set to zero. This has the advantage of per-unitizing both the REF and ADC signals; a buck converter producing 25 V from a 50V source would then have REF and ADC integer values of ~16383 for a pu value of 0.5.

    But expressing the controller coefficients in a "pu" system doesn't seem to make sense since there is no "base" value. In this case, since I will be multiplying the Q15 REF and ADC values in a 32 bit DSP, I could use any Q representation for the coefficients up to Q16 (Q15*Q16=Q31). In one case, I could choose Qx as Q0,x --> the range of the coefficient is -1 to 1. Or I could use something like Q4.12, which would give me the range I need ([-16 16-2^-12]) while maintaining 12 bits of decimal resolution. Which choice is proper, or best?

    I know the IQ library automates a lot of the conversions, but it still can't tell me which base is the proper one to use. I need guidance more on how to choose which Q format to use and how that affects the range of my control signal instead of guidance on how to create a Q number.

  • Nick,

    When I use IQ numbers, my rule of thumb it to choose always the format that gives me the best resolution without harming the ranges I need. So first I try to understand which ranges I need for my calculations, the IQ format selection is obvious then (and can be different for individual calculations). I never used "exotic" Q format like your proposed Q4.12... If you need an overview about the available Q formats have a look into IQmath library documentation section 3.2 "IQmath Data type: Range & Resolution". Q15 is used for ADC because the 12Bit DAC results are left shifted by 4 digits, which is exactly a Q15 representation.
    For your pu issue - You are right, you don't have a reference, but if you would like to have coefficients between +/-1, you could divide every coefficient through your biggest coefficient (in your case 8.246), I hope this gives you a bit of the guidance you need...

    Best Andreas

  • Thanks for the response, Andreas.

    Dividing by 8.246 in the numerator would work to scale the error terms, but I can't divide the denominator. Also, shouldn't scaling be done by the first power of 2 that is larger than the largest coefficient, i.e. 2^4?

    Let me try asking the original question in a different way. In the DCDC_BUCK_VREG example code, there is a macro in dplib280x.c called CTRL_2P_2Z that contains the assembly code for a 2 pole, 2 zero compensator. Based on the assembly instructions, it appears that all the math is done fractionally; i.e., all the refs, feedback values, errors, and compensator coefficients are assumed to lie between -1 and 1.

    This macro is called in the Buck-ISR routine. The coefficients are listed in integer notation in this subroutine, but there's no information on what their real-world value is or what their Q format is. The magnitude of the largest integer has 29 bits, so the coefficients could be written in one of 3 possible Q formats: Q31 (31 fractional bits), Q1,30 (one integer bit, 30 fractional bits), or Q2, 29(2 integer bits, 29 fractional bits).

    What is the real world value of these coefficients? Which Q format are they in, and why was it chosen this way? Why are the maximum and minimum values given in Q0,24 but the coefficients are listed in some other format?

    (Note that the IQ library uses Qx to mean Q(31-x),x; TI's code examples seem to use Qx to mean Q0,x. This is important because a Q0,15 number is fractional, but an _IQ15 number is not fractional. I don't think you can get a completely fractional number in IQmath because IQ30 is the largest format and extends from -2 to 1.99...)

    Thanks!

     

  • Hi,

    to choose the suitable IQ format you must take into account the resolution of the decimal part (i.e. the number of bits on the right of dot) and the dyinamic range of the values (i.e the largest and the smallest integer number you want to be able to use in your program).

    I usually use Q21 format: it gives you 21 bits of resolution, the smallest increment in a variable is around 0.5e-6 enough for usual applications while it allows you to use numbers in the range +/-1024 and since several years I needed to adjust IQ format only few times in very special cases that didn't fit within those limits.

    To limit the dynamic range of the values in your program you can use normalized number also known as PU values: the value used by the program is the actual value compared to the full scale value. For example think of a measured current Im it's PU value is

    Ipu = Im / Ifullscale

    The PU value is always between IQ(0.0) and IQ(1.0) doesn't matter if you are acquaring with a full scale in the range of mA or KA. Note that the data in the ADC registers are arranged in a way that you already get the PU value with no need of performing any costly IQdiv. A further advantage of PU values is that also all regulators and filters in your program will be in PU with errors being at worst in the range +/-IQ(2.0) allowing you to use IQ formats like Q29 without the need of worry too much about the numbers dynamic range. Most likely in TI's code where Q29 is used also PU units are used, so to know the real world value of numbers you need to multiply them by the full scale value.

    Alas there is no precooked right choice to use, just try to find the right balance: if you choose too few integer bits probably you will often need to rescale numbers and change IQ format to fit the numbers you need, if there are not enough bits on the right side of dot you won't have enough resolution to for the required performance of regulators and filters.

     

  • Q21 to Q24 is a good range that we tend to use most often.

  • Thanks for the responses. From all the responses, it sounds like the format of the controller coefficients can be anything with sufficient range and resolution. Then, if my software interprets the ADC conversion as pu and uses a pu reference, I'll have a pu error signal that will be transformed into a pu control signal regardless of the choice of coefficient Q format. I can then saturate that pu control value (if necessary) and multiply it by the number of clock cycles in a PWM period to get my value for the CMPR register. Sound correct?

    Again, thanks to all for the helpful responses. I'm sure it's simpler than I'm making it, but the details are a little intimidating the first time through...

  • You are correct.

    Here is a snippet of code I use to do generate the PWM values from the PU output of a space vector modulator, PwmPeriod  is Uint16 all other variables are IQ.
    Maybe it could be coded in a better C style but it works.

    // Compute the compare 1 (Q0) from the PWM 1 & 2 duty cycle ratio (IQ)
        Tmp = PwmPeriod * _IQtoIQ15(_IQsat(MfuncC1, IdxLim , - IdxLim));
        EvaRegs.CMPR1 = (int16)(Tmp >> 16) + (int16)(PwmPeriod >> 1);

    // Compute the compare 2 (Q0) from the PWM 3 & 4 duty cycle ratio (IQ)
        Tmp = PwmPeriod * _IQtoIQ15(_IQsat(MfuncC2,  IdxLim , - IdxLim));
        EvaRegs.CMPR2 = (int16)(Tmp >> 16) + (int16)(PwmPeriod >> 1);

    // Compute the compare 3 (Q0) from the PWM 5 & 6 duty cycle ratio (IQ)
        Tmp = PwmPeriod * _IQtoIQ15(_IQsat(MfuncC3,  IdxLim , - IdxLim));
        EvaRegs.CMPR3 = (int16)(Tmp >> 16) + (int16)(PwmPeriod >> 1);

    Alas applications notes and software examples are not all written with the same conventions in mind so, at the beginning, the more you read, the more different options and approaches you find: instead of getting clearer things get more confusing. I had the same difficulties at the beginning: just face one problem at time, code and debug single modules like PI regulator, filters, modulator and so on... Only when you are very sure they are working properly put things together to build your application. It could sound time consuming and probably, at the beginning, it is; though it's much easier to debug a function  ten lines of code long than to try to nail down even a trivial bug in an application that span through several files containing hundreds lines of code.