FOC questions

Without knowing exactly how you've implemented the duty mode and sensors observer with duty mode it's very hard to say. One thing of note is that if you're limiting the duty, the current control can no longer be effective, and depending which variables where and how you're using them, the observer might not be getting what's actually going into the motor.

Or you might just need to adapt the resistance and inductance parameters.
Well the duty mode was just incrementing/decrementing Vq thru a time constant buffer (no PID).
The sensored observer at startup just gives 6 angles, one for each middle sector (like 6 step commutation), but now i working on implementing to get real angles from it.
I tried (sensorless after start) torque/current mode Vq thru PID and that works a lot better, no more losing sinc, if i command say 2-3 amps, rotor will speed up, and if apply load to rotor it will slow down until stops, seems ok. But in this mode it does no do regen any more.
Another issue, i'm having trouble switching from sensored after start to sensorless run, but that is because of my poor sesored implementation (6 step) .
Can you explain a bit what does the PLL in sensored observer? i'm a bit confused about this PLL thing, i watched some tutorials on it, i understand its use in freq multiplication, but that is it. Even RPM calculation with PLL baffles me.
 
Well the duty mode was just incrementing/decrementing Vq thru a time constant buffer (no PID).
The sensored observer at startup just gives 6 angles, one for each middle sector (like 6 step commutation), but now i working on implementing to get real angles from it.
I tried (sensorless after start) torque/current mode Vq thru PID and that works a lot better, no more losing sinc, if i command say 2-3 amps, rotor will speed up, and if apply load to rotor it will slow down until stops, seems ok. But in this mode it does no do regen any more.
Another issue, i'm having trouble switching from sensored after start to sensorless run, but that is because of my poor sesored implementation (6 step) .
Can you explain a bit what does the PLL in sensored observer? i'm a bit confused about this PLL thing, i watched some tutorials on it, i understand its use in freq multiplication, but that is it. Even RPM calculation with PLL baffles me.
Firstly... You get regen by requesting a negative iq in your PI controller input. If your math is done properly it'll just work. Secondly... Why do you want Regen on a plane?

The pll for the sensored observer is just a PI controller.

It guesses the next angle by adding angle increments to the last estimated angle. When it next gets a measured data point (hall sensor state change) it calculates an error from the difference between estimated angle and measured angle, and therefore can improve its guess of the increment to apply.
 
Firstly... You get regen by requesting a negative iq in your PI controller input. If your math is done properly it'll just work. Secondly... Why do you want Regen on a plane?

The pll for the sensored observer is just a PI controller.

It guesses the next angle by adding angle increments to the last estimated angle. When it next gets a measured data point (hall sensor state change) it calculates an error from the difference between estimated angle and measured angle, and therefore can improve its guess of the increment to apply.
The main usage of these FOC is for terrestrial use, this is my test platform project Electric Drift Trike Build
Did you had problem with current range of the current sensor/shunt? i'm getting really high phase current "spikes", i put the current sanity check on phase currents and its limit is at 90A, same code implementation like in MESCFOC, so those "spikes" do trip the safety shut off. I have 30A hall current sensors with shunts bypassing current in order to extend the range up to about 110A (not exact, nor 100%shure), i used allegro app note to calculate this shunts, they say it is common practice to increase the current sensors rage.
The motor is a 1800w vevor MY1020 48v inrunner, tryed on 36V and on 60v batt, the same "spikes" trip the shut off.
I had to buffer the throttle so that it is not possible to aggressively increase the Iq request, so that current "spikes" stay down,
If i remove the over current shutoff, once the sensors get over ranged, the sensorless FOC gets it trouble from that, and starts to run bad and loses sink.
 
The main usage of these FOC is for terrestrial use, this is my test platform project Electric Drift Trike Build
Did you had problem with current range of the current sensor/shunt? i'm getting really high phase current "spikes", i put the current sanity check on phase currents and its limit is at 90A, same code implementation like in MESCFOC, so those "spikes" do trip the safety shut off. I have 30A hall current sensors with shunts bypassing current in order to extend the range up to about 110A (not exact, nor 100%shure), i used allegro app note to calculate this shunts, they say it is common practice to increase the current sensors rage.
The motor is a 1800w vevor MY1020 48v inrunner, tryed on 36V and on 60v batt, the same "spikes" trip the shut off.
I had to buffer the throttle so that it is not possible to aggressively increase the Iq request, so that current "spikes" stay down,
If i remove the over current shutoff, once the sensors get over ranged, the sensorless FOC gets it trouble from that, and starts to run bad and loses sink.
Sounds like you need to do the pid tuning. Did you look into my calculate gains function? That should show you how to set the proportional and integral gains such that the currents remain in control.

