Tuesday, March 30, 2021

Timing Advance finally works

 With enough power, anything is possible

I decided to attempt the phase timing advance system again, to compensate for the lack of flux-weakening, timing advance in the Kelly KLS controllers.  With BLDC motors, there is real benefit to dynamic phase timing to both gain additional torque in the lower RPMs and a bit more speed at the top-end.  The trade off is more power going into the motor which can increase the motor temperature, but that is reasonable given the increase in power.  A fixed (rotate the timing sensor on the motor) would provide incremental benefit in the forward direction, but with electronic reverse, this permanent advanced angle would make reverse rotation difficult and maybe unusable. This is what contributes to the need to have dynamic timing adjustment.  The motor (Motenergy ME1306) comes from the factory set to neutral timing.

Using a Teensy 4.0, which is an impressive platform, combined with a bidirectional 5V-3.3V level shifter CYT1082 for the 6 signals (3 from the motor, 3 to the controller), the timing shifter's HW was rather easy to integrate.

A number of key teachings came from developing the phase timing shifter code.

  1. Give the motor a full revolution to stabilize before starting any timing shifts.  This means a full 24 phase changes (6 phase for 4 e-revolutions).  
  2. Having a floating point processor simplifies the process.  The phase times for the motor go from about 30,000 microseconds (at low RPM) to less than 500 microseconds when spinning at 5000 RPM.  Phase shift is typically referenced as a angular shift (independent of speed, so the algorithm selects a desired angle of shift and then computes the amount of shift time (timing advance... The time the next shift should occur) necessary to achieve that angular shift.  Floating point math just makes this easier to program.  Each phase is 60 e-degrees so the shift time = phase time x (shift angle / 60).
  3. A 600 MHz processor means that the system can loop through the state-machine many times per e-phase, minimizing the chance of a missed or delayed signal.
  4. A basic state-machine worked well with the following paths.
    1. Bypass->Forward->Advance Timing-> Bypass
    2. Bypass->Reverse->Bypass
    3. Bypass: a pass through mode when the timing signals pass through unaltered.
    4. Forward: Forward rotation is detected.
    5. Advance Timing: After a number of forward cycles, timing shifting can begin.  This includes a linear slew rate for how fast the timing is changed and a timing advancement curve that sets the target degrees of advancement based on the current RPM.
    6. Reverse - Reverse rotation is detected.  Currently the system just passes through the signals in reverse since no timing changes are needed.
  5. Using timer-driven interrupts to drive the signal change is simple, but managing two timers simultaneously is necessary since the "next" cycle may begin either before or after the previous cycle has ended depending on if the motor is accelerating or decelerating.  Also, assuring the timers have completed their cycle before the state machine transitions to another state is key to avoid unexpected signal changes.
After all of this, there is a noticeable low-RPM torque boost from the timing advance and an increase in the top-end RPMs when in neutral.  The motor now hits around 5,000 RPM in neutral where before the timing advance, it was closer to 4,500.  This was the evidence that the timing is advancing.  I have not tested to see if this will result in higher road speed.

Just a note, when the timing shifter is not functioning properly, the motor can behave quite poorly, resulting in unexpected phase changes or changes that are not aligned with the physical coils/magnets of the motor.  This resulted in some loud thunks, sudden vibrations, or other undesirable motor actions.  There is still some empirical work to do to see what the optimum timing advancement curve should be. 

Currently the timing advance curve looks like this.
 RPMs                  25k    5k   3333   2500  1250   833   625   416   357     156  
angleOut[] =   {      35,   45,    45,    45,     35,     35,     30,     25,   25,      20}