# Coverage for pySDC/implementations/problem_classes/BuckConverter.py: 100%

## 47 statements

, created at 2024-09-09 14:59 +0000

1import numpy as np

3from pySDC.core.problem import Problem

4from pySDC.implementations.datatype_classes.mesh import mesh, imex_mesh

7class buck_converter(Problem):

8 r"""

9 Example implementing the model of a buck converter, which is also called a step-down converter. The converter has two different

10 states and each of this state can be expressed as a nonhomogeneous linear system of ordinary differential equations (ODEs)

12 .. math::

13 \frac{d u(t)}{dt} = A_k u(t) + f_k (t)

15 for :math:k=1,2. The two states are the following. Define :math:T_{sw}:=\frac{1}{f_{sw}} as the switching period with

16 switching frequency :math:f_{sw}. The duty cycle :math:d defines the period of how long the switches are in one state

17 until they switch to the other state. Roughly saying, the duty cycle can be seen as a percentage [1]_. A duty cycle of one means

18 that the switches are always in only one state. If :math:0 \leq \frac{t}{T_{sw}} \bmod 1 \leq d [2]_:

20 .. math::

21 \frac{d v_{C_1} (t)}{dt} = -\frac{1}{R_s C_1}v_{C_1} (t) - \frac{1}{C_1} i_{L_1} (t) + \frac{V_s}{R_s C_1},

23 .. math::

24 \frac{d v_{C_2} (t)}{dt} = -\frac{1}{R_\ell C_2}v_{C_2} (t) + \frac{1}{C_2} i_{L_1} (t),

26 .. math::

27 \frac{d i_{L_1} (t)}{dt} = \frac{1}{L_1} v_{C_1} (t) - \frac{1}{L_1} v_{C_2} (t) - \frac{R_\pi}{L_1} i_{L_1} (t),

29 Otherwise, the equations are

31 .. math::

32 \frac{d v_{C_1} (t)}{dt} = -\frac{1}{R_s C_1}v_{C_1} (t) + \frac{V_s}{R_s C_1},

34 .. math::

35 \frac{d v_{C_2} (t)}{dt} = -\frac{1}{R_\ell C_2}v_{C_2} (t) + \frac{1}{C_2} i_{L_1} (t),

37 .. math::

38 \frac{d i_{L_1} (t)}{dt} = \frac{R_\pi}{R_s L_1} v_{C_1} (t) - \frac{1}{L_1} v_{C_2} (t) - \frac{R_\pi V_s}{L_1 R_s}.

40 using an initial condition.

42 Parameters

43 ----------

44 duty : float, optional

45 Duty cycle :math:d between zero and one indicates the time period how long the converter stays on one switching

46 state until it switches to the other state.

47 fsw : int, optional

48 Switching frequency, it is used to determine the number of time steps after the switching state is changed.

49 Vs : float, optional

50 Voltage at the voltage source :math:V_s.

51 Rs : float, optional

52 Resistance of the resistor :math:R_s at the voltage source.

53 C1 : float, optional

54 Capacitance of the capacitor :math:C_1.

55 Rp : float, optional

56 Resistance of the resistor in front of the inductor :math:R_\pi.

57 L1 : float, optional

58 Inductance of the inductor :math:L_1.

59 C2 : float, optional

60 Capacitance of the capacitor :math:C_2.

61 Rl : float, optional

62 Resistance of the resistor :math:R_\pi

64 Attributes

65 ----------

66 A : np.2darray

67 Coefficient matrix of the ODE system.

69 Note

70 ----

71 The duty cycle needs to be a value in :math:[0,1].

73 References

74 ----------

75 .. [1] J. Sun. Pulse-Width Modulation. 25-61. Springer, (2012).

76 .. [2] J. Gyselinck, C. Martis, R. V. Sabariego. Using dedicated time-domain basis functions for the simulation of

77 pulse-width-modulation controlled devices - application to the steady-state regime of a buck converter. Electromotion (2013).

78 """

80 dtype_u = mesh

81 dtype_f = imex_mesh

83 def __init__(self, duty=0.5, fsw=1e3, Vs=10.0, Rs=0.5, C1=1e-3, Rp=0.01, L1=1e-3, C2=1e-3, Rl=10):

84 """Initialization routine"""

86 # invoke super init, passing number of dofs

87 nvars = 3

88 super().__init__(init=(nvars, None, np.dtype('float64')))

89 self._makeAttributeAndRegister(

90 'nvars', 'duty', 'fsw', 'Vs', 'Rs', 'C1', 'Rp', 'L1', 'C2', 'Rl', localVars=locals(), readOnly=True

91 )

93 self.A = np.zeros((nvars, nvars))

95 def eval_f(self, u, t):

96 """

97 Routine to evaluate the right-hand side of the problem.

99 Parameters

100 ----------

101 u : dtype_u

102 Current values of the numerical solution.

103 t : float

104 Current time of the numerical solution is computed.

106 Returns

107 -------

108 f : dtype_f

109 The right-hand side of the problem.

110 """

111 Tsw = 1 / self.fsw

113 f = self.dtype_f(self.init, val=0.0)

114 f.impl[:] = self.A.dot(u)

116 if 0 <= ((t / Tsw) % 1) <= self.duty:

117 f.expl[0] = self.Vs / (self.Rs * self.C1)

118 f.expl[2] = 0

120 else:

121 f.expl[0] = self.Vs / (self.Rs * self.C1)

122 f.expl[2] = -(self.Rp * self.Vs) / (self.L1 * self.Rs)

124 return f

126 def solve_system(self, rhs, factor, u0, t):

127 r"""

128 Simple linear solver for :math:(I-factor\cdot A)\vec{u}=\vec{rhs}.

130 Parameters

131 ----------

132 rhs : dtype_f

133 Right-hand side for the linear system.

134 factor : float

135 Abbrev. for the local stepsize (or any other factor required).

136 u0 : dtype_u

137 Initial guess for the iterative solver.

138 t : float

139 Current time (e.g. for time-dependent BCs).

141 Returns

142 -------

143 me : dtype_u

144 The solution as mesh.

145 """

146 Tsw = 1 / self.fsw

147 self.A = np.zeros((3, 3))

149 if 0 <= ((t / Tsw) % 1) <= self.duty:

150 self.A[0, 0] = -1 / (self.C1 * self.Rs)

151 self.A[0, 2] = -1 / self.C1

153 self.A[1, 1] = -1 / (self.C2 * self.Rl)

154 self.A[1, 2] = 1 / self.C2

156 self.A[2, 0] = 1 / self.L1

157 self.A[2, 1] = -1 / self.L1

158 self.A[2, 2] = -self.Rp / self.L1

160 else:

161 self.A[0, 0] = -1 / (self.C1 * self.Rs)

163 self.A[1, 1] = -1 / (self.C2 * self.Rl)

164 self.A[1, 2] = 1 / self.C2

166 self.A[2, 0] = self.Rp / (self.L1 * self.Rs)

167 self.A[2, 1] = -1 / self.L1

169 me = self.dtype_u(self.init)

170 me[:] = np.linalg.solve(np.eye(self.nvars) - factor * self.A, rhs)

171 return me

173 def u_exact(self, t):

174 r"""

175 Routine to compute the exact solution at time :math:t.

177 Parameters

178 ----------

179 t : float

180 Time of the exact solution.

182 Returns

183 -------

184 me : dtype_u

185 The exact solution.

186 """

187 assert t == 0, 'ERROR: u_exact only valid for t=0'

189 me = self.dtype_u(self.init)

191 me[0] = 0.0 # v1

192 me[1] = 0.0 # v2

193 me[2] = 0.0 # p3

195 return me