Menu

Probable problem with GCBasic

Help
2009-02-24
2013-05-30
  • Edward LaBudde

    Edward LaBudde - 2009-02-24

    Hi all newbie here. I called my brother Robert on this math problem, encountered in PID and the filter.

    He is a scientist (Phd.) and a genius in math and computer science, which he taught at MIT in the ‘70’s.  And yes, he knows how to program PIC’s in assembler.

    He told me that the “standard solution to this issue is the make the input a “signed integer” by subtracting half the range (128), (and mentioned something about 2’s complement which the PIC supports) do the intermediate calculations and then add back the 128 when you output to the PWM.  While on the phone, I tried this out with the filter problem.  It did not work correctly.  It worked ok on the positive going part, but got “hung” up when going back down.  We trace the problem to a single line of code” output = (inputsgn-outputn)/tp + outputn 'compute output, where inputsgn is the a-d read –128.  This line would execute correctly only if tp=1 and no other value.  Dimensioning everything as word makes it go nuts! 

    He asked me to send him the .hex file and he would examine it with MPLab.  Later he e-mailed me to say he could not load MPLab on his Vista computer and was going to try an old one.  I do not know if he will ever get this solved, but it is his opinion that GCBasic is at fault. 

    I checked his assertions in an Excel spreadsheet and confirmed the equations work ok.

    Try it yourself, here is the code we tested:

    'A first order lag with PWM output
    'Tested 02-23-09 does not work correctly

    'Chip model
    #chip 16F88, 8
    #config INTRC_IO

    'Set the pin directions
    dir portA.0 in    'input test signal pin #17 (an0)
    dir portB.0 out  'set pwm output pin 6

    'dim Input as word
    'dim inputsgn as word
    'dim outputn as word
    'dim output as word
    'dim outputpwm as word
    'dim PWMDC as word

    outputn = 0    'Initial condition
    PWMDC = 0        'Initial condition
    tp = 2        'time constant = tp in seconds (ratio of tp/dt ) – only 1 works!

    FirstLag:         'reads input and computes output
    Input = readad(an0)    'get new data
    Inputsgn = input -128    'make input a signed integer
    output = (inputsgn-outputn)/tp + outputn 'compute output
    outputn = output    'set n-1 value of output
    outputpwm = output +128 'translate to 0-255

    PWMon                'Turn PWM on so we can see the internal calulations
    PWMDC = outputpwm    'scale PWM
    HPWM  1, 40, PWMDC    'output PWM
    wait 100 ms            'set sample rate = dt
    goto firstlag

     
    • kent_twt4

      kent_twt4 - 2009-02-25

      Ed, as you know GCBasic doesn't support signed integers.  Tried Santiago's signed math library with your code, but still hung up on proper data presentation.

      The two's complement for a negative number representation can easily be done by variable = !variable + 1.  Have used that for the Dallas DS18X20 temp senseors.  But not sure if that's the way to go or not.

      The most readable code is just use some conditional statements and keeping track of whether the result will be negative or positive.

      Here is my thought process:

      Make a header file for Santiago's signed math library.  To do that, make a copy of any header file and plop it back in the include folder.  Then copy and paste in his code to that file and rename it say SignedMath.h
      Be sure to put his fix in per the signed math post.  Do not use my posted fix!!!, because it messes up.

      Use the #include <SignedMath.h>

      Make sure that any variables and parameters that are used with the signed math functions are dimensioned as words.

      :make your pot adjust from -127,0,+127
      If Feedback > 127 Then Inputsgn = Feedback - 127 ;positve value
      If Feedback = 127 Then Inputsgn = 0
      If Feedback < 128 Then
      Inputsgn = 127 - Feedback
      Inputsgn = Inputsgn + 256  ;make a negative value
      End if

      Now for every little math operation you have to break it down to just two operators, oh joy!  Surely there is a more simple way, but I am lost here.

      PIDfactor = Signed_Sub(Inputsgn, outputn)
      PIDfactor = Signed_Div(PIDfactor, tp)
      output = signed_add (PIDfactor, outputn)
      outputn = output

      All said and done the positive side works like a charm, but the negative side is another story.  The PIDfactor sometimes comes back to zero (i.e. 256?) but the output value is not working for me.  It is probably something simple.

      Good luck,
      Kent

       
    • Santiago

      Santiago - 2009-02-25

      Hi... i tried the filter with signed math and it works for me.

      Deading adc 8 bits (0-255, i did not use +127 -127), tp=10 ( to see the effect)

      Here you can see the effect of the filter, red is unfiltered reading, white is filtered:

      http://docs.google.com/Doc?id=ddvgzjtz_48d89s2pf5

       
    • Santiago

      Santiago - 2009-02-25

      I forgot to say that i used exactly the code proposed by Kent ( not the +127 -127 adjust):

      PIDfactor = Signed_Sub(Inputsgn, outputn) 
      PIDfactor = Signed_Div(PIDfactor, tp)
      output = signed_add (PIDfactor, outputn)
      outputn = output

      Red channel is inputsgn, and white is output

       
    • Edward LaBudde

      Edward LaBudde - 2009-02-25

      Kent, thanks, for the reply.  I did not know that GCBasic did not support signed integers!  Had I known that I would have saved much time. 

      I am not sure that this approch is easier than what I ended up doing, has just as many lines, maybe not quite as confusing thogh.  Where do I find the signed math include file?

      Santiogo, thanks for your help and the signed math libs.  I take it you like the filter?!  It is a "first oder lad" in engineering terms.  In financial terms it is called an "exponential moving average"

      I will have to study this in more detail

      Best regards, Ed.

       
    • Edward LaBudde

      Edward LaBudde - 2009-02-25

      Kent, not supporting signed math is a significant limitation for Great Cow!  That makes control system stuff and signal processing very difficult to do! 

      Great Cow is such a wonderful (and very flexible) program it seems a shame to have this glaring flaw.  Is it on Hughes to do list? If not could you get him to put it on?

      Santigo, could you post you PID code useing your library, so I can see how to best use it?  Also so PID code needs to include clamps to prevent overflow for high gain terms, to prevent overflow (usually need on the Proportional and dervivitive terms).

      Best regards, Ed.

       
    • kent_twt4

      kent_twt4 - 2009-02-25

      Well, stumbled upon the fix to my negative input problem late last night.  Still having a hard time visualizing the negative number input.  The following fix is used to get the right output.  There is a question if I have adjusted the data correctly, just to fit the form?  The adjustment might somehow be related to the fact that the output.7 bit is not used in my example.

      :To be applied to the output value after all
      ;calculations prior to readout.  LCDinput = output
          If LCDinput_H.0 On Then
              Set LCDinput_H.0 Off
                  LCDinput = 255 - LCDinput
              If LCDinput >= 0 Then Minus = True
          End if

      All my tests thus far have been using tp = 2.

      Santiago, thanks for the visual representation of the filter, very nice!  Would be great if you could get a shot of a negative voltage with the above fix?....... :-).

      Ed, hard to say whether the missing signed maths, floating point, and trig functions are a glaring GCBasic oversight, or simply an opportunity?  If in need ASAP, there is a commercially available floating point math co-processor,  that might serve your needs.  Serious digital signal analysis would entail a 16 bit dsPIC, (haven't tried one personally).  You would probably be using C though, but the librarys are already done for you.

      Not sure where these items line up priority wise with Hugh.  Need to nail down the wait delay and RS232 routines first I would think.

      Santiago's header/library file is in the contributors section of the forum, with the associated fix in the signed math thread in this(help) forum.  You can use the posted code there, to test the routines on an lcd.

       
    • Santiago

      Santiago - 2009-02-25

      Hi Ed... i still testing all this stuff, but in the way i'm using it works for me. I added a flag to avoid overflow in add and mult fuctions... just using bit 1 of high byte as an overflow flag, then you can check the bit and limit the value to 255 if it is 1.

      But take it with care as i'm not fully-tested this and perhaps it needs more thoughts and work to bring the functions to work in an easy way.

      To don't loose indentation and keep the forun clean you can download signed_math.h from here:
      http://www.box.net/shared/0jk7mzeax0

      The way i'm testing signed math for PID is the following; there are the declared variables and some comments, the use of the resultant value can be different in different cases.
      Note that every operation is started with a comment line of the equivalent "standard math":

      '--------------------------------------------------------------------
      dim pos_target as word      'Target value
      dim pos_mot as word         'Readed value

      dim error_pot as word       'error actual
      dim error_pot_prev as word  'error prev.

      dim K_propo as word         'Prop. gain
      dim K_deriv as word         'Deriv. gain
      dim K_integ as word         'Integ. gain (1/K).. i use gain < 1

      dim T_propo as word         'Prop. term
      dim T_deriv as word         'Deriv term
      dim T_integ as wo           'Integ. term

      dim Total_integ as word     'Total integ

      dim Total_term as word      'Total term

      out_pwm = 0 'byte variable
      '--------------------------------------------------------------------

              'error_pot = pos_mot - pos_target

              error_pot = Signed_Sub(pos_mot, pos_target)

              'T_propo = error_pot * K_propo

              T_propo = Signed_Mul(error_pot, K_propo)

              if Signed_Mul_H.1 on then           'Avoid overflow, value limited to 255
                  MOVLW 255                       'T_propo = 255
                  MOVWF T_propo
              End if

              'T_deriv = (error_pot - error_pot_prev) * K_deriv

              T_deriv = Signed_Sub(error_pot, error_pot_prev)
              T_deriv = Signed_Mul(T_deriv, K_deriv)

              if Signed_Mul_H.1 on then           'Avoid overflow, value limited to 255
                  MOVLW 255                       'T_deriv = 255
                  MOVWF T_deriv
              End if

              'T_integ = error_pot / K_integ + Total_integ

              T_integ = Signed_Div(error_pot, K_integ)
              Total_integ = Signed_Add(Total_integ, T_integ)

              if Signed_Add_H.1 on then           'Avoid overflow, value limited to 255
                  MOVLW 255                       'Total_integ = 255
                  MOVWF Total_integ
              End if

              error_pot_prev = error_pot

              'Total_term = T_propo + T_deriv + T_integ

              Total_term = Signed_Add(T_propo, T_deriv)

              if Signed_Add_H.1 on then           'Avoid overflow, value limited to 255
                  MOVLW 255                       'Total_term = 255
                  MOVWF Total_term
                  goto salida_pwm
              End if

              Total_term = Signed_Add(Total_term, Total_integ)

              if Signed_Add_H.1 on then           'Avoid overflow, value limited to 255
                  MOVLW 255                       'Total_term = 255
                  MOVWF Total_term
                  goto salida_pwm
              End if

      'Here is the output
              salida_pwm:

              out_pwm = Total_term

              if Total_term_H.0 on then out_pwm = 255 - out_pwm 'invert pwm for neg. values

              HPWM 2, 10, out_pwm

              dir_motor = Total_term_H.0 'motor turn direction = sign flag

      '--------------------------------------------------------------------

      this asm lines:

                  MOVLW 255                       'Total_term = 255
                  MOVWF Total_term

      could be sustituted (i think) by this basic ones:

      Total_term = Total_term | 255

      I prefer the asm byte operation instead of the basic word opreration, but the result should be similar: low byte = 255
      What cannot be done is:

      Total_term = 255

      This way you will loose sign flag

      Regards.

       
    • Santiago

      Santiago - 2009-02-25

      I forgot to comment that the signed_math.h in the link has the fix to the bug finded by Kent and the overflow flag suff (take in account this bit if you use this library).

      Kent:
      I still Keep in the positive side of output (in the filter routine), the corrections made by the filter can be positive or negative (that's why the signed math), but the outputed value will be always positive.
      Not tried representing negative values, but when i try it i will take in account your suggestions and post it.

      In PID, the outputed value to PWM is always positive, i just toggle the motor turn by setting or clearing the opposite side of the motor... still doing tests with this... PID is complex when you try to find a proper combination of constants (gains) values, still don't understand this, and need a lot of reading and testing untill i can manage this properly, but i'm amazed with this kind of stuff...

       
    • Edward LaBudde

      Edward LaBudde - 2009-02-26

      Kent thanks.  You are right about DSP, however control stuff works well within the limitations of the current PIC families.  For most control stuff 8 bits works fine (<.5% error).  I really would like to see this fixed as it is an imprtant "opportunity."  The other stuff can wait as far as I am concerned.

      Santiago, I downloaded your file from your link and it has no indention and is almost unreable! 

      I find that it is easy to tune the PID.  First raise the P gain until you see an overshoot.  Then increase D gain to smoooth it out.  If there is a steady state error, increase the I gain, then redo the D gain to compensate for any change in overshoot.  That should do it.

      Regards, Ed.

       
    • Edward LaBudde

      Edward LaBudde - 2009-02-26

      Sainiagoi, forgot to mention - test it with a square wave.  Ed.

       
    • Santiago

      Santiago - 2009-02-26

      Ed.. i downloaded the file and for me is ok...

      In Windows perhaps you need to rename it to .txt to have a look to it... but not sure about this

       
    • Edward LaBudde

      Edward LaBudde - 2009-02-26

      Santiago, WordPad opens it fine , but Notepad has a problem. Regards, Ed.

       
    • Edward LaBudde

      Edward LaBudde - 2009-02-26

      Kent, You mentioned RS-232 problems Hugh might be working on.  Is this sominge I need to Know about as I am struggling to get mime to work?  Regards, Ed.

       
    • Santiago

      Santiago - 2009-02-26

      Hi Ed....

      Try the hardware RS-232, it works fine for me; very useful to send data to PC.

       

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.