PWM Deadtime compensation

Uh oh, IDK, take the discussion however you like, it will not undo what has been done, people can still read the stuff above, which mostly answers the question of how to change dead time on the board. I think we are mostly done with that subject, I would just make a new post for organizational reasons of the forum if the subject is changed but all good to me.

Moved to new thread by popular demand :smiley:

Thanks @runger, and sorry for creating that mess.

Here is another illustration of the problem with the deadtime.
This is the pwm waveform when running in openloop. The vertical lines are when the hall sensors change state, it should happen at the pwm waveform zero crossing (red arrows), with possibly a slight shift if the hall sensors are missaligned. But here it’s completely off, it means the magnetic angle generated by the windings is shifted.

Now this is with deadtime compensation. It’s much cleaner and the hall sensor signal can be used to identify the start and end electrical angle of each sector(autodetect)

That is an impressive difference, I’m really surprised!

is this with SimpleFOC code? Are the settings otherwise the same except for the deadtime compensation?

What do you mean by PWM waveform? The phase to GND voltage? Or the phase current?

Yes this is simplefoc with the changes mentioned here, I am just making the compensation 0(OFF) or 0.7V.
By PWM waveform, I mean the output duty cycles of the SVPWM sorry. I assume it’s in sync with the BEMF with low speed and load.

Now I tried something else, I halved the timers deadtime (60 to 30 cycles, it was too high anyway), and I still had to compensate by 0.5V instead of 0.7V to have a nice sinusoidal phase current waveform.
So that means I am not only compensating for the deadtime but probably also the stiction, otherwise I would have to halve the compensation as well.
If I still remember my middle school math, the deadtime compensation is 0.40V and stiction compensation is 0.30V. And by halving the deadtime, I get 0.20V deadtime compensation and still 0.30V stiction or black energy compensation.

This makes sense…

Ah, so we’re looking at the computed value for the PWM duty cycle, rather than the PWM itself or a measured voltage/current. This also makes more sense to me now.

The position of the HallSensor interrupts is an indirect feedback confirming it is probably working as intended? But to really see the effect we’d have to look at a phase current measurement?

Yes it is visible here, the phase current waveform improves as I increase the compensation.

So nice, the improvement is very visible!

Congratulations, I must say this is a very nice result. I think we should add it to SimpleFOC for the next release. I love the fact that it is implemented in a completely hardware-independent way.

We can introduce a motor.dtcomp and default it to 0 for the next release. That way existing code would not be immediately impacted, but the feature would be available to those who want to test it…

What do you think? Would you like to contribute it?

Remember I cheated by taking the easiest example (velocity openloop with slow speed and low load).
It should help get feedback from others if it works well on different controllers and motors, and with what compensation value.

Eventually I should be using the sign of the current to add or substract the compensation, but when the phase current jumps below and above zero because of noise, it’s not working well. So I need to still work on this.

Are you using a LPF on the measured current? The zero crossings would occur far less frequently than the measurements, so a good deal of filtering should be possible?

I think your solution is appropriate to the open-loop, but also the closed loop modes that don’t use current sensing. I wonder if the BEMF estimation and lag compensation we already have (when you enter the motor resistance, KV and inductance) are sufficient to also make it work at higher speeds and currents? Of course it would be subject to the same limitations as everything else when you don’t have the real current sensing, but the voltage control or estimated current control does pretty well on a wide class of motors and applications, I would say.

I think it would be cool if people could test it out if they are interested (certainly I want to try it :slight_smile: ) but I don’t have any kind of feeling yet for how hard it will be to pick good values, whether they vary a lot by setup (presumably yes because it will depend on the FETs and voltages being used) and how to give people guidelines for using it with their setup…

But looking at where it goes in the code it isn’t something we can easily add on with a new class in the drivers repository… so perhaps putting it in the code but deactivated by default for now is the way to go…

But if you think its better to wait a bit more, then that’s fine too!

I haven’t tried the LPF on the phase current sensing yet. So far my gd32 current sensing is not using any interrupt at all. But I will try it to see if it’s useful.

So far my only way to pick the right compensation value is to look at the phase current waveform, so current sensing will be needed for sure.
If I wanted to automate this by measuring the deadtime, I would increase the duty cycle until the phase current is visible, but that means we still need current sensing.
Maybe one idea would be to move to a specific position, and increase the duty cycle until the position changes. This could measure the deadtime + stiction without current sensing. But this is then getting closer to the anticogging map.

I would be happy to get feedback, I want to make sure it’s not only helping on a few setups, otherwise it’s not worth spending too much time.

We could add a freewheeling parameter, which tells the FOC loop what the minimum PWM should be. It would be the sum of deadtime_shift + stiction_PWM
The stiction_PWM could be measured during the init process I guess?

I have to think about this. “Freewheeling” is usually associated with the idea of switching all the FETs off (Hi-Z mode, also called “slow decay”).
What you’re suggesting is I think already possible with current control - by setting a 0 current target?

The stiction part I don’t fully understand yet. The dead time compensation is somewhat clear, this is a fix at the electrical level for asymmetry caused by the FET switching times and dead-time.

But the stiction seems to me to have little to do with the PWM and FET switching, but rather this is a function of the motor’s physical properties and bearing etc, as well as of course the load in a loaded situation? One would also expect the stiction to be independent of the PWM cycle/frequency?
How is it tied back to the PWM timings fix?

→ After reading through the paper you linked quickly, I think I get it. I have to read it properly this evening.

Someone shared a great idea

I ran the motor without the rotor, and I still had to compensate with 0.70v, so no it has nothing to do with stiction in my case.

1 Like

Here is my challenge, compensating based on the duty cycle below or above the center is easy and works well. But with the phase current it’s hard.

I added an interrupt for current sensing and a basic low pass filter (current = prev * 0.90 + adc * 0.10) but probably I need to be very precise with the offsets and the thresholds

Sorry for the noob question, but this formula I knew as “running average”. Is that the same as LPF?

It seems to be called first order IIR filter

1 Like

This paper is also interesting, I need to read it carefully.

I will make it :mechanical_arm:

[EDIT] I really like this paper. It also understand why my simple magnitude correction is not good enough. It seems I can start from d-q as I suggested here, instead of using the raw phase currents.

[EDIT2] @runger I think I understand now. I am now using the voltage waveform zero crossing (center crossing of duty cycle) to define the sign of the compensation. This will not work when the phase current lags behind.
atan2(current.q, current.d) should give me the phase lag. That I could use to shift when to compensate. I am always surprised how foc works with those noisy raw phase currents, but I imagine current.q and current.d must be cleaner.

1 Like

After many months, I wanted to set up the B-G431B-ESC1 again and check why I had failed in the past now that I know SimpleFOC better.

PIO_FRAMEWORK_ARDUINO_ENABLE_CDC is mentioned on many example of platformio.ini, specially in the first post of the beginner’s guide.

But it shouldn’t be used because it’s using one of the PWM signal pin as USB dataline.
Luckily I came across this post :expressionless: