I posted this idea here in the context of analog buck control:
https://budgetlightforum.com/t/-/41762
But I thought the details of this DAC are a little more general and worth their own post. This isn't novel, and Ti has documents even describing multi-cap setups to reduce ripple farther for instance, but maybe it's useful.
I'd post a typeset document but BLF doesn't keep images around so this is better.
We want to charge cap to a DC voltage from a PWM. You construct a voltage divider connecting the PWM output to the top of the cap through R1, and the top of the cap to ground through R2. The bottom of the cap connects directly to ground. Presumably something else connects to the top of the cap to sense its voltage.
In the special case of the LM3409 IC current adjust pin that inspired this, there is also an approximately 5uA current passing directly to the cap from the IC (used to bias an internal diode). I'll call this bias current I_B. In general this could be positive or negative or other more resistive leaks may exist that can be folded into R2 instead.
Variables:
C: capacitance
I_B bias current onto cap from LM3409 (or such). Use 0 for other applications.
D: Duty cycle of PWM
V_i: Input voltage from PWM (output voltage of mcu)
V: voltage on output cap, our analog output signal.
G: voltage divider "gain" factor: R2/(R1+R2)
To find the equilibrium voltage you just write down the average current for one full PWM cycle (on-time current current times D plus off-time current * (1-D)) as a function of V_i and V. Then set it equal to zero and solve for V. The result is:
Output voltage
V=GDV_i + G R1 I_B
Neglecting I_B it's just the obvious input voltage times divider times duty cycle. Great.
Ripple, peak to peak:
To get ripple you just write down (either) the on time (or off time) current and multiply by D (or 1-D) and /fC.
The result in terms of V is:
V_pp= [ V/(R1G)-I_B](1-D)/(fC)
Fractional ripple is then
V_pp/V= [1/(R1G)-I_B/V](1-D)/(fC) and the I_B term should normally be small/neglectable
This is a maximum as duty cycle approaches zero (zero output voltage). It increases with decreasing G (as max output voltage is set lower max ripple gets worse) BUT i'ts always zero at D=1, ie at max output. For this reason it's still best to use the divider, not softare PWM, to set the max output, because then at max output control ripple is zero, and that's where it matters most.
Neglecting I_B, a simple estimate of max factional ripple is obviously:
V_pp/V= 1/(R1*C*f*G)
Response time, tau, or effective RC:
Tau=R1*C*G
(easily seen by writing down dV/dt=I_average/C, using the same average I as above, and simply examining the coefficient on the V term)
It can be tempting to make R1C huge to avoid ripple and/or to create nice soft 1/2 second transitions. But other currents, leakage etc must be considered, in this case I_B. See the V offset note below. However C can be made large without negative consequences, if you can fit a large enough capacitor in.
V offset/minimum:
In the output voltage equation above notice the offset voltage I_B*R1*G creates a minimum output voltage and an offset to the voltage curve. High values of R increase this. For the LM3409 application this will mean the highest modes saturate the input and moonlight won't be reachable (but we'll use other tricks for that anyway).
The offset as a fraction of max output voltage is clearly:
V_offset/V_max= I_B*R1/(V_i+I_B*R1)
which if kept reasonably small is approximated by the nearly intuitive expression:
V_offset/V ~ I_B/ (V_i/R1)
So in simple terms V_i/R1 should be kept much larger (100 times if you want to reach 1% output) than the bias current.
(minor clarity edits)