Assuming you haven't got some other problem that is...
 
Sounds like you need to do the pid tuning. Did you look into my calculate gains function? That should show you how to set the proportional and integral gains such that the currents remain in control.

Assuming you haven't got some other problem that is...
that may be... well this FOC stuff has a lot of parameters, many of them need a good explanation of what do they do, so far i'm struggling understanding their implication and their effect, and i do not know how it should work right. BLDC 6 step that i'm used to is waaaay simple.
So still learning.
on Id pid what does I and P gain do and on Iq pid what does I and P gain do ?, i mean i tested some values, seen some results, but i do not know when is right or wrong, how about motor inductance and resistance? If you can give a brief description of how they affect or should affect the algorithm...
 
i did manage to tune the PID a bit more, i did have the issue of not using S.I. units for the values of all the parameters, voltage current and so on..., went out with the drift trike tested the controller with 60V batt, did work better but still losing sinc when crossing from sensored to sensorless... had to fiddle the throttle just right to make that crossing, once in sensorless i could give it full beans it did go up to about 30km/h, it could go even more but did not have enough length in the parking lot. Them it pulled some slides, and after an agressive slide with burnout with my kid on the drift trike, when let off the throttle the motor stopped abruptly, and then silence. Upon investigation i found LM5017 buck blown, and one high side FET on one phase also shorted, the conclusion is that during motor abrupt stop it overvolted because regen i guess. During some no load tests i found that if the motor stops very abruptly from high speed it does over volt, some logs showed Vbus up to 126v on 60v batt... so yeah, just found that regen has to be handled with great care... but hey we did have some fun with it, and smoking the controller while on the ground is very anticlimactic, i'm used to heave smoked controller while flying :ROFLMAO:
 
I have made the hall implementation, without interpolation works great, good torque all that.
I have also made hall sensor interpolation, and it kind-of works, it somehow produces rpm/angle fluctuation ,with a small motor seems to run smooth, because rpm fluctuations are not so pronounced on a small rotor inertia, it does not jerk so much, but on a big motor like MY1020, once the interpolation starts, it runs jerky. The RPM calculation is made such that it count sectors, so once the interpolation kicks in, the rpm counter doubles but not the physical RPM , it is like interpolation runs twice thru sectors in same amount of time, hence rpm/angle fluctuations... . So there is definitely wrong with the interpolation. here is my code, Any thoughts?

Code:
//...
_motor->START_BLO_ANG=500;
_motor->HALL_ANGLE_OFFSET=0.0f;
//...

//Hall block comutation
   Get_Hall_State(&FOC);    //Get hall input
        if(_motor->RPM < START_BLO_ANG && _motor->started_flag==0)  //Run only below this rpm and at startup
        {

            if(CW_CCW==1)
            {
                switch(_motor->Hall_State)
                {
                    case 1:
                        _motor->theta_angle=-2.094f - _motor->HALL_ANGLE_OFFSET;
                    break;
                    case 2:
                        _motor->theta_angle=2.094f - _motor->HALL_ANGLE_OFFSET;
                    break;
                    case 3:
                        _motor->theta_angle=3.141f - _motor->HALL_ANGLE_OFFSET;
                    break;
                    case 4:
                        _motor->theta_angle=-0.0f - _motor->HALL_ANGLE_OFFSET;
                    break;
                    case 5:
                        _motor->theta_angle=-1.047f - _motor->HALL_ANGLE_OFFSET;
                    break;
                    case 6:
                        _motor->theta_angle=1.047f - _motor->HALL_ANGLE_OFFSET;
                    break;
                }
            }
            else
            {
                switch(_motor->Hall_State)
                {
                    case 1:
                        _motor->theta_angle=0.0f + _motor->HALL_ANGLE_OFFSET;
                    break;
                    case 2:
                        _motor->theta_angle=-2.094f + _motor->HALL_ANGLE_OFFSET;
                    break;
                    case 3:
                        _motor->theta_angle=-1.047f + _motor->HALL_ANGLE_OFFSET;
                    break;
                    case 4:
                        _motor->theta_angle=2.094f + _motor->HALL_ANGLE_OFFSET;
                    break;
                    case 5:
                        _motor->theta_angle=1.047f + _motor->HALL_ANGLE_OFFSET;
                    break;
                    case 6:
                        _motor->theta_angle=-3.141f + _motor->HALL_ANGLE_OFFSET;
                    break;
                }

            }


        }
//....


//Interpolation
//...
   Get_Hall_State(&FOC);    //Get hall input

    if(_motor->Hall_State ==_motor->Prev_Hall_State)
    {
        if( _motor->RPM > (START_BLO_ANG/2))    //start over a certain rpm o avoid overflow of the pwm_count at 0 rpm, 
                                                                             //and have it running before actually kicking in
        {
            _motor->pwm_count =_motor->pwm_count+1.0f;

            if(_motor->pwm_count >_motor->prev_pwm_count) _motor->prev_pwm_count = _motor->pwm_count;

            if(CW_CCW==1)
            {
                if(_motor->hall_theta_angle >-3.14)
                {
                    _motor->hall_theta_angle =_motor->hall_angle -((_motor->pwm_count *1.047f)/_motor->prev_pwm_count);    //interpolate
                }
                else _motor->hall_theta_angle= 3.14;    //wrap around
            }
            else
            {
                if(_motor->hall_theta_angle <3.14)
                {
                    _motor->hall_theta_angle =_motor->hall_angle +((_motor->pwm_count *1.047f)/_motor->prev_pwm_count);    //interpolate
                }
                else _motor->hall_theta_angle= -3.14;    //wrap around
            }
        }
    }
    else //if new sector update angle
    {
        _motor->prev_pwm_count= _motor->pwm_count;    //save count
        _motor->pwm_count =0;    //reset count
        _motor->Prev_Hall_State=_motor->Hall_State;    //save hall state

        if(CW_CCW==1)
        {
            switch(_motor->Hall_State)    //Update angle begining->midle of sector
            {
                case 1:
                _motor->hall_angle= -2.094f - _motor->HALL_ANGLE_OFFSET;
                break;
                case 3:
                _motor->hall_angle= 3.141f - _motor->HALL_ANGLE_OFFSET;
                break;
                case 2:
                _motor->hall_angle= 2.094f - _motor->HALL_ANGLE_OFFSET;
                break;
                case 6:
                _motor->hall_angle= 1.047f - _motor->HALL_ANGLE_OFFSET;
                break;
                case 4:
                _motor->hall_angle= 0.0f - _motor->HALL_ANGLE_OFFSET;
                break;
                case 5:
                _motor->hall_angle= -1.047f - _motor->HALL_ANGLE_OFFSET;
                break;

            }
        }
        else
        {
            switch(_motor->Hall_State)    //Update angle begining->midle of sector
            {
                case 1:
                _motor->hall_angle= 0.0f + _motor->HALL_ANGLE_OFFSET;
                break;
                case 5:
                _motor->hall_angle= 1.047f + _motor->HALL_ANGLE_OFFSET;
                break;
                case 4:
                _motor->hall_angle= 2.094f + _motor->HALL_ANGLE_OFFSET;
                break;
                case 6:
                _motor->hall_angle= -3.141f + _motor->HALL_ANGLE_OFFSET;
                break;
                case 2:
                _motor->hall_angle= -2.094f + _motor->HALL_ANGLE_OFFSET;
                break;
                case 3:
                _motor->hall_angle= -1.047f + _motor->HALL_ANGLE_OFFSET;
                break;



            }

        }
//...
 
Hm, if you just do linear extrapolation, you'll never exactly hit the right angle at the next hall event.
I solved the extrapolation with just one line of code:

This solution is more noisy than the PLL for the angle estimation, because with the PLL you will never get an negative angle increment, that causes a noisy jerk. But for most of the motors I tested, the extrapolation is sufficient, only a few motors need the PLL to run smoothly.

The PLL is no witchwork at all. It just calculates the angle increment from one PWM cycle to the next.

regards
stancecoke
 
Last edited:
Hm, if you just do linear extrapolation, you'll never exactly hit the right angle at the next hall event.
I solved the extrapolation with just one line of code:

This solution is more noisy than the PLL for the angle estimation, because with the PLL you will never get an negative angle increment, that causes a noisy jerk. But for most of the motors I tested, the extrapolation is sufficient, only a few motors need the PLL to run smoothly.

The PLL is no witchwork at all. It just calculates the angle increment from one PWM cycle to the next.

regards
stancecoke
hy, thanks for your input, i have looked on it, will think about it and learn. In the mean time, i figured out some things, first is that i got bit by the hall sensor noise again, and only if i had not been in that position before..., yep... Then the second, i modified the code so that interpolation in sectors can not switch sector, only hall event can switch sector, that cleared a lot of jerkiness, but most was cleared after i filtered the hall inputs both in HW and SW. Now starts to be better, the goal is to start sensored in block mode up to 100rpm then use interpolation up to about 500-800rpm then switch to sensorless up to max, be it 6000rpm or so...
 
well some of my hall noise was caused by slow FETs (IRFP4468 with added 33nF on gates. This is test setup) and not enough dead time, 2us, at 22,5Khz PWM freq, the turn on and off kind of overlapped a bit with 2us deadtime....increased deadtime to 3us and is cleared that noise on Hall signals... now interpolation works nice.... bummer... I was so focused on SW i forgot to look on the scope to se what is going on with the FETs.....at first about half a year ago i had 800ns dead time and had about 0,5Amp continuous draw without any motor connected :D
 
well some of my hall noise was caused by slow FETs (IRFP4468 with added 33nF on gates. This is test setup) and not enough dead time, 2us, at 22,5Khz PWM freq, the turn on and off kind of overlapped a bit with 2us deadtime....increased deadtime to 3us and is cleared that noise on Hall signals... now interpolation works nice.... bummer... I was so focused on SW i forgot to look on the scope to se what is going on with the FETs.....at first about half a year ago i had 800ns dead time and had about 0,5Amp continuous draw without any motor connected :D
Mihai, this is not a win. 3us dead time at 22.5khz is crippling, that's eating 13% of your available voltage. Sorry but this is just not a place you want to be for a high performance controller.

3us rise and 3us fall per pwm so 6us
22.5khz is 44.4us.
 
Mihai, this is not a win. 3us dead time at 22.5khz is crippling, that's eating 13% of your available voltage. Sorry but this is just not a place you want to be for a high performance controller.

3us rise and 3us fall per pwm so 6us
22.5khz is 44.4us.
O yes, that is crap for switching, this setup is just some beefy parts that i had around and would be strong enough to drive my ass around for some fun, and test the FOC SW, plus this bundle of wires between bords was a nightmare of noise and crap signal, as soon as the phase amps got over 50A.
The correct HW with the adequate parts are ordered and on they'r way (PCB and components), in the next weeks i'l assemble and the test.
 
@mxlemming , i have a question regarding SI units for the inputs of the flux observer,
"flux_a = flux_a + (Vab.a - m.R * Iab.a)* pwm_period- m.L_D * (Iab.a - Ia_last)"
Vab.a is in Volts aka V
m.Rin is in Ohms aka "omega"
Iab.a is in Amps aka A
pwm_period is 1/PWM freq in Hz (ex. 1/20000)
m.L_D in in Henry aka H
Since i made the move to SI units the flux observer does not work any more.
Before the Volts had a range from 0 to 1000 and fluxobserver was working, now it is in the range of Vbat (0-48v) it does not work any more
 
@mxlemming , i have a question regarding SI units for the inputs of the flux observer,
"flux_a = flux_a + (Vab.a - m.R * Iab.a)* pwm_period- m.L_D * (Iab.a - Ia_last)"
Vab.a is in Volts aka V
m.Rin is in Ohms aka "omega"
Iab.a is in Amps aka A
pwm_period is 1/PWM freq in Hz (ex. 1/20000)
m.L_D in in Henry aka H
Since i made the move to SI units the flux observer does not work any more.
Before the Volts had a range from 0 to 1000 and fluxobserver was working, now it is in the range of Vbat (0-48v) it does not work any more
I do not think I can help with this, it works for me and all you said is "I attempted to copy it and it does not work" from which I infer you did not completely and accurately copy it, or have wrong parameters.
 
I found this document https://s3.amazonaws.com/scolton-www/motordrive/sensorless_gen1_Rev1.pdf
that discuses FOC but the interest is the Flux Observer and in particular the integration problem (page 29),
My flux observer with low pass filter working got suddenly explained in that paper, they call it "pseudo integrator" low pass filter.
After i moved to SI units and the V got its range down from 1000 to 48, now my filter needs different filtering parameters in order to work again, this is an adaptive to change filter, but the change is multiplied by 0.001f, and if my V range is more than an order of magnitude lower (almost 2), that parameter needs to be lower.
So with 0.1f works again.
Now the "pseudo integrator" LPF- needs to be tweaked as they say in that paper. And also noticed that LPF has a phase shift with respect to motor rpm (frequency), the Vd increases exponentialy in order to keep Id at 0 as the motor rpm goes higher, tested it up to 30k rpm with a 6 pole motor.
"_motor->flux_a_filt += (_motor->flux_a - _motor->flux_a_filt) *(fabsf((_motor->flux_a - _motor->flux_a_filt))*0.001f);"
"Science!"
I got frustrated again working with hall sensors (rotor position), and i rememberd again why i hated them, nosie and crap precision, implementing interpolation from crap signal is carp interpolation.- kinda works , but it sucks.
Sensorless is the way to go....
 
I found this document https://s3.amazonaws.com/scolton-www/motordrive/sensorless_gen1_Rev1.pdf
that discuses FOC but the interest is the Flux Observer and in particular the integration problem (page 29),
My flux observer with low pass filter working got suddenly explained in that paper, they call it "pseudo integrator" low pass filter.
After i moved to SI units and the V got its range down from 1000 to 48, now my filter needs different filtering parameters in order to work again, this is an adaptive to change filter, but the change is multiplied by 0.001f, and if my V range is more than an order of magnitude lower (almost 2), that parameter needs to be lower.
So with 0.1f works again.
Now the "pseudo integrator" LPF- needs to be tweaked as they say in that paper. And also noticed that LPF has a phase shift with respect to motor rpm (frequency), the Vd increases exponentialy in order to keep Id at 0 as the motor rpm goes higher, tested it up to 30k rpm with a 6 pole motor.
"_motor->flux_a_filt += (_motor->flux_a - _motor->flux_a_filt) *(fabsf((_motor->flux_a - _motor->flux_a_filt))*0.001f);"
"Science!"
I got frustrated again working with hall sensors (rotor position), and i rememberd again why i hated them, nosie and crap precision, implementing interpolation from crap signal is carp interpolation.- kinda works , but it sucks.
Sensorless is the way to go....
You really do not need to be filtering the fluxes, since they are integrals, then unless your current sensors are absolutely awful then they are already low pass filtered with a known constant phase shift. Adding filters with a time constant does not really help atall.

Using this as the input to an interplolator also makes my head swim. I actually tried this before and it was endless tuning and parameters and... ARCTAN is your friend. It seems like a lot of clock cycles, but it is not compared to the hassle and irregularity of the PLL/interpolator and filters needed to get anywhere near the same performance.
 
You really do not need to be filtering the fluxes, since they are integrals, then unless your current sensors are absolutely awful then they are already low pass filtered with a known constant phase shift. Adding filters with a time constant does not really help atall.

Using this as the input to an interplolator also makes my head swim. I actually tried this before and it was endless tuning and parameters and... ARCTAN is your friend. It seems like a lot of clock cycles, but it is not compared to the hassle and irregularity of the PLL/interpolator and filters needed to get anywhere near the same performance.
I do not use integration, because winds up and does not center well, just flux=V-(i*r) *(1/freq)-L(i-i_prev), then LPF as an pseudo integrator like they say in the document, so after LPF there is no bias no decentering no windup, just flux with some phaseshift, then atan2 to get the angle. (the interpolation was for the sensored part)
 
I do not use integration, because winds up and does not center well, just flux=V-(i*r) *(1/freq)-L(i-i_prev), then LPF as an pseudo integrator like they say in the document, so after LPF there is no bias no decentering no windup, just flux with some phaseshift, then atan2 to get the angle. (the interpolation was for the sensored part)
That is not a flux then. Flux IS the integral of voltage... what you have is a corrected and low passed voltage.

I guess that works... complicated way of achieving the same, and you have to deal with the phase shift which you do not have to with integration but hey.

Maybe monitor power factor and adjust the phase shift to target unity?
 
@mxlemming
hy,
i sorted some things out, i was using wrong ecuations from turorials for FOC algorithm, the reason nothing worked as expected... ,now i use the ones in MESC, now the flux observer works (MESC version with integration), now it keeps the rotation direction and it changes only when i command negative or positive Vq, as expected i guess .
Can you please tell me some values for motor parameters that you tested and worked and not worked in sensorless mode (flux observer). inductance, resistence, pole pairs, PI parameters, i't would help me to see some numbers that work together, because i have no ideea how it should work ok.
How should the Id Iq look? how should Vd look? describe how is/ how Id Iq look when the motor works ok
I have 2 motors, one 30poles that has constant Id and Iq, for this motor i can tun the PI, "sims" fine, and one with 6poles MY1020 Vevor that has verry wiggly Id, Iq sims fine, for this motor i can not tune the PI in any way.... it starts spinning then goes berserk motor, because wiggly Id, .
 
Last edited:
@mxlemming
hy,
i sorted some things out, i was using wrong ecuations from turorials for FOC algorithm, the reason now nothing working as expected... ,now i use the ones in MESC, now the flux observer works (MESC version with integration), now it keeps the rotation direction and it changes only when i command negative or positive Vd, as expected i guess .
Can you please tell me some values for motor parameters that you tested and worked and not worked in sensorless mode (flux observer). inductance, resistence, pole pairs, PI parameters, i't would help me to see some numbers that work together, because i have no ideea how it should work ok.
How should the Id Iq look? how should Vd look? describe how is/ how Id Iq look when the motor works ok
I have 2 motors, one 30poles that has constant Id and Iq, for this motor i can tun the PI, "sims" fine, and one with 6poles MY1020 Vevor that has verry wiggly Id, Iq sims fine, for this motor i can not tune the PI in any way.... it starts spinning then goes berserk motor, because wiggly Id, .
Within the project there's a folder full of motor default parameters you can look at. It includes inrunners, outrunners of various sizes.

Then in the mescfoc file you can find the way to calculate the kp and ki from these. It's all in there, publicly available.
 
hy @mxlemming,
i have a question regarding, flux linkage max / min limits used in the flux observer, why 1,7 and 0,5 during the calculation of min and max. does it ever need wider range, like in really big motors? i noticed that for small motors the flux_a and b "range" is smaller never reaches the limits, but for really big motor it reaches it's max value (no good for angle), and if i use higher flux linkage value it's min value is to big at startup and does not center, and fails to rotate...
how about the integral initial state, in reality it is not 0, and if not it starts with offset, aka not centered. Can you explain a bit?
here is the code that i'm refering with 1,7 and 0,5
Code:
      _motor->m.flux_linkage_max = 1.7f*_motor->m.flux_linkage;
      _motor->m.flux_linkage_min = 0.5f*_motor->m.flux_linkage;
another question (just a thought) is regarding flux calculation in flux observer, during integration it uses the Va and Vb "pseudo BEMF" from CCRx output value, so lets say the motor spins at 1000rpm witch has a real BEMF of say X with a load say Z with a q comand of 10A, if we increase the load at 2*Z, then the rpm wil go down say half (500rpm) and we maintain q comand at 10A, that 500rpm wil have a lower real BEMF value say half Z /2, and if the q command says the same in both cases that means the CCRx value does not change and that means the Va and Vb is the same in both cases, but in reality BEMF amplitude is tied to rpm, so isn't this a problem for the flux observer? or the flux observer does no care of amplitude of the BEMF in order to find angle, and is just the phase of the BEMF that matters? i know that atan2 cares just about the phase of its inputs to get the angle, amplitude does not change the output angle. So please explain a bit.
 
Back
Top