Pages: [1]   Go Down
Author Topic: Hysteresis Current Control  (Read 1665 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Full Member
***
Karma: 1
Posts: 131
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi this is my first post here I have searched but could not find anything similar I really have hit a brick wall and I dont know what to do.

I am an electrical engineering student and I am trying to build an hysteresis current controller to drive an AC induction motor the motor has two windings and the currents need to be 90 degrees out of phase with each other, I have designed and built the rectifier stage (easy bit). I will use three Arduinos to drive a three phase inverter (6 IGBT's).

I will drive the middle leg of the inverter at 16kHz to give a reference(VDC/2) I have already done the program to do this I had to use direct port addressing the 16kHz square wave is perfect and I will use a gate drive chip to interface between the controller and IGBT.


Now the other two legs will be controlled using a hall effect current transducer,I have the sensor and I have written a program to measure the current the sensor gives out 2.5 volts with no current and increases by 200mv at my full load of 0.34A

So my analogue read at 0A = 515
                             at 0.35A = 558

I plan on taking a measurement and comparing with a look up value the difference between the two is the actual error and a positive error means not enough current was measured hence the top IGBT needs to turn on a negative error means too much current and the bottom IGBT needs to be turned on

Now I think I can write the program to measure and compare I will use one arduino to measure both currents and control two legs what I really need some advice with is how to cycle through a lookup table with accurate timing

my look up table (for1/4 of a cycle)will look something like

Main Ref[]= {515, 516,517,518........................558] (44 elements up to pi/2)

44 elements in the array up to pi/2 rads

the Aux winding reference has a slightly less magnitude so its look up table (1/4 of a cycle)

Aux Ref[515,516,517.....................545]

So I want an arduino to output these values in a timed fashion for a 50Hz output reference the main lookup table will need to change element every 116.28 us and for the aux it will have less values so its step time need to be 166.67 us

Is this possible with an Arduino? to use two separate timers to increment the values in the array so that two outputs are achieved ready to be received by another arduino?

I hope my problem is clear I look forward to any advice

Regards

Edit

To make it easy lets say we had a small look up table up to 10 max 0 min

Table[]= { 5, 6, 7, 8, 9, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0}  say thats a sin

A cos is 90 degrees out so with 70% of magnitude

Table2[]= { 7, 6, 5, 4, 3, 2, 1, 0, 1, 2, 3, 4, 5, 6, 7}

how could I output those values in time so they cycle through in the same period
« Last Edit: December 06, 2011, 01:41:14 am by Resinator » Logged

0
Offline Offline
Shannon Member
****
Karma: 206
Posts: 12177
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

If your table is a power-of-two long, lets say its 16, then something like:

Code:
  int angle = ?? ;  // setup the angle here, 0 means 0, 4 means pi/2, 8 means pi, 12 means 3pi/2
  int sine_val = sinetable [angle & 15] ;   // 15 is a mask to collapse down to the 0..15 range, angle can be anything.
  int cosine_val = sinetable [(angle+4) & 15] ;  // 4 means pi/2..
  ...
Logged

[ I won't respond to messages, use the forum please ]

Offline Offline
Full Member
***
Karma: 1
Posts: 131
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for your reply, I am pretty new to programming so the above code doesn't make much sense to me

It was rather early this morning so I think I will re-explain my problem

I have a single phase motor capacitor run with two windings (main and aux) the aux winding current needs to lead the main winding current by 90degrees for max torque

I want to decrease the speed of the motor using a three phase inverter variable frequency drive and I had looked into space vector modulation but I think its too much to ask of an Arduino and my programming skills  smiley
The two phase motor can be connected as an unbalanced three phase loadwith both windings sharing the middle leg as a common (See Lipo and Benedict Improved PWM modulation for a permanent-split capacitor motor)

I have decided on an hysteresis current controller which uses hall effect current sensors to measure the current and compares this to a reference value the difference being the error and the error is used to decide when to switch IGBT's the V/Hz princuple needs to be implemented to stop saturation of the motor hence the peak current at 25Hz is half the peak current at 50 Hz

The middle leg is switched at 16 kHz to give a reference of Vdc/2

I have a lookup table with 44 elements up to 90 degrees (1/4cycle) I can count up then down and go negative with these 44 elements to give an entire cycle

So I have to measure a voltage from a pot 2.5-5V which will correspond to 25-50Hz

Vin(mV)/100 = f
T=100/Vin(mV)

The step time between values in the lookup table incrementing Ts

Ts = T/4(n-1)

n = number of codes in 1/4 cycle

for a 50 Hz output Vin (pot) 5000mV

T = 0.02

Ts= T/4(43)

Ts= 116.279us

So if I had a table with 44 codes until peak then the table will need to increment every 116.3us to have a 50Hz output

So after some thought I am thinking I can use one arduino for the main winding and one for the aux winding which both do the same thing only the aux is phase shifted and scaled so I will concentrate on the main winding program

As said I have a look up table with step size calculated

Ts=100/Vin(4(n-1))

I can use a timer to go to an interupt to increment the value and I am now thinking in the same interupt I could do the analogue read of the hall sensor then subtract this from the reference value and use the error to decide which IGBT to switch

Now this is where I need some advice if I can read the analogue value quickly (117 uS is far too long) and switch quickly enough within the interupt surely the time taken for these steps will be pretty much constant and this time could be subtracted from the timer count so that the timer count and the interupt execution time both add up to the calculated step size which would mean the table cycles at the correct rate and my motor drive will have a chance to show me the weird and wonderful problems inherent

Job done

I look forward to any advice
Logged

Offline Offline
Full Member
***
Karma: 1
Posts: 131
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am really struggling with this.

I have written some code comprising a lookup table, I want to use a timer to increment the lookup table but I need the timer to count continuously without stopping

So that after the time count the table will increment and some actions will occur such as read an input and switch an output

My question is will the timer still count whilst the controller executes a subroutine? or will I need to subtract the subroutine execution time from the next timer count so that the table will increment in exact steps each and every time

I think (and have been told) timers just count regardless of where the processor may be I would like some confirmation of this if anyone can advise I would really appreciate it


I will upload the code I have done later

Thanks
Logged

NZ
Offline Offline
Jr. Member
**
Karma: 1
Posts: 91
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Freescale, Texas and MicroChip, among others, have a significant amount of application notes on their web sites relating to vector drives and their applications.
Arduino should be fast enough for simple speed control and proof of design.

Once you go further you will need DSP/32bit to do real time calculations.
BTW you can get 32bit arduino (PIC32) boards :-)

K
Logged

Offline Offline
Full Member
***
Karma: 1
Posts: 131
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am trying to build a variable frequency drive

I will measure a current and compare to a reference value

my hall sensor gives 2.5V out for 0 Amps and has a range of 400mV acroos full load

So I write my look up table

Code:

 int MainRef[] = {
 

  433, 435, 437, 439, 441, 443, 445, 447, 449, 451, 453, 455, 457,
  459, 461, 463, 465, 467, 469, 471, 473, 475, 477, 479, 481, 483,
  485, 487, 489, 491, 493, 495, 497, 499, 501, 503, 505, 507, 509,
  511, 
 
  513, 515, 517, 519, 521, 523, 525, 527, 529, 531, 533, 535, 537,
  539, 541, 543, 545, 547, 549, 551, 553, 555, 557, 559, 561, 563,
  565, 567, 569, 571, 573, 575, 577, 579, 581, 583, 585, 587, 589,
  591, 593

 
}


Now I need to cycle through the table at dead set intervals which needs to be accurate in order to synthesise the sin wave (I know its a staircase!!!)

So I will use a timed interrupt and to calculate the time between table increments I will measure an input voltage between 2.5 and 5 Volts with that relating to 25 Hz-50Hz


Heres the snippet of code to calculate the step time, as the frequency increases then the amplitude of the sin needs to decrease also so less points in the table will be used i.e all 80 values for 50Hz but only 40 Values for 25 Hz this is what NUM is the number of values in the table

Code:

float SETUP_VIN =analogRead(A0);
  TEST_VIN = SETUP_VIN;

  float TEST_HERTZ = ((SETUP_VIN)/1023.0)*50.0;
  float FLOAT_NUM = TEST_HERTZ*1.6;
  NUM=ceil(FLOAT_NUM);
  HERTZ =ceil(TEST_HERTZ);
 
  STEP_TIME = (1000000)/(HERTZ*2*NUM);



So I have the step time calculated

I now add the step time to the timer so that I interrupt every step time to increment the table in a timed manner I start the table at index 40 (dead in the middle) and count up by NUM/2 and down the same

Code:

index = 40;
increment=1;
Timer1.initialize();
  Timer1.disablePwm(9);
  Timer1.disablePwm(10);
  Timer1.attachInterrupt(flash);
  Timer1.setPeriod(STEP_TIME);


Heres the interrupt program

Code:

void flash ()
 

    if (index<=40 + (NUM/2)){
    (increment=1);
  }
     
  else{
    if (index>=(40 - (NUM/2))){
    increment=-1;}
             
 }
   index = index+increment;
   
   Iin=analogRead(A1);
   ERR = MainRef[index]-Iin;
   if (ERR>= 2){
   digitalWrite(GATE, HIGH);}

   else{
     if (ERR <= -2){
       
     digitalWrite(GATE, LOW);}
   }     
   

}



Every time the period STEP_TIME passes the program jumps to flash where it increments or decrements the table and cycles through it measures the current and makes a decision on which transistor gate to turn on


Now this program so far works, I see with my scope that the interrupt does indeed work and the table does increment as I want it to


But.........................


I want to check the input voltage to see if any speed change has been commanded and this is where I am really stuck


What I want is to recheck the input voltage and see if its changed since it as setup, if theres a change then I need to stop the interrupt and recalculate the step time and then reload the timer with the new value


This is what I have done


Code:

 void loop(){
    Vin=analogRead(A0);
    int x = abs(TEST_VIN - Vin);

       
if (x>7){   
   
 
   
       
        Vin=analogRead(A0);
        x = (TEST_VIN - Vin);
       
     if(x>10, x<-10){
       
       digitalWrite(13, HIGH);
      noInterrupts();
     
  volatile int SETUP_VIN2 =analogRead(A0);
 
  TEST_VIN = SETUP_VIN2;
  Vin=analogRead(A0);
  float TEST_HERTZ2 = ((SETUP_VIN2)/1023.0)*50.0;
  float FLOAT_NUM2 = TEST_HERTZ2*1.6;
  NUM2=ceil(FLOAT_NUM2);
  HERTZ2 =ceil(TEST_HERTZ2);
 
  STEP_TIME2 = (1000000)/(HERTZ2*2*NUM2);
    Serial.print("NEWSTEP_TIME  ");
    Serial.println(STEP_TIME2);
    Serial.print("TEST_VIN  ");
    Serial.println(TEST_VIN);
    index = 43;
     increment=1;
     delay(5000);
     Timer1.setPeriod(STEP_TIME2);
     interrupts();
     digitalWrite(13, LOW);

       
 
 
       
       
}
}   
   
      }


Vin is re-read

TEST_VIN-Vin is calculated and   x = abs(TEST_VIN - Vin) is used to see how much the value has changed

Because of some dodgy readings I have done a double if to try to (unsuccesfully) stop strange readings


if the voltage has changed by more than 10 codes I want to re setup the step time but I want to stop the interrupt why it does this hence me trying to delay it and writing pin 13 high so I can see it on my scope

But it just does not work right I think it may well have something to do with me reusing values all over the place I just dont know what to do to move this forward I have been on 3 days trying

Here is my entire program

Code:

#include <TimerOne.h>
 
  volatile int TEST_VIN;
  volatile int TEST_VIN2;
  float TEST_HERTZ;
  float FLOAT_NUM;
  float TEST_HERTZ2;
  float FLOAT_NUM2;
  volatile int NUM;
  volatile int HERTZ;
  volatile int STEP_TIME;
  volatile int NUM2;
  volatile int HERTZ2;
  volatile int STEP_TIME2;
  volatile int Vin;
  volatile int x;


 int MainRef[] = {
 

  433, 435, 437, 439, 441, 443, 445, 447, 449, 451, 453, 455, 457,
  459, 461, 463, 465, 467, 469, 471, 473, 475, 477, 479, 481, 483,
  485, 487, 489, 491, 493, 495, 497, 499, 501, 503, 505, 507, 509,
  511, 
 
  513, 515, 517, 519, 521, 523, 525, 527, 529, 531, 533, 535, 537,
  539, 541, 543, 545, 547, 549, 551, 553, 555, 557, 559, 561, 563,
  565, 567, 569, 571, 573, 575, 577, 579, 581, 583, 585, 587, 589,
  591, 593

 
}; 
  volatile int index;
  volatile int increment ;
  long unsigned int REF = MainRef[index];
  int Iin;
  int ERR;
  int GATE = 12;
  int SPEED_CHANGE;
 
 
  void setup()
{
 
  Serial.begin(9600);
 
   pinMode(13, OUTPUT);
   pinMode(GATE, OUTPUT);
   pinMode(8, OUTPUT);
   pinMode(7, INPUT);
 
  bitClear(ADCSRA,ADPS0) ;
  bitClear(ADCSRA,ADPS1) ;
  bitSet(ADCSRA,ADPS2) ;
 
  index = 40;

  float SETUP_VIN =analogRead(A0);
  TEST_VIN = SETUP_VIN;

  float TEST_HERTZ = ((SETUP_VIN)/1023.0)*50.0;
  float FLOAT_NUM = TEST_HERTZ*1.6;
  NUM=ceil(FLOAT_NUM);
  HERTZ =ceil(TEST_HERTZ);
 
  STEP_TIME = (1000000)/(HERTZ*2*NUM);
  Serial.println(STEP_TIME);
  Serial.print("HERTZ  ");
  Serial.println(HERTZ);
  Serial.print("NUM  ");
  Serial.println(NUM);
  Timer1.initialize();
  Timer1.disablePwm(9);
  Timer1.disablePwm(10);
  Timer1.attachInterrupt(flash);
  Timer1.setPeriod(STEP_TIME);
 
   
   
 
  increment=1;
 

}




 void flash ()
 
{    digitalWrite(8, HIGH);
    if (index<=40 + (NUM/2)){
    (increment=1);
  }
     
  else{
    if (index>=(40 - (NUM/2))){
    increment=-1;}
             
 }
   index = index+increment;
   
   Iin=analogRead(A1);
   ERR = MainRef[index]-Iin;
   if (ERR>= 2){
   digitalWrite(GATE, HIGH);}

   else{
     if (ERR <= -2){
       
     digitalWrite(GATE, LOW);}
   }     
   
digitalWrite(8, LOW);
}


 void loop(){
    Vin=analogRead(A0);
    int x = abs(TEST_VIN - Vin);

       
if (x>7){   
   
 
   
       
        Vin=analogRead(A0);
        x = (TEST_VIN - Vin);
       
     if(x>10, x<-10){
       
       digitalWrite(13, HIGH);
      noInterrupts();
     
  volatile int SETUP_VIN2 =analogRead(A0);
 
  TEST_VIN = SETUP_VIN2;
  Vin=analogRead(A0);
  float TEST_HERTZ2 = ((SETUP_VIN2)/1023.0)*50.0;
  float FLOAT_NUM2 = TEST_HERTZ2*1.6;
  NUM2=ceil(FLOAT_NUM2);
  HERTZ2 =ceil(TEST_HERTZ2);
 
  STEP_TIME2 = (1000000)/(HERTZ2*2*NUM2);
    Serial.print("NEWSTEP_TIME  ");
    Serial.println(STEP_TIME2);
    Serial.print("TEST_VIN  ");
    Serial.println(TEST_VIN);
    index = 43;
     increment=1;
     delay(5000);
     Timer1.setPeriod(STEP_TIME2);
     interrupts();
     digitalWrite(13, LOW);

       
 
 
       
       
}
}   
   
      }

       
The digital writes and serial stuff can all be dropped later its only for me to try and see whats going wrong


Any help much appreciated, can I use the nointerrupt() to stop the timer command or should I detach interrupt? it doesnt seem to work either way so how would an expert here go about resetting up something I did earlier its really confusing how the program doesnt see things from the setup within the loop

Logged

Offline Offline
Full Member
***
Karma: 1
Posts: 131
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Updated here, I loved every minute of this project so much more to go at

http://arduino.cc/forum/index.php/topic,84086.0.html
Logged

Pages: [1]   Go Up
Jump to: