Created
March 4, 2018 08:37
-
-
Save bradysalz/9e4f57db8305da5b4587774161be1c35 to your computer and use it in GitHub Desktop.
Interleaving Power Converters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Interleaved Buck Converter Simulations | |
Brady Salz | |
March 3 2018 | |
This script helps us visualize the improvements in the output current ripple | |
of interleaved buck converters. We can view this as a 2D optimization over | |
the phase difference between the converters and the duty cycle of each | |
converter. | |
""" | |
import matplotlib as mpl | |
import matplotlib.pyplot as plt | |
import numpy as np | |
mpl.style.use('research') | |
def gen_wave(duty_cycle: float, num_points: int = 100, | |
cycles: int = 1) -> np.ndarray: | |
"""Creates a triangle wave | |
Args: | |
duty_cycle: on-time percentage (50% ontime would be 0.5) | |
num_points: number of points in one period | |
cycles: how many times to repeat the waveform | |
Returns: | |
1D waveform | |
""" | |
on_length = int(duty_cycle * num_points) | |
off_length = num_points - on_length | |
i_out = np.append( | |
np.linspace(-1, 1, num=on_length), np.linspace(1, -1, num=off_length)) | |
i_out = np.tile(i_out, cycles) | |
return i_out | |
def interleave(waveform: np.ndarray, num_conv: int, | |
phase: float) -> np.ndarray: | |
"""Interleaves N copies of waveform by phase amount | |
Args: | |
waveform: 1D numpy array (usually triangular) | |
num_conv: the number of parallel converters to emulate | |
phase: offset in degrees of each converter. | |
Returns: | |
1D interleaved waveform | |
Note the phase offset is modular, e.g. 4 converters, each with a phase | |
offset of 100 degrees woud result in the 4th one having a '400 degree | |
offset', which wraps back around to 40 degrees. | |
""" | |
v_sum = np.zeros(waveform.shape) | |
length = waveform.size | |
for conv in range(num_conv): | |
shift = int(phase / 360 * conv * length) | |
v_sum += np.roll(waveform, shift) | |
return v_sum | |
def calc_ripple_reduction(num_conv: int, num_phase_points: int, | |
num_duty_points: int): | |
"""Plots ripple reduction contour plot! | |
Args: | |
num_conv: how many converters to interleave | |
num_phase_points: number of phase points | |
(steps in increments of 360/num_points) | |
num_duty_points: number of duty cycle points | |
(steps in increments of 100/num_points) | |
""" | |
degrees = np.linspace(0, 360, num_phase_points) | |
duty_cycles = np.linspace(0, 1, num_duty_points) | |
rvals = np.zeros((degrees.size, duty_cycles.size)) | |
for idx, deg_shift in enumerate(degrees): | |
for idy, duty in enumerate(duty_cycles): | |
v_out = gen_wave(duty) | |
v_sum = interleave(v_out, num_conv, deg_shift) | |
ripple = np.amax(v_sum) - np.amin(v_sum) | |
rvals[idx, idy] = ripple | |
rvals = rvals / np.amax(rvals) * 100 # normalize to 100% ripple | |
levels = np.array([0, 10, 25, 50, 75, 100]) | |
plt.set_cmap("plasma") | |
plt.contour(100 * duty_cycles, degrees, rvals, levels=levels) | |
cs = plt.contourf(100 * duty_cycles, degrees, rvals, levels=levels) | |
proxy = [ | |
plt.Rectangle((0, 0), 1, 1, fc=pc.get_facecolor()[0]) | |
for pc in cs.collections | |
] | |
plt.legend(proxy, | |
["0 - 10%", "10 - 25%", "25 - 50%", "50 - 75%", "75 - 100%"]) | |
plt.xlabel("Duty Cycle [%]") | |
plt.ylabel("Phase Shift [deg]") | |
plt.title("Ripple Reduction with %d Converters" % num_conv) | |
plt.tight_layout() | |
plt.show() | |
if __name__ == '__main__': | |
calc_ripple_reduction(4, 360, 100) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment