is integration possible in Mbed?

07 Feb 2013

i want to integrate signal, suppose it is sine signal. i give the sine signal through function generator to the Adc of the Mbed board. then i used the trapezoidal method to integration.it formula is given below

f(x)=(h/2)*{(y1+yn)+2*(y1+y2+y3+y4.......+yn)};; y is sample here ;h is the sampling time;;

problem is that when i try to show the integrated signal through the DAC(pin18)then it is not able to show me any signal. it shows me random noise signal rather than cos signal. i have tryed it in simulation software (matlab) then this code is perfectly run but in mbed it is not working.

#include "mbed.h"
#include "math.h"
AnalogIn I(p17);
AnalogOut Aout(p18);       
main()
{     
     int i;
     float Ia[200],a[200];
     float temp,sum[200],b[200];
     while(1)
     {
        for(i=1;i<200;i++)
        {
             Ia[i]=I;
             wait_us(100);
             temp=temp+Ia[i];
             sum[i]=2*temp;
             a[i] =sum[i]*0.000005; 
             Aout=a[i];
          } 
        }
}
07 Feb 2013

As far as I understand, the trapezoidal integration is equivalent to Euler integration except for the very first and last sample, which are counted half. In embedded realtime systems you mostly don't care about these border situations (certainly not the last because that is when you switch of the system). For Euler integration you just sum up all the input values, no need for arrays, just a single sum variable. You may want to divide the sum by some constant (proportional to sampling time) before you present it to the output. A spreadsheet is always a great tool to simulate these programs. About your program: you also do not seem to care about the first and last values; the temp variable is a stack variable and must be initialised; your for-loop starts at 1; the constant 5e-6 may be too small, consider 1.0 as input, temp will grow to 200 (199 in your case) and sum[199] will be 398, hence your output will be 0.00199 which translates to 6mV or so.

07 Feb 2013

Tejas,

Note that what you are integrating is an ADC value that is never negative ( range = 0.00 ... 1.00). Therefore, your integration (summation) into temp just keeps increasing until you run into floating point limits or the DAC input range limit.

You probably need to start your for() loop with "i = 0;" (it's a 'C' language thing, arrays start at subscript zero). More importantly, since you set Aout in every step of the loop you are not performing trapazoidal integration. Perhaps your intent would be to set "temp = 0;" just before the for() loop and only set Aout after the for() loop? With your 100us delay and 200 samples, that would create a filter with a notch (zero response) at 50 Hz (updated 50 times per second).

To perform a running trapazoidal integration with samples and outputs 10,000 times per second, you need to remove the inner for() loop, and run your input array (Ia[]) as a 'ring buffer' with the index wrapped to modulus 200. Then the trapazoidal integration (over a fixed 200 sample history) reduces to subtracting half of (the oldest sample (which you are about to replace) plus the next-to-oldest sample) from your running sum (temp), and adding half of (the new sample plus the previous sample). That works best with integer ADC values. With floating-point representations of the ADC samples you may need to figure out how to prevent the accumulation of floating-point round-off errors into your running sum.

After your code is doing what you want, you might consider stablizing the sample rate by using a 'ticker' interrupt function to update a (volatile global) sample-value and a 'sample-ready' flag. Replace your (sample and wait) lines with a (wait on the flag) followed by setting the DAC (from the previously updated sum), copying the global sample value, and re-setting the flag. That will bury any timing delays and variations (from the subsequent calculation of the next sum) within the ticker's background delay. You could also put the new running sum into another global variable and let the ticker function update the DAC from that global instead.

11 Feb 2013

Fred Scipione wrote:

Tejas,

Note that what you are integrating is an ADC value that is never negative ( range = 0.00 ... 1.00). Therefore, your integration (summation) into temp just keeps increasing until you run into floating point limits or the DAC input range limit.

You probably need to start your for() loop with "i = 0;" (it's a 'C' language thing, arrays start at subscript zero). More importantly, since you set Aout in every step of the loop you are not performing trapazoidal integration. Perhaps your intent would be to set "temp = 0;" just before the for() loop and only set Aout after the for() loop? With your 100us delay and 200 samples, that would create a filter with a notch (zero response) at 50 Hz (updated 50 times per second).

To perform a running trapazoidal integration with samples and outputs 10,000 times per second, you need to remove the inner for() loop, and run your input array (Ia[]) as a 'ring buffer' with the index wrapped to modulus 200. Then the trapazoidal integration (over a fixed 200 sample history) reduces to subtracting half of (the oldest sample (which you are about to replace) plus the next-to-oldest sample) from your running sum (temp), and adding half of (the new sample plus the previous sample). That works best with integer ADC values. With floating-point representations of the ADC samples you may need to figure out how to prevent the accumulation of floating-point round-off errors into your running sum.

After your code is doing what you want, you might consider stablizing the sample rate by using a 'ticker' interrupt function to update a (volatile global) sample-value and a 'sample-ready' flag. Replace your (sample and wait) lines with a (wait on the flag) followed by setting the DAC (from the previously updated sum), copying the global sample value, and re-setting the flag. That will bury any timing delays and variations (from the subsequent calculation of the next sum) within the ticker's background delay. You could also put the new running sum into another global variable and let the ticker function update the DAC from that global instead.

thank you fred for your valueable replied

first thing is that it is my mistake to start array from 1 in stead of 0. i accept it.

second if i use the wait_us(100) then adc take the sample every 100 us then it would be taken 200 sample in one cycle,if signal of 50hz that way i stabilized the sampling rate.

third thing is that if i put the aout out of for loop then how can i show the result because it is an array variable then i need the for loop.

forth point if we want to show instantaneously (running) value of integration what would we do?

if we want show the integration of the one cycle at the end of integration then what would we do?beause ending of one cycle , we have 200 value of the integration because we run loop for 200 times the how to show this value on time axes?

i really don't understand the how to use ring buffer in my program? here i show the result of the same code which i run in matab yes, i have polt this graph out of the scope of for loop it mean after completion of the integration of one cycle. i really do not understand how can i do this thing in lpc 1768. /media/uploads/tejaspanchal/_scaled_integration.png /media/uploads/tejaspanchal/integration.png

11 Feb 2013

one another thing i point out today is that "wait_us" command is not stop the process for that particular time but ... what it exactly do it is not understand..because as i told befor that i take 200 sample in one cycle then i shift it to 50sample Right then upto first 50 sample it show me garbage value then another 150samole it has to show me correct value and then cyle will comple in that 150 sample but garbage value is no return after one complete cycle but it will return in between the cycle it mean this it is take more then 200 sample in one cycle.

11 Feb 2013

I don't think we really understand each other. You are sampling a real-time signal, in order to integrate that you don't need an array. Can you explain why you are using an array, you're not really using any of its values? So in a single endless loop you can integrate the input signal from the start of your program until the end of your program. You chose 100us as your sampling interval, that is fine, the shorter this time, the higher the accuracy of the integration. Of course this also depends on your input signal. In your simulation you use a pure sine wave. What is your real life input signal? If it is a 50Hz sine, make sure you get offset and amplitude right, e.g. 1V amplitude with 1.5V offset. Be aware that this will also integrate the offset which you will see as a ramp added to the output. This is probably not what you intended so before integrating you should remove the offset by subtracting 1.5/3.3 from the input. Nevertheless, unless you have some kind of feedback, your integrated value will go through the roof sooner or later. Of course you can first get 200 samples into an array and then do the integration over the array and outputting the sum as a single value (in fact decimating your input by 200), you can restart your integration (initialised to 0) after outputting the value. In that case you are not truly integrating but sort of averaging over 200 samples. Maybe you can explain exactly what you want to achieve.

main()
{ float sum = 0.0;
  for(;;)
  { sum += in-1.5/3.3; //remove offset and integrate
    out = sum;         //output running integral
  }
}
11 Feb 2013

Ad van der Weiden wrote:

I don't think we really understand each other. You are sampling a real-time signal, in order to integrate that you don't need an array. Can you explain why you are using an array, you're not really using any of its values? So in a single endless loop you can integrate the input signal from the start of your program until the end of your program. You chose 100us as your sampling interval, that is fine, the shorter this time, the higher the accuracy of the integration. Of course this also depends on your input signal. In your simulation you use a pure sine wave. What is your real life input signal? If it is a 50Hz sine, make sure you get offset and amplitude right, e.g. 1V amplitude with 1.5V offset. Be aware that this will also integrate the offset which you will see as a ramp added to the output. This is probably not what you intended so before integrating you should remove the offset by subtracting 1.5/3.3 from the input. Nevertheless, unless you have some kind of feedback, your integrated value will go through the roof sooner or later. Of course you can first get 200 samples into an array and then do the integration over the array and outputting the sum as a single value (in fact decimating your input by 200), you can restart your integration (initialised to 0) after outputting the value. In that case you are not truly integrating but sort of averaging over 200 samples. Maybe you can explain exactly what you want to achieve.

main()
{ float sum = 0.0;
  for(;;)
  { sum += in-1.5/3.3; //remove offset and integrate
    out = sum;         //output running integral
  }
}

thank you ad weiden i surely try your idea tomorrow. it is very simple, but i have doubt ..... i will do it practically .

12 Feb 2013

The code was to illustrate the integration process, it is not production grade code. You still need implement a well defined sampling time, e.g. as you did with your wait statement or with a timer. And subsequently you need to correct the output value with the sampling time. Also my example only works for an offset of exactly 1.5V and a reference of exactly 3.3V.

12 Feb 2013

Ad van der Weiden wrote:

The code was to illustrate the integration process, it is not production grade code. You still need implement a well defined sampling time, e.g. as you did with your wait statement or with a timer. And subsequently you need to correct the output value with the sampling time. Also my example only works for an offset of exactly 1.5V and a reference of exactly 3.3V.

weiden

i have tried as you suggest, but here we are again faceing problem of overflow of dac , this problem also explain in fred's reply.

if we want to control the dac and continuous signal on dac then we must reset the variable somehow. obviously it is possible in this method also but i think we would not get exact ans by this integration method. With use of arrays we easily control the sampling and reset the variable.

i want the cosine signal on the dac after integration of the sin signal, i don't think so that is possible with your suggested method.

12 Feb 2013

#include "mbed.h"
#include "math.h"

//Serial pc(USBTX, USBRX);
AnalogIn I(p17);
//BusOut Bout(p15,p19,p20);
AnalogOut Aout(p18);       
DigitalOut k(LED1);
main()
{     
     int i,j;
     float Ia[200],temp=0,temp1,temp_Ia;
     float sum=0,I1,a[200];
  
     for (i=0;i<200;i++)
         {
            
            Ia[i]=I-0.5; 
            wait_us(80);
            temp= temp+Ia[i];            
            sum=2*temp;            
            temp1=Ia[0]+Ia[199]+sum;
            //Aout=Ia[i];
            a[i]=temp1*0.0001; 
              }
     while(1)
        {    
             
         for(i=0;i<200;i++)
         {
            Ia[i]=I-0.5;
            temp_Ia=Ia[i];
            for(j=0;j<200;j++)
            {
                Ia[j]=Ia[j+1];
                }
            Ia[199]=temp_Ia;            
            temp= temp+temp_Ia;
            sum=2*temp;            
            temp1=Ia[0]+Ia[199]+sum;
            a[i]=temp1*0.000001;
            
            Aout=a[i];
            wait_us(80);  
                  
          }
       }
     }       

today i tried on this program, in this program i shift the sample to the previous sample and new sample is stored in the last sample. so every time i have all the 200 samples except then 1st cycle. during the first cycle i stored the all the 200 sample in the arrays and then modified last value ans discard the first value in short it is "first in first out" method.

but here also i have faceing the problem of dac range.

i also tried to show after stored all the value of the integrated signal in arrays then again run the loop but i did not get any signal rather then the dc value is increased in dac and then it will become out of range of dac.

12 Feb 2013

Hi, I'm still confused about which problem you are trying to solve. Your program is getting more complicated again. If what you want is a pure integration, you have a problem because inevitably there will be some DC offset that will integrate and let your DAC run out of bounds. How is a ringbuffer going to solve this? If you want to get rid of the DC offset you have to filter it out but what you have then is not a pure integrator. Also you can integrate over only a specific interval, like your 200 samples, is that what you want? Do you then want output every 200 samples or every sample? Something like this?

#define SIZE 200
main()
{ int i=0;
  int sum = 0;
  static int a[SIZE]; //use integers to avoid accumulation of rounding errors, static to avoid initialisation
  for(;;)
  { sum -= a[i]; //remove first value from the sum
    a[i] = 4096*(in-0.5); //get new value, 12bit resolution
    sum += a[i]; //sum over 200 samples
    i++;
    if (i>=SIZE) i = 0;
    out = sum * some_constant;
  }
}
12 Feb 2013

Ad van der Weiden wrote:

Hi, I'm still confused about which problem you are trying to solve. Your program is getting more complicated again. If what you want is a pure integration, you have a problem because inevitably there will be some DC offset that will integrate and let your DAC run out of bounds. How is a ringbuffer going to solve this? If you want to get rid of the DC offset you have to filter it out but what you have then is not a pure integrator. Also you can integrate over only a specific interval, like your 200 samples, is that what you want? Do you then want output every 200 samples or every sample? Something like this?

#define SIZE 200
main()
{ int i=0;
  int sum = 0;
  static int a[SIZE]; //use integers to avoid accumulation of rounding errors, static to avoid initialisation
  for(;;)
  { sum -= a[i]; //remove first value from the sum
    a[i] = 4096*(in-0.5); //get new value, 12bit resolution
    sum += a[i]; //sum over 200 samples
    i++;
    if (i>=SIZE) i = 0;
    out = sum * some_constant;
  }
}

o.k dear i am going to explain you what exactly i want to do. actually i don't no you know that thing or not but in control engineering proportional integral(PI) term is very famous if you have error signal then you need to integrate it or differentiate it.

for that purpose i need the accurate integration of error signal. i am using the adc for take in the sensed current then i generate current reference and compare with actual one and generate error then integrate it..

second thing why i am taking samples reason is this if i want the instantaneous control of error, it mean instantaneous compensation of error then i have to use sample domain.

if the integration code is correct then it can be able to integrate any signal, to Check it i used the sine signal to check my integration code correct or not, then i am facing difficulties to show cosine signal on dac. write now i am constantly try to solve this problem.

12 Feb 2013

If that is what you want, you don't really need to worry about the DAC running out of bounds. The entire idea behind a PI regulator is that the error will go to zero, so you can integrate for eternity without it clipping the output. That is of course assuming the final control value is within range of the DAC.

12 Feb 2013

Or you use the PID from the library

13 Feb 2013

Ad van der Weiden wrote:

Or you use the PID from the library

i really don't know about the pid library block i just tried to make pid in my program through this..

but now i try through the this library.

thank you weiden