Page 3 of 3

Re: Field oriented control of induction motors

Posted: Mon Feb 13, 2023 12:27 pm
by catphish
So, rather late last night I wrote a simpler FOC implementation. The full code is here: https://github.com/catphish/stm32-sine/ ... n-sine.cpp

First we fetch some settings. slipconst is a time constant. It's a combination of motor parameters and the PWM frequency. It doesn't really matter how it's derived, it just needs to be tuned to the specific motor, and it determines the slip. curkp controls the current gains. idtarget is the d-axis current target. We set this to a fixed value for now. throtcur is multiplied by the torque request to get the q-axis current target iqtarget.

Code: Select all

      // Fetch settings
      int dir = Param::GetInt(Param::dir);
      s32fp slipconst = Param::GetInt(Param::slipconst);
      s32fp curkp = Param::Get(Param::curkp);
      s32fp idtarget = Param::Get(Param::idtarget);
      s32fp throtcur  = Param::Get(Param::throtcur);
      s32fp iqtarget = FP_MUL(throtcur, torqueRequest) * dir;
The next part is standard, we fetch the rotor angle from the encoder, and the three phase currents from the ADC.

Code: Select all

      // Update rotor angle from encoder
      Encoder::UpdateRotorAngle(dir);

      // Process currents
      s32fp il2 = GetCurrent(AnaIn::il1, ilofs[0], Param::Get(Param::il1gain));
      s32fp il3 = GetCurrent(AnaIn::il2, ilofs[1], Param::Get(Param::il2gain));
      s32fp il1 = -il2 - il3;
      s32fp ilMax = GetIlMax(il1, il2);
      Param::SetFixed(Param::il1, il1);
      Param::SetFixed(Param::il2, il2);
      Param::SetFixed(Param::ilmax, ilMax);
Next we run a Park and Clarke transform using the last known rotor field angle to derive the Id and Iq currents.

Code: Select all

      // Calculate measured IQ and ID
      FOC::SetAngle(angle);
      FOC::ParkClarke(il1, il2);
      Param::SetFixed(Param::iq, FOC::iq);
      Param::SetFixed(Param::id, FOC::id);
This block of code estimates the slip and advances the rotor field angle accordingly We assume that slip is proportional to iqtarget divided by idtarget, disregarding the difference between target and reality, as well as the rotor time constant. slipIncr is integrated into slipAngle and added the the physical rotor angle to arrive at a rotor field angle. The accuracy of this process is largely determined by the value of slipconst.

Code: Select all

      // Increment rotor field angle
      int32_t slipIncr = 0;
      if(idtarget > 0)
      {
         slipIncr = iqtarget;
         slipIncr <<= 12;
         slipIncr /= slipconst;
         slipIncr <<= 12;
         slipIncr /= idtarget;
      }
      static uint32_t slipAngle = 0;
      slipAngle += slipIncr;
      slipAngle &= 0xFFFFFF;
      uint16_t rotorAngle = Encoder::GetRotorAngle();
      angle = -polePairRatio * rotorAngle + (slipAngle >> 8);
      Param::SetFixed(Param::fslipspnt, fslip);
The slip and electrical frequencies are converted back to Hz for display calculation and use elsewhere in the application.

Code: Select all

      // Caculate slip frequency in Hz
      fslip = (slipIncr * pwmfrq) >> 19;
      Param::SetFixed(Param::fslipspnt, fslip);

      // Calculate rotor frequency in Hz
      frq = ABS(polePairRatio * Encoder::GetRotorFrequency() + fslip);
      Param::SetFixed(Param::fstat, frq);
Here we run an extremely simple I-only PID to apply corrections to Ud and Uq according to the measured error in Id and Iq. Each voltage is limited to a value that prevents the combined total from exceeding the DC bus voltage.

Code: Select all

      // Apply corrections to IQ and ID voltages
      static int32_t ud = 0;
      int32_t dError = idtarget - FOC::id;
      ud += FP_MUL(curkp, dError)/1000;
      if(ud > 26737) ud = 26737;
      if(ud < -26737) ud = -26737;
      static int32_t uq = 0;

      int32_t qError = iqtarget - FOC::iq;
      uq += FP_MUL(curkp, qError)/1000;
      if(uq > 26737) uq = 26737;
      if(uq < -26737) uq = -26737;
      Param::SetFixed(Param::ud, ud);
      Param::SetFixed(Param::uq, uq);

And finally, as one might expect, we run the inverse Park and Clarke before outputting the voltages to the inverter.

Code: Select all

      // Inverse Park Clarke
      FOC::SetAngle(angle);
      FOC::InvParkClarke(ud, uq);

      /* Match to PWM resolution */
      timer_set_oc_value(PWM_TIMER, TIM_OC1, FOC::DutyCycles[0] >> shiftForTimer);
      timer_set_oc_value(PWM_TIMER, TIM_OC2, FOC::DutyCycles[1] >> shiftForTimer);
      timer_set_oc_value(PWM_TIMER, TIM_OC3, FOC::DutyCycles[2] >> shiftForTimer);

This code *appears* to work!
foc1.png
foc2.png
I'm sure there will still be lots to do to get this accurate, and I apologize for not using the existing FOC loop. It just did a lot of things that may not apply to my motor and and I wanted to keep it simple to begin with. Sadly with no load on the motor most tests quickly exceed the voltage of the supply.

I think it's worth appreciating that ultimately, this code is still just controlling current and slip, much like my "current control" version. The substantial difference is that by handling d-axis and q-axis current independently, it should now be able to control negative currents.

Video of this code running on my bench.


Re: Field oriented control of induction motors

Posted: Mon Feb 13, 2023 12:37 pm
by Pete9008
Looking good :)

Edit - I'll rephrase that - looking VERY good, well done!

Slightly envious of your test setup too ;)

Re: Field oriented control of induction motors

Posted: Mon Feb 13, 2023 1:15 pm
by johu
Wow!

I'm sure we can eventually unify the code, now the target is to run it smoothly, with regen, in your car :)

Re: Field oriented control of induction motors

Posted: Mon Feb 13, 2023 2:52 pm
by Pete9008
catphish wrote: Sun Feb 12, 2023 10:30 pm I'm not sure how best to explain, but I'm thinking that Lm multiplies the input value FOC::id, and hence comes along with it throughout the recursive process. Perhaps this is clearer if written like this:

Code: Select all

   IdLm = FOC::id * LM;
   rotorFlux -= rotorFlux / TR;
   rotorFlux += IdLm / TR;
All terms just become LM larger.
Had a look at this but still can't work out how Lm could cancel :? Here are my calcs in case they are of any use?

Re: Field oriented control of induction motors

Posted: Mon Feb 13, 2023 3:45 pm
by catphish
Here's another short demo of the motor running on the bench after some tweaking of settings.

Re: Field oriented control of induction motors

Posted: Mon Feb 13, 2023 4:08 pm
by catphish
Pete9008 wrote: Mon Feb 13, 2023 2:52 pm Had a look at this but still can't work out how Lm could cancel :? Here are my calcs in case they are of any use?
Thank you for going through this. On the very first line of your calculations, you have "-Psir/Tr". My argument was based on the assumption that Lm and Id are both factors of Psir. If Ld were doubled, Psir would also be doubled independent of time.

I'm no longer certain that I'm correct here, but my best argument is as follows, this isn't a mathematical proof, more a demonstration of how it would be executed:

Starting condition:
Psir = 0

First iteration:
Psir = LmId / Tr - 0 / Tr = LmId / Tr

Second iteration (we insert the previous value of Psir):
Psir = LmId / Tr - (LmId / Tr)/Tr

Re: Field oriented control of induction motors

Posted: Mon Feb 13, 2023 5:05 pm
by Pete9008
Are you referring to equation (11) here? If so that is just for the steady state, where dPsir/dt = 0. Under non-steady state conditions I think you need the other term too.

Gut feel is that either solution will actually work, I think the extra term is mainly there to include flux decay due to rotor resistive losses and I would have thought that would be a fairly minot component compared to everything else.

Edit - and it's very rare I'm ever certain about anything and definitely not this!

Re: Field oriented control of induction motors

Posted: Mon Feb 13, 2023 8:00 pm
by catphish
Pete9008 wrote: Mon Feb 13, 2023 5:05 pm Are you referring to equation (11) here? If so that is just for the steady state, where dPsir/dt = 0. Under non-steady state conditions I think you need the other term too.
Nope, referring to Phir in equation 9 - the one that's self-referential. I'm suggesting that if you replace Phir with... itself... Lm and Ld appear as factors.
NB: this really isn't very important, probably best not to spend any more time worrying about it for now.

Re: Field oriented control of induction motors

Posted: Mon Feb 13, 2023 11:15 pm
by catphish
Pete9008 wrote: Mon Feb 13, 2023 12:37 pm Slightly envious of your test setup too ;)
I really like this setup. Thanks to johu for providing the STM32 board! The Prius inverter and industrial motor were quite cheap (about £80 each). The battery and contactors were leftover from my car build.

I'd still like to find a way to test with a load. Might need to build a go-kart :)

Re: Field oriented control of induction motors

Posted: Tue Feb 14, 2023 5:07 pm
by Ev8
Need to find an old exercise bike the type with a large flywheel with a brake band around it, hook it up to that and you can simulate inertia and momentum

Re: Field oriented control of induction motors

Posted: Tue Feb 14, 2023 5:22 pm
by Pete9008
Ev8 wrote: Tue Feb 14, 2023 5:07 pm Need to find an old exercise bike the type with a large flywheel with a brake band around it, hook it up to that and you can simulate inertia and momentum
That's been suggested in another thread too :)

I've had this in my ebay watchlist for the last couple of weeks https://www.ebay.co.uk/itm/125763018895 , just can't decide whether I can be bothered!

Re: Field oriented control of induction motors

Posted: Tue Feb 14, 2023 5:28 pm
by Ev8
Yeah that would be perfect, I think you should do it just because it’s a cool contraption to build!

Re: Field oriented control of induction motors

Posted: Tue Feb 14, 2023 5:40 pm
by Peter
Maybe a car or motorbike wheel, tyre filled with water for extra load ? I can machine a hub to fit your motor if that will work ?

Re: Field oriented control of induction motors

Posted: Tue Feb 14, 2023 7:44 pm
by catphish
I've been donated another 1kW motor with a chain sprocket on it. This one might be more practical to attach a load to :)

Re: Field oriented control of induction motors

Posted: Tue Feb 14, 2023 10:33 pm
by Pete9008
catphish wrote: Tue Feb 14, 2023 7:44 pm I've been donated another 1kW motor with a chain sprocket on it. This one might be more practical to attach a load to :)
How about coupling the two motors together. One on MG1 the other on MG2 and run the pair as a dyno ;)

Re: Field oriented control of induction motors

Posted: Sat Feb 18, 2023 4:16 pm
by catphish
Pete9008 wrote: Tue Feb 14, 2023 10:33 pm How about coupling the two motors together. One on MG1 the other on MG2 and run the pair as a dyno ;)
This is seeming like it might be the best idea. Probably easiest to do with two identical sizes motors, will make mounting and coupling a lot simpler.

I am putting this FOC on hold for now as it kinda works on the bench but I'm a long way from being confident getting it anywhere near by car!

However I have some more ideas about using in phase and out of phase (reactive) current measurements for "good enough" current control. Will update my other thread soon I hope.

Re: Field oriented control of induction motors

Posted: Sat Feb 18, 2023 6:47 pm
by MattsAwesomeStuff
What's the benefit be of using FOC for induction motors versus just the plain Sine algorithm?

I'll be running an induction motor (nothing fancy like a tesla, a forklift motor). Wondering if/how this might affect me.

Re: Field oriented control of induction motors

Posted: Sat Feb 18, 2023 7:16 pm
by catphish
MattsAwesomeStuff wrote: Sat Feb 18, 2023 6:47 pm What's the benefit be of using FOC for induction motors versus just the plain Sine algorithm?

I'll be running an induction motor (nothing fancy like a tesla, a forklift motor). Wondering if/how this might affect me.
In theory, a correctly implemented FOC algorithm has three main benefits:
1) More efficiency, because the motor can be run in its optimal conditions regardless of speed and load.
2) More precise control. This means better throttle response and the ability to push the motor closer to its limits.
3) Regen can be controlled properly all the way down to a stop.

The downside is that FOC is very difficult to implement in induction motors, and also requires accurate current sensing. It's unlikely I will have a working implementation any time soon.

I am instead focusing on an approach that lies somewhere in between, driving the motor the normal sine way, but adjusting the various parameters automatically / dynamically. This achieves point (2) above, but I haven't yet got regen working.

The short answer is that this probably doesn't affect you, and you'll probably be happy for now using the sine firmware, but I hope to have a good alternative available soon for comparison.

Re: Field oriented control of induction motors

Posted: Thu Apr 20, 2023 9:28 am
by Romale
appeared?
an alternative for comparison?

I would be happy to try something new with my industrial acim motor with a modified winding. it's a pity, but with the sine firmware, I burned three inverters out of the blue at low currents ((

Re: Field oriented control of induction motors

Posted: Thu Apr 20, 2023 11:04 am
by catphish
Romale wrote: Thu Apr 20, 2023 9:28 am appeared?
an alternative for comparison?

I would be happy to try something new with my industrial acim motor with a modified winding. it's a pity, but with the sine firmware, I burned three inverters out of the blue at low currents ((
I haven't made any now progress with this. If you want a viable alternative firmware, please try my current control version.

Re: Field oriented control of induction motors

Posted: Thu Apr 20, 2023 12:07 pm
by Romale
catphish wrote: Thu Apr 20, 2023 11:04 am If you want a viable alternative firmware, please try my current control version.
I'll try it with pleasure.
and where to get it?
could you add a .bin file here?

Re: Field oriented control of induction motors

Posted: Thu Apr 20, 2023 12:57 pm
by catphish
Romale wrote: Thu Apr 20, 2023 12:07 pm I'll try it with pleasure.
and where to get it?
could you add a .bin file here?
It's on another thread called current control of induction motors. Go to the bottom of the thread and you'll find the download and information.