femagtools 1.5.7__py3-none-any.whl → 1.6.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- femagtools/__init__.py +1 -1
- femagtools/bch.py +38 -3
- femagtools/dxfsl/area.py +2 -3
- femagtools/dxfsl/conv.py +6 -1
- femagtools/dxfsl/converter.py +10 -2
- femagtools/dxfsl/fslrenderer.py +1 -2
- femagtools/dxfsl/functions.py +24 -27
- femagtools/dxfsl/geom.py +210 -89
- femagtools/dxfsl/machine.py +43 -16
- femagtools/dxfsl/plotrenderer.py +2 -2
- femagtools/dxfsl/shape.py +84 -19
- femagtools/femag.py +21 -3
- femagtools/fsl.py +14 -2
- femagtools/machine/__init__.py +13 -33
- femagtools/machine/afpm.py +22 -21
- femagtools/machine/pm.py +22 -21
- femagtools/machine/sm.py +1 -1
- femagtools/machine/utils.py +112 -58
- femagtools/mcv.py +27 -1
- femagtools/model.py +4 -2
- femagtools/nc.py +7 -0
- femagtools/opt.py +1 -1
- femagtools/parstudy.py +5 -2
- femagtools/plot/__init__.py +1 -0
- femagtools/plot/bch.py +2 -0
- femagtools/plot/fieldlines.py +37 -0
- femagtools/templates/basic_modpar.mako +8 -0
- femagtools/templates/bertotti.mako +40 -0
- femagtools/templates/modified_steinmetz.mako +39 -0
- femagtools/ts.py +1 -1
- femagtools/utils.py +9 -3
- {femagtools-1.5.7.dist-info → femagtools-1.6.1.dist-info}/METADATA +1 -1
- {femagtools-1.5.7.dist-info → femagtools-1.6.1.dist-info}/RECORD +40 -37
- tests/test_bchreader.py +12 -1
- tests/test_femag.py +1 -1
- tests/test_fsl.py +1 -1
- {femagtools-1.5.7.dist-info → femagtools-1.6.1.dist-info}/LICENSE +0 -0
- {femagtools-1.5.7.dist-info → femagtools-1.6.1.dist-info}/WHEEL +0 -0
- {femagtools-1.5.7.dist-info → femagtools-1.6.1.dist-info}/entry_points.txt +0 -0
- {femagtools-1.5.7.dist-info → femagtools-1.6.1.dist-info}/top_level.txt +0 -0
femagtools/machine/afpm.py
CHANGED
@@ -45,7 +45,7 @@ def ld_interpol(i1, beta, v):
|
|
45
45
|
cur = copy.deepcopy(i1)
|
46
46
|
betad = copy.deepcopy(beta)
|
47
47
|
if np.amin(beta) < -90 and \
|
48
|
-
np.amax(beta) > -90:
|
48
|
+
np.amax(beta) > -90:
|
49
49
|
# motor and generator
|
50
50
|
v[0] = v[1]
|
51
51
|
v[-1] = v[-2]
|
@@ -53,18 +53,18 @@ def ld_interpol(i1, beta, v):
|
|
53
53
|
dbeta = np.abs(beta[0][0] - beta[1][0])
|
54
54
|
bp = [[beta[0][0]-dbeta for i in range(len(np.unique(i1)))]] + beta[1:-1] + \
|
55
55
|
[[dbeta for i in range(len(np.unique(i1)))]]
|
56
|
-
else:
|
56
|
+
else:
|
57
57
|
v[-1] = v[-2]
|
58
58
|
dbeta = np.abs(beta[0][0] - beta[1][0])
|
59
59
|
bp = beta[0:-1] + \
|
60
60
|
[[dbeta for i in range(len(np.unique(i1)))]]
|
61
|
-
|
61
|
+
|
62
62
|
return RectBivariateSpline(np.unique(bp), np.unique(cur), \
|
63
63
|
np.array(v)).ev(*[betad, i1]).tolist()
|
64
64
|
|
65
65
|
def lq_interpol(i1, beta, v):
|
66
66
|
'''interpolate Lq at beta -90°'''
|
67
|
-
if -90 not in np.unique(beta):
|
67
|
+
if -90 not in np.unique(beta):
|
68
68
|
return v
|
69
69
|
# lq
|
70
70
|
betad = copy.deepcopy(beta)
|
@@ -75,7 +75,7 @@ def lq_interpol(i1, beta, v):
|
|
75
75
|
v.pop(inx[0, 0])
|
76
76
|
bp = beta[0:inx[0, 0]] + beta[inx[0, 0]+1:]
|
77
77
|
cp = i1[0:inx[0, 0]] + i1[inx[0, 0]+1:]
|
78
|
-
else:
|
78
|
+
else:
|
79
79
|
v[0] = v[1]
|
80
80
|
dbeta = np.abs(beta[0][0] - beta[1][0])
|
81
81
|
bp = [[-90-dbeta for i in i1[0]]] + beta[1::]
|
@@ -181,7 +181,7 @@ def parident(workdir, engine, temp, machine,
|
|
181
181
|
poc=poc.Poc(999),
|
182
182
|
speed=0)
|
183
183
|
logging.info("Noload simulation")
|
184
|
-
if kwargs.get('use_multiprocessing', True):
|
184
|
+
if kwargs.get('use_multiprocessing', True):
|
185
185
|
pstudy = parstudy.List(
|
186
186
|
workdir, condMat=condMat, magnets=magnetMat,
|
187
187
|
magnetizingCurves=magnetizingCurves,
|
@@ -190,17 +190,17 @@ def parident(workdir, engine, temp, machine,
|
|
190
190
|
nlresults = pstudy(nlparvardef, machine, nlcalc, engine)
|
191
191
|
if nlresults['status'].count('C') != len(nlresults['status']):
|
192
192
|
raise ValueError('Noload simulation failed %s', nlresults['status'])
|
193
|
-
else:
|
193
|
+
else:
|
194
194
|
nlresults = {"x": [], "f": []}
|
195
195
|
i = 0
|
196
|
-
for pw, le, sp in zip(pole_width, lfe, linspeed):
|
196
|
+
for pw, le, sp in zip(pole_width, lfe, linspeed):
|
197
197
|
nlmachine = {k: machine[k] for k in machine}
|
198
198
|
nlmachine['pole_width'] = pw
|
199
199
|
nlmachine['lfe'] = le
|
200
200
|
nlcalc.update({"speed": sp})
|
201
201
|
nlsubdir = f'{workdir}/{i}'
|
202
202
|
nlworkdir = Path(nlsubdir)
|
203
|
-
if nlworkdir.exists():
|
203
|
+
if nlworkdir.exists():
|
204
204
|
shutil.rmtree(nlworkdir)
|
205
205
|
nlworkdir.mkdir(exist_ok=True)
|
206
206
|
noloadsim = femag.Femag(nlworkdir, condMat=condMat, magnets=magnetMat,
|
@@ -235,8 +235,8 @@ def parident(workdir, engine, temp, machine,
|
|
235
235
|
num_move_steps=60,
|
236
236
|
speed=linspeed[i],
|
237
237
|
num_par_wdgs=machine[wdgk].get('num_par_wdgs', 1))
|
238
|
-
|
239
|
-
if kwargs.get('use_multiprocessing', True):
|
238
|
+
|
239
|
+
if kwargs.get('use_multiprocessing', True):
|
240
240
|
gpstudy = parstudy.Grid(
|
241
241
|
subdir, condMat=condMat, magnets=magnetMat,
|
242
242
|
magnetizingCurves=magnetizingCurves,
|
@@ -248,7 +248,7 @@ def parident(workdir, engine, temp, machine,
|
|
248
248
|
domain_beta = np.linspace(beta_min, 0, num_beta_steps).tolist()
|
249
249
|
domain_cur = np.linspace(i1_max/num_cur_steps, i1_max, num_cur_steps).tolist()
|
250
250
|
dir_index = 0
|
251
|
-
for cur in domain_cur:
|
251
|
+
for cur in domain_cur:
|
252
252
|
for be in domain_beta:
|
253
253
|
simulation['angl_i_up'] = be
|
254
254
|
simulation['current'] = cur
|
@@ -256,7 +256,7 @@ def parident(workdir, engine, temp, machine,
|
|
256
256
|
subsubdir = subdir + f'/{dir_index}'
|
257
257
|
dir_index = dir_index + 1
|
258
258
|
lworkdir = Path(subsubdir)
|
259
|
-
if lworkdir.exists():
|
259
|
+
if lworkdir.exists():
|
260
260
|
shutil.rmtree(lworkdir)
|
261
261
|
lworkdir.mkdir(exist_ok=True)
|
262
262
|
loadsim = femag.Femag(lworkdir, condMat=condMat, magnets=magnetMat,
|
@@ -264,7 +264,7 @@ def parident(workdir, engine, temp, machine,
|
|
264
264
|
cmd=kwargs.get('cmd', None))
|
265
265
|
r = loadsim(mpart, simulation)
|
266
266
|
lresults['f'].append({k: v for k, v in r.items()})
|
267
|
-
|
267
|
+
|
268
268
|
f = [{k: bch[k]
|
269
269
|
for k in ('linearForce', 'flux', 'losses', 'lossPar')}
|
270
270
|
for bch in lresults['f']]
|
@@ -288,18 +288,18 @@ def parident(workdir, engine, temp, machine,
|
|
288
288
|
(-1, num_beta_steps)).T/np.sqrt(2)
|
289
289
|
psiq = np.reshape([r['psiq'] for r in postp],
|
290
290
|
(-1, num_beta_steps)).T/np.sqrt(2)
|
291
|
-
|
291
|
+
|
292
292
|
ld = np.reshape([r['Ld'] for r in postp],
|
293
293
|
(-1, num_beta_steps)).T.tolist()
|
294
294
|
lq = np.reshape([r['Lq'] for r in postp],
|
295
295
|
(-1, num_beta_steps)).T.tolist()
|
296
296
|
# interpolation ld, lq
|
297
|
-
curr, angl = [], []
|
298
|
-
for cr in range(len(beta)):
|
297
|
+
curr, angl = [], []
|
298
|
+
for cr in range(len(beta)):
|
299
299
|
curr.append(i1)
|
300
|
-
for al in beta:
|
300
|
+
for al in beta:
|
301
301
|
tmp = []
|
302
|
-
for cr in range(len(i1)):
|
302
|
+
for cr in range(len(i1)):
|
303
303
|
tmp.append(al)
|
304
304
|
angl.append(tmp)
|
305
305
|
try:
|
@@ -307,10 +307,10 @@ def parident(workdir, engine, temp, machine,
|
|
307
307
|
ld = ld_interpol(xx, yy, ld)
|
308
308
|
xx, yy = copy.deepcopy(curr), copy.deepcopy(angl)
|
309
309
|
lq = lq_interpol(xx, yy, lq)
|
310
|
-
except:
|
310
|
+
except:
|
311
311
|
ld = np.zeros_like(psid).tolist()
|
312
312
|
lq = np.zeros_like(psid).tolist()
|
313
|
-
|
313
|
+
|
314
314
|
torque = np.reshape([r['torque'] for r in postp],
|
315
315
|
(-1, num_beta_steps)).T
|
316
316
|
losses = {k: np.flip(np.reshape([r['plfe'][k] for r in postp],
|
@@ -547,6 +547,7 @@ def wdg_resistance(wdg, n, g, aw, outer_diam, inner_diam,
|
|
547
547
|
def _get_copper_losses(scale_factor, bch):
|
548
548
|
"""return copper losses from bch files"""
|
549
549
|
try:
|
550
|
+
wdgk = 'winding'
|
550
551
|
cu_losses = sum([b['losses'][0][wdgk] for b in bch])
|
551
552
|
return scale_factor*cu_losses
|
552
553
|
except KeyError:
|
femagtools/machine/pm.py
CHANGED
@@ -638,10 +638,10 @@ class PmRelMachine(object):
|
|
638
638
|
'rotor_hyst': hf[1],
|
639
639
|
'rotor_eddy': ef[1]}
|
640
640
|
# 'magnet'):
|
641
|
-
if '
|
642
|
-
self.plexp.update({'
|
643
|
-
'
|
644
|
-
'
|
641
|
+
if 'styoke_excess' in pfe:
|
642
|
+
self.plexp.update({'styoke_excess': cf[0],
|
643
|
+
'stteeth_excess':cf[0],
|
644
|
+
'rotor_excess': cf[1]})
|
645
645
|
|
646
646
|
def betai1_plcu(self, i1, w1=0):
|
647
647
|
return self.m*self.rstat(w1)*i1**2
|
@@ -1143,15 +1143,16 @@ class PmRelMachineLdq(PmRelMachine):
|
|
1143
1143
|
kx = len(beta)-1
|
1144
1144
|
try:
|
1145
1145
|
pfe = kwargs['losses']
|
1146
|
-
if '
|
1146
|
+
if 'styoke_excess' in pfe and np.any(pfe['styoke_excess']):
|
1147
1147
|
self.bertotti = True
|
1148
|
-
self.losskeys += ['
|
1149
|
-
'
|
1150
|
-
'
|
1148
|
+
self.losskeys += ['styoke_excess',
|
1149
|
+
'stteeth_excess',
|
1150
|
+
'rotor_excess']
|
1151
1151
|
self._set_losspar(pfe)
|
1152
1152
|
self._losses = {k: ip.RectBivariateSpline(
|
1153
1153
|
beta, i1, np.array(pfe[k]),
|
1154
|
-
kx=kx, ky=ky).ev for k in
|
1154
|
+
kx=kx, ky=ky).ev for k in self.losskeys
|
1155
|
+
if k in pfe}
|
1155
1156
|
except KeyError as e:
|
1156
1157
|
logger.warning("loss map missing: %s", e)
|
1157
1158
|
pass
|
@@ -1238,12 +1239,12 @@ class PmRelMachineLdq(PmRelMachine):
|
|
1238
1239
|
|
1239
1240
|
def betai1_plfe1(self, beta, i1, f1):
|
1240
1241
|
stator_losskeys = ['styoke_eddy', 'styoke_hyst',
|
1241
|
-
|
1242
|
+
'stteeth_eddy', 'stteeth_hyst']
|
1242
1243
|
if self.bertotti:
|
1243
|
-
stator_losskeys += ['
|
1244
|
+
stator_losskeys += ['styoke_excess', 'stteeth_excess']
|
1244
1245
|
return np.sum([
|
1245
|
-
self._losses[k](beta, i1)*(f1/self.fo)**self.plexp[k]
|
1246
|
-
k in
|
1246
|
+
self._losses[k](beta, i1)*(f1/self.fo)**self.plexp[k]
|
1247
|
+
for k in stator_losskeys if k in self._losses], axis=0)
|
1247
1248
|
|
1248
1249
|
def iqd_plfe1(self, iq, id, f1):
|
1249
1250
|
return self.betai1_plfe1(*betai1(iq, id), f1)
|
@@ -1251,7 +1252,7 @@ class PmRelMachineLdq(PmRelMachine):
|
|
1251
1252
|
def betai1_plfe2(self, beta, i1, f1):
|
1252
1253
|
rotor_losskeys = ['rotor_eddy', 'rotor_hyst']
|
1253
1254
|
if self.bertotti:
|
1254
|
-
rotor_losskeys += ['
|
1255
|
+
rotor_losskeys += ['rotor_excess']
|
1255
1256
|
return np.sum([
|
1256
1257
|
self._losses[k](beta, i1)*(f1/self.fo)**self.plexp[k] for
|
1257
1258
|
k in tuple(rotor_losskeys)], axis=0)
|
@@ -1295,7 +1296,7 @@ class PmRelMachinePsidq(PmRelMachine):
|
|
1295
1296
|
self.iqrange = (min(iq), max(iq))
|
1296
1297
|
self.betarange = (-np.pi if min(iq) < 0 else -np.pi/2,
|
1297
1298
|
0 if max(iq) > 0 else -np.pi/2)
|
1298
|
-
self.i1range = (0,
|
1299
|
+
self.i1range = (0, betai1(np.max(iq), 0)[1])
|
1299
1300
|
self.io = np.max(iq)/2, np.min(id)/2
|
1300
1301
|
|
1301
1302
|
if np.any(psid.shape < (4, 4)):
|
@@ -1322,11 +1323,11 @@ class PmRelMachinePsidq(PmRelMachine):
|
|
1322
1323
|
self._psiq = ip.RectBivariateSpline(iq, id, psiq).ev
|
1323
1324
|
try:
|
1324
1325
|
pfe = kwargs['losses']
|
1325
|
-
if '
|
1326
|
+
if 'styoke_excess' in pfe and np.any(pfe['styoke_excess']):
|
1326
1327
|
self.bertotti = True
|
1327
|
-
self.losskeys += ['
|
1328
|
-
'
|
1329
|
-
'
|
1328
|
+
self.losskeys += ['styoke_excess',
|
1329
|
+
'stteeth_excess',
|
1330
|
+
'rotor_excess']
|
1330
1331
|
self._set_losspar(pfe)
|
1331
1332
|
self._losses = {k: ip.RectBivariateSpline(
|
1332
1333
|
iq, id, np.array(pfe[k])).ev for k in (
|
@@ -1385,7 +1386,7 @@ class PmRelMachinePsidq(PmRelMachine):
|
|
1385
1386
|
stator_losskeys = ['styoke_eddy', 'styoke_hyst',
|
1386
1387
|
'stteeth_eddy', 'stteeth_hyst']
|
1387
1388
|
if self.bertotti:
|
1388
|
-
stator_losskeys += ['
|
1389
|
+
stator_losskeys += ['styoke_excess', 'stteeth_excess']
|
1389
1390
|
return np.sum([
|
1390
1391
|
self._losses[k](iq, id)*(f1/self.fo)**self.plexp[k] for
|
1391
1392
|
k in tuple(stator_losskeys)], axis=0)
|
@@ -1396,7 +1397,7 @@ class PmRelMachinePsidq(PmRelMachine):
|
|
1396
1397
|
def iqd_plfe2(self, iq, id, f1):
|
1397
1398
|
rotor_losskeys = ['rotor_eddy', 'rotor_hyst']
|
1398
1399
|
if self.bertotti:
|
1399
|
-
rotor_losskeys += ['
|
1400
|
+
rotor_losskeys += ['rotor_excess']
|
1400
1401
|
return np.sum([
|
1401
1402
|
self._losses[k](iq, id)*(f1/self.fo)**self.plexp[k] for
|
1402
1403
|
k in tuple(rotor_losskeys)], axis=0)
|
femagtools/machine/sm.py
CHANGED
@@ -546,7 +546,7 @@ class SynchronousMachine(object):
|
|
546
546
|
w10)[0]
|
547
547
|
|
548
548
|
def characteristics(self, T, n, u1max, nsamples=50,
|
549
|
-
with_tmech=True, with_torque_corr=False):
|
549
|
+
with_tmech=True, with_torque_corr=False, **kwargs):
|
550
550
|
"""calculate torque speed characteristics.
|
551
551
|
return dict with list values of
|
552
552
|
n, T, u1, i1, beta, cosphi, pmech, n_type
|
femagtools/machine/utils.py
CHANGED
@@ -303,11 +303,12 @@ def dqpar_interpol(xfit, dqpars, ipkey='temperature'):
|
|
303
303
|
else:
|
304
304
|
fpip[k] = ip.interp1d(
|
305
305
|
x, m, fill_value='extrapolate')(xfit).T
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
306
|
+
|
307
|
+
for k in ('styoke_hyst', 'stteeth_hyst',
|
308
|
+
'styoke_eddy', 'stteeth_eddy',
|
309
|
+
'rotor_hyst', 'rotor_eddy',
|
310
|
+
'magnet'):
|
311
|
+
try:
|
311
312
|
m = np.array([f['losses'][k] for f in sorted_dqpars]).T
|
312
313
|
if len(x) > 2:
|
313
314
|
fpip['losses'][k] = np.array(
|
@@ -316,12 +317,13 @@ def dqpar_interpol(xfit, dqpars, ipkey='temperature'):
|
|
316
317
|
else:
|
317
318
|
fpip['losses'][k] = ip.interp1d(
|
318
319
|
x, m, fill_value='extrapolate')(xfit).T
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
320
|
+
except KeyError:
|
321
|
+
pass
|
322
|
+
|
323
|
+
fpip['losses']['speed'] = dqpars[0]['losses']['speed']
|
324
|
+
for f in ('hf', 'ef'):
|
325
|
+
if f in dqpars[0]['losses']:
|
326
|
+
fpip['losses'][f] = dqpars[0]['losses'][f]
|
325
327
|
return x, fpip
|
326
328
|
|
327
329
|
|
@@ -351,52 +353,70 @@ def dqparident(workdir, engine, temp, machine,
|
|
351
353
|
import pathlib
|
352
354
|
|
353
355
|
wdgk = 'windings' if 'windings' in machine else 'winding'
|
354
|
-
|
355
|
-
|
356
|
+
def create_wdg(machine):
|
357
|
+
wpar = {'Q': machine['stator']['num_slots'],
|
358
|
+
'm': machine[wdgk]['num_phases'],
|
359
|
+
'p': machine['poles']//2}
|
360
|
+
|
361
|
+
if 'coil_span' in machine[wdgk]:
|
362
|
+
wpar['yd'] = machine[wdgk]['coil_span']
|
363
|
+
if 'num_layers' in machine[wdgk]:
|
364
|
+
wpar['l'] = machine[wdgk]['num_layers']
|
365
|
+
|
366
|
+
return windings.Winding(wpar)
|
367
|
+
try:
|
368
|
+
defspeed = 160/machine['poles']
|
369
|
+
except KeyError:
|
370
|
+
if kwargs.get('speed', 0) == 0:
|
371
|
+
raise ValueError('rated speed missing')
|
372
|
+
defspeed = kwargs['speed']
|
373
|
+
|
356
374
|
lfe = machine['lfe']
|
357
375
|
g = machine[wdgk].get('num_par_wdgs', 1)
|
358
|
-
slotmodel = [k for k in machine['stator'] if isinstance(
|
359
|
-
machine['stator'][k], dict)][-1]
|
360
|
-
if slotmodel == 'stator1':
|
361
|
-
hs = machine['stator']['stator1']['slot_rf1'] - \
|
362
|
-
machine['stator']['stator1']['tip_rh1']
|
363
|
-
else:
|
364
|
-
dy1 = machine['outer_diam']
|
365
|
-
hs = machine['stator'][slotmodel].get(
|
366
|
-
'slot_height', 0.6*(dy1-da1)/2)
|
367
|
-
|
368
376
|
N = machine[wdgk]['num_wires']
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
377
|
+
if 'cufilfact' in machine[wdgk]:
|
378
|
+
fcu = machine[wdgk]['cufilfact']
|
379
|
+
elif 'fillfac' in machine[wdgk]:
|
380
|
+
fcu = machine[wdgk]['fillfac']
|
381
|
+
else:
|
382
|
+
fcu = 0.42
|
383
|
+
|
384
|
+
try: # calc basic dimensions if not fsl or dxf model
|
385
|
+
Q1 = machine['stator']['num_slots']
|
386
|
+
da1 = machine['bore_diam']
|
387
|
+
slotmodel = [k for k in machine['stator'] if isinstance(
|
388
|
+
machine['stator'][k], dict)][-1]
|
389
|
+
if slotmodel == 'stator1':
|
390
|
+
hs = machine['stator']['stator1']['slot_rf1'] - \
|
391
|
+
machine['stator']['stator1']['tip_rh1']
|
392
|
+
else:
|
393
|
+
dy1 = machine['outer_diam']
|
394
|
+
hs = machine['stator'][slotmodel].get(
|
395
|
+
'slot_height', 0.6*(dy1-da1)/2)
|
373
396
|
|
374
|
-
|
375
|
-
|
376
|
-
|
397
|
+
Jmax = 30e6 # max current density in A/m2
|
398
|
+
Acu = fcu*0.5*np.pi*(da1+hs)*hs
|
399
|
+
i1_max = round(Acu/Q1/N*Jmax/10)*10
|
400
|
+
except KeyError:
|
401
|
+
if kwargs.get('i1_max', 0) == 0:
|
402
|
+
raise ValueError('i1_max missing')
|
403
|
+
i1_max = kwargs['i1_max']
|
377
404
|
|
378
405
|
# winding resistance
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
aw = np.pi*machine[wdgk].get('dia_wire', 1e-3)**2/4
|
394
|
-
elif ('wire_width' in machine[wdgk]) and ('wire_height' in machine[wdgk]):
|
395
|
-
aw = machine['windings']['wire_width']*machine[wdgk]['wire_height']
|
396
|
-
else: # wire diameter from slot area
|
397
|
-
aw = 0.75 * machine[wdgk].get('cufilfact', 0.45)*\
|
398
|
-
np.pi*da1*hs/Q1/wpar['l']/N
|
399
|
-
r1 = wdg_resistance(wdg, N, g, aw, da1, hs, lfe)
|
406
|
+
try:
|
407
|
+
wdg = create_wdg(machine)
|
408
|
+
|
409
|
+
if 'wire_gauge' in machine[wdgk]:
|
410
|
+
aw = machine[wdgk]['wire_gauge']
|
411
|
+
elif 'dia_wire' in machine[wdgk]:
|
412
|
+
aw = np.pi*machine[wdgk].get('dia_wire', 1e-3)**2/4
|
413
|
+
elif ('wire_width' in machine[wdgk]) and ('wire_height' in machine[wdgk]):
|
414
|
+
aw = machine['windings']['wire_width']*machine[wdgk]['wire_height']
|
415
|
+
else: # wire diameter from slot area
|
416
|
+
aw = 0.75 * fcu * np.pi*da1*hs/Q1/wdg.l/N
|
417
|
+
r1 = wdg_resistance(wdg, N, g, aw, da1, hs, lfe)
|
418
|
+
except (NameError, KeyError):
|
419
|
+
r1 = 0 # cannot calc winding resistance
|
400
420
|
|
401
421
|
n = len(temp)
|
402
422
|
parvardef = {
|
@@ -415,6 +435,10 @@ def dqparident(workdir, engine, temp, machine,
|
|
415
435
|
leakfile = pathlib.Path(workdir) / 'end_wind_leak.dat'
|
416
436
|
leakfile.unlink(missing_ok=True)
|
417
437
|
|
438
|
+
period_frac = kwargs.get('period_frac', 6)
|
439
|
+
if machine.get('external_rotor', False):
|
440
|
+
period_frac = 1 # TODO: missing femag support
|
441
|
+
|
418
442
|
simulation = dict(
|
419
443
|
calculationMode='ld_lq_fast',
|
420
444
|
i1_max=kwargs.get('i1_max', i1_max),
|
@@ -426,12 +450,15 @@ def dqparident(workdir, engine, temp, machine,
|
|
426
450
|
num_par_wdgs=machine[wdgk].get('num_par_wdgs', 1),
|
427
451
|
num_cur_steps=kwargs.get('num_cur_steps', 5),
|
428
452
|
num_beta_steps=kwargs.get('num_beta_steps', 7),
|
429
|
-
speed=kwargs.get('speed',
|
453
|
+
speed=kwargs.get('speed', defspeed),
|
430
454
|
period_frac=period_frac)
|
431
455
|
|
432
456
|
# TODO: cleanup() # remove previously created files in workdir
|
433
457
|
# start calculation
|
434
458
|
results = parvar(parvardef, machine, simulation, engine)
|
459
|
+
if 'poles' not in machine:
|
460
|
+
machine['poles'] = 2*results['f'][0]['machine']['p']
|
461
|
+
da1 = 2*results['f'][0]['machine']['fc_radius']
|
435
462
|
#import json
|
436
463
|
#with open('results.json', 'w') as fp:
|
437
464
|
# json.dump(results, fp)
|
@@ -457,14 +484,25 @@ def dqparident(workdir, engine, temp, machine,
|
|
457
484
|
np.array(results['f'][i]['ldq'][k]))).tolist()
|
458
485
|
for k in ('psid', 'psiq', 'torque', 'ld', 'lq', 'psim')})
|
459
486
|
ldq.append(d)
|
460
|
-
|
461
|
-
|
462
|
-
|
487
|
+
# collect existing losses only
|
488
|
+
losskeymap = {'magnet': 'magnet'}
|
489
|
+
losskeys = [k for k in results['f'][0]['ldq']['losses']
|
490
|
+
if len(k.split('_')) > 1] + ['magnet']
|
491
|
+
for k in losskeys:
|
492
|
+
if k.find('_') > -1:
|
493
|
+
pref, post = k.split('_')
|
494
|
+
if pref.lower() == 'stza':
|
495
|
+
losskeymap[k] = 'stteeth_'+post
|
496
|
+
elif pref.lower() == 'stjo':
|
497
|
+
losskeymap[k] = 'styoke_'+post
|
498
|
+
else:
|
499
|
+
losskeymap[k] = k
|
463
500
|
for i in range(0, len(results['f']), 2):
|
464
501
|
j = i//2
|
465
502
|
ldq[j]['temperature'] = results['x'][0][i]
|
466
|
-
ldq[j]['losses'] = {k: np.vstack(
|
467
|
-
|
503
|
+
ldq[j]['losses'] = {losskeymap[k]: np.vstack(
|
504
|
+
(np.array(results['f'][i+1]['ldq']['losses'][k])[:-1, :],
|
505
|
+
np.array(results['f'][i]['ldq']['losses'][k]))).tolist()
|
468
506
|
for k in losskeys}
|
469
507
|
ldq[j]['losses']['speed'] = results['f'][i]['ldq']['losses']['speed']
|
470
508
|
for k in ('hf', 'ef'):
|
@@ -473,10 +511,26 @@ def dqparident(workdir, engine, temp, machine,
|
|
473
511
|
dqpars = {
|
474
512
|
'm': machine[wdgk]['num_phases'],
|
475
513
|
'p': machine['poles']//2,
|
476
|
-
'r1': machine[wdgk].get('resistance', r1),
|
477
514
|
'ls1': ls1,
|
478
515
|
"rotor_mass": rotor_mass, "kfric_b": 1,
|
479
516
|
'ldq': ldq}
|
517
|
+
if 'resistance' in machine[wdgk]:
|
518
|
+
dqpars['r1'] = machine[wdgk]['resistance']
|
519
|
+
else:
|
520
|
+
if r1:
|
521
|
+
dqpars['r1'] = r1
|
522
|
+
else:
|
523
|
+
from .. import nc
|
524
|
+
model = nc.read(str(pathlib.Path(workdir) / machine['name']))
|
525
|
+
Q1 = model.num_slots
|
526
|
+
#machine['stator']['num_slots'] = Q1
|
527
|
+
wdg = create_wdg(machine)
|
528
|
+
istat = 0 if model.get_areas()[0]['slots'] else 1
|
529
|
+
asl = model.get_areas()[istat]['slots']
|
530
|
+
# diameter of wires
|
531
|
+
aw = fcu*asl/Q1/wdg.l/N
|
532
|
+
hs = asl/(np.pi*da1/3)
|
533
|
+
dqpars['r1'] = wdg_resistance(wdg, N, g, aw, da1, hs, lfe)
|
480
534
|
|
481
535
|
if 'current_angles' in results['f'][0]:
|
482
536
|
dqpars['current_angles'] = results['f'][0]['current_angles']
|
femagtools/mcv.py
CHANGED
@@ -50,6 +50,7 @@ transl = dict(
|
|
50
50
|
rho='mc1_fe_spez_weigth',
|
51
51
|
ch='mc1_ch_factor',
|
52
52
|
cw='mc1_cw_factor',
|
53
|
+
ce='mc1_ce_factor',
|
53
54
|
ch_freq='mc1_ch_freq_factor',
|
54
55
|
cw_freq='mc1_cw_freq_factor',
|
55
56
|
fillfac='mc1_fillfac',
|
@@ -58,6 +59,7 @@ transl = dict(
|
|
58
59
|
bsat='mc1_bsat',
|
59
60
|
Bo='mc1_base_induction',
|
60
61
|
b_coeff='mc1_induction_factor',
|
62
|
+
b_beta_coeff='mc1_induction_beta_factor',
|
61
63
|
fo='mc1_base_frequency',
|
62
64
|
curve=[dict(
|
63
65
|
hi='mc1_hi',
|
@@ -227,9 +229,12 @@ class Mcv(object):
|
|
227
229
|
self.MC1_BASE_INDUCTION = 1.5
|
228
230
|
self.MC1_CH_FACTOR = 0.0
|
229
231
|
self.MC1_CW_FACTOR = 0.0
|
232
|
+
self.MC1_CE_FACTOR = 0.0
|
230
233
|
self.MC1_CH_FREQ_FACTOR = 0.0
|
231
234
|
self.MC1_CW_FREQ_FACTOR = 0.0
|
232
235
|
self.MC1_INDUCTION_FACTOR = 0.0
|
236
|
+
self.MC1_INDUCTION_BETA_FACTOR = 0.0
|
237
|
+
|
233
238
|
self.MC1_FE_SPEZ_WEIGTH = 7.65
|
234
239
|
self.MC1_FE_SAT_MAGNETIZATION = 2.15
|
235
240
|
|
@@ -237,9 +242,11 @@ class Mcv(object):
|
|
237
242
|
self.mc1_base_induction = self.MC1_BASE_INDUCTION
|
238
243
|
self.mc1_ch_factor = self.MC1_CH_FACTOR
|
239
244
|
self.mc1_cw_factor = self.MC1_CW_FACTOR
|
245
|
+
self.mc1_ce_factor = self.MC1_CE_FACTOR
|
240
246
|
self.mc1_ch_freq_factor = self.MC1_CH_FREQ_FACTOR
|
241
247
|
self.mc1_cw_freq_factor = self.MC1_CW_FREQ_FACTOR
|
242
248
|
self.mc1_induction_factor = self.MC1_INDUCTION_FACTOR
|
249
|
+
self.mc1_induction_beta_factor = self.MC1_INDUCTION_BETA_FACTOR
|
243
250
|
self.mc1_fe_spez_weigth = self.MC1_FE_SPEZ_WEIGTH
|
244
251
|
self.mc1_fe_sat_magnetization = self.MC1_FE_SAT_MAGNETIZATION
|
245
252
|
|
@@ -519,6 +526,13 @@ class Writer(Mcv):
|
|
519
526
|
float(self.mc1_fe_sat_magnetization)])
|
520
527
|
|
521
528
|
if not hasattr(self, 'losses') or not self.losses:
|
529
|
+
# new variables: ce factor for bertotti losses
|
530
|
+
# b_beta_coeff for modified steinmetz
|
531
|
+
try:
|
532
|
+
self.writeBlock([float(self.mc1_ce_factor),
|
533
|
+
float(self.mc1_induction_beta_factor)])
|
534
|
+
except:
|
535
|
+
pass
|
522
536
|
return
|
523
537
|
|
524
538
|
try:
|
@@ -585,7 +599,7 @@ class Writer(Mcv):
|
|
585
599
|
logger.info('Losses n freq %d n ind %d', nfreq, nind)
|
586
600
|
except Exception as e:
|
587
601
|
logger.error("Exception %s", e, exc_info=True)
|
588
|
-
|
602
|
+
|
589
603
|
def writeMcv(self, filename, fillfac=None, recsin=''):
|
590
604
|
# windows needs this strip to remove '\r'
|
591
605
|
filename = filename.strip()
|
@@ -857,6 +871,16 @@ class Reader(Mcv):
|
|
857
871
|
if not self.losses['f'] or not self.losses['pfe']:
|
858
872
|
self.losses = {}
|
859
873
|
|
874
|
+
self.ce = 0
|
875
|
+
self.b_beta_coeff = 0
|
876
|
+
try:
|
877
|
+
if not self.losses['f'][0]:
|
878
|
+
self.fp.seek(-16, 1)
|
879
|
+
res = self.readBlock([float]*2)
|
880
|
+
self.ce, self.b_beta_coeff = res[0], res[1]
|
881
|
+
except:
|
882
|
+
pass
|
883
|
+
|
860
884
|
def get_results(self):
|
861
885
|
result = {
|
862
886
|
'name': self.name,
|
@@ -873,6 +897,8 @@ class Reader(Mcv):
|
|
873
897
|
'ch': self.ch,
|
874
898
|
'ch_freq': self.ch_freq,
|
875
899
|
'cw': self.cw,
|
900
|
+
'ce': self.ce,
|
901
|
+
'b_beta_coeff': self.b_beta_coeff,
|
876
902
|
'cw_freq': self.cw_freq,
|
877
903
|
'b_coeff': self.b_coeff,
|
878
904
|
'rho': self.rho,
|
femagtools/model.py
CHANGED
@@ -379,6 +379,7 @@ class MachineModel(Model):
|
|
379
379
|
def rotortype(self):
|
380
380
|
"""return type of rotor slot"""
|
381
381
|
for k in self.rotor:
|
382
|
+
# anything that is a dict must represent the type
|
382
383
|
if isinstance(self.rotor[k], dict):
|
383
384
|
return k
|
384
385
|
raise AttributeError("Missing rotor model in {}".format(self.magnet))
|
@@ -386,8 +387,9 @@ class MachineModel(Model):
|
|
386
387
|
def magnettype(self):
|
387
388
|
"""return type of magnet slot"""
|
388
389
|
for k in self.magnet:
|
389
|
-
if k
|
390
|
-
|
390
|
+
if k not in {'material', 'temp_prop'}:
|
391
|
+
if isinstance(self.magnet[k], dict):
|
392
|
+
return k
|
391
393
|
raise AttributeError("Missing magnet model in {}".format(self.magnet))
|
392
394
|
|
393
395
|
def is_complete(self):
|
femagtools/nc.py
CHANGED
@@ -262,6 +262,7 @@ class Reader(object):
|
|
262
262
|
ce_ind_exp = 1.5
|
263
263
|
ke = 0.0
|
264
264
|
khml = 0.65
|
265
|
+
cw_ind_beta_exp = 0
|
265
266
|
|
266
267
|
lctype = ['magn_curve']*lmc + ['Outside', 'Inside']
|
267
268
|
for i in range(lmc+2):
|
@@ -280,6 +281,11 @@ class Reader(object):
|
|
280
281
|
cw = float(mcgrp.variables['cw'][i].data)
|
281
282
|
cw_freq_exp = float(mcgrp.variables['cw_exp'][i].data)
|
282
283
|
cw_ind_exp = float(mcgrp.variables['ind_exp'][i].data)
|
284
|
+
try:
|
285
|
+
ce = float(mcgrp.variables['ce'][i].data)
|
286
|
+
cw_ind_beta_exp = float(mcgrp.variables['ind_beta_exp'][i].data)
|
287
|
+
except:
|
288
|
+
pass
|
283
289
|
spec_weight = float(mcgrp.variables['spec_weight'][i].data)
|
284
290
|
fillfactor = float(mcgrp.variables['fillfac'][i].data)
|
285
291
|
shapefactor = 1.0
|
@@ -327,6 +333,7 @@ class Reader(object):
|
|
327
333
|
"cw_freq_exp": cw_freq_exp,
|
328
334
|
"cw_ind_exp": cw_ind_exp,
|
329
335
|
"ce": ce,
|
336
|
+
"cw_ind_beta_exp": cw_ind_beta_exp,
|
330
337
|
"ce_freq_exp": ce_freq_exp,
|
331
338
|
"ce_ind_exp": ce_ind_exp,
|
332
339
|
"ke": ke,
|
femagtools/opt.py
CHANGED
@@ -82,7 +82,7 @@ class Optimizer(object):
|
|
82
82
|
task.add_file(self.fea['pocfilename'],
|
83
83
|
self.fea['poc'].content())
|
84
84
|
if 'stateofproblem' in self.fea:
|
85
|
-
task.set_stateofproblem(fea['stateofproblem'])
|
85
|
+
task.set_stateofproblem(self.fea['stateofproblem'])
|
86
86
|
tstart = time.time()
|
87
87
|
ntasks = engine.submit()
|
88
88
|
status = engine.join()
|
femagtools/parstudy.py
CHANGED
@@ -181,10 +181,13 @@ class ParameterStudy(object):
|
|
181
181
|
simulation['lfe'] = model.lfe
|
182
182
|
simulation['move_action'] = model.move_action
|
183
183
|
simulation['phi_start'] = 0.0
|
184
|
-
|
184
|
+
try:
|
185
|
+
simulation['range_phi'] = 720/model.get('poles')
|
186
|
+
except AttributeError: # if dxf or pure fsl model
|
187
|
+
simulation['range_phi'] = 0.0
|
185
188
|
simulation.update(model.winding)
|
186
189
|
if 'pocfilename' not in simulation:
|
187
|
-
simulation['pocfilename'] = f"{model.name}
|
190
|
+
simulation['pocfilename'] = f"{model.name}.poc"
|
188
191
|
fea = femagtools.model.FeaModel(simulation)
|
189
192
|
|
190
193
|
prob = femagtools.moproblem.FemagMoProblem(decision_vars,
|