femagtools 1.7.6__py3-none-any.whl → 1.7.7__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 +11 -1
- femagtools/dxfsl/converter.py +14 -5
- femagtools/dxfsl/fslrenderer.py +93 -45
- femagtools/dxfsl/functions.py +8 -0
- femagtools/dxfsl/geom.py +37 -1
- femagtools/dxfsl/machine.py +4 -0
- femagtools/femag.py +3 -3
- femagtools/fsl.py +73 -51
- femagtools/isa7.py +2 -2
- femagtools/machine/effloss.py +2 -0
- femagtools/machine/pm.py +10 -1
- femagtools/machine/sm.py +294 -253
- femagtools/machine/utils.py +3 -12
- femagtools/model.py +32 -2
- femagtools/moo/algorithm.py +6 -0
- femagtools/nc.py +2 -0
- femagtools/opt.py +2 -1
- femagtools/plot/char.py +4 -4
- femagtools/plot/nc.py +21 -4
- femagtools/plot/wdg.py +38 -26
- femagtools/templates/gen_hairpin_winding.mako +209 -0
- femagtools/templates/gen_winding.mako +8 -9
- femagtools/templates/magnetIron.mako +32 -6
- femagtools/templates/rotor_winding.mako +10 -6
- femagtools/templates/statorRotor3.mako +6 -6
- femagtools/windings.py +31 -18
- {femagtools-1.7.6.dist-info → femagtools-1.7.7.dist-info}/METADATA +1 -1
- {femagtools-1.7.6.dist-info → femagtools-1.7.7.dist-info}/RECORD +34 -33
- {femagtools-1.7.6.dist-info → femagtools-1.7.7.dist-info}/WHEEL +1 -1
- tests/test_windings.py +1 -1
- {femagtools-1.7.6.dist-info → femagtools-1.7.7.dist-info}/LICENSE +0 -0
- {femagtools-1.7.6.dist-info → femagtools-1.7.7.dist-info}/entry_points.txt +0 -0
- {femagtools-1.7.6.dist-info → femagtools-1.7.7.dist-info}/top_level.txt +0 -0
femagtools/fsl.py
CHANGED
@@ -42,7 +42,7 @@ class Builder:
|
|
42
42
|
default_filters=['decode.utf8'])
|
43
43
|
|
44
44
|
self.fsl_stator = False
|
45
|
-
self.
|
45
|
+
self.fsl_rotor = False
|
46
46
|
|
47
47
|
def create_wdg_def(self, model):
|
48
48
|
name = 'winding'
|
@@ -216,7 +216,7 @@ class Builder:
|
|
216
216
|
.format(model.magnet.get('mcvkey_shaft', 'dummy'))]
|
217
217
|
|
218
218
|
if 'magnetFsl' in model.magnet:
|
219
|
-
self.
|
219
|
+
self.fsl_rotor = True
|
220
220
|
# obsolete
|
221
221
|
if 'parameter' in model.magnet['magnetFsl']:
|
222
222
|
return mcv + self.render_template(
|
@@ -242,10 +242,10 @@ class Builder:
|
|
242
242
|
magmodel['mcvkey_magnet'] = model.get_mcvkey_magnet()
|
243
243
|
if templ == 'dxf':
|
244
244
|
return mcv + [
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
245
|
+
'xmag = {}',
|
246
|
+
'ymag = {}',
|
247
|
+
'mag_orient = {}',
|
248
|
+
'ndt(agndst)'] + model.magnet['dxf']['fsl']
|
249
249
|
|
250
250
|
return mcv + self.render_rotor(magmodel, templ)
|
251
251
|
|
@@ -267,12 +267,16 @@ class Builder:
|
|
267
267
|
rotmodel['winding_inside'] = not model.external_rotor
|
268
268
|
culosses = self.create_cu_losses(rotmodel, condMat)
|
269
269
|
|
270
|
-
rotmodel.update(model.rotor[templ])
|
271
270
|
rotmodel['is_rotor'] = True # just in case for the template
|
271
|
+
if templ == 'EESM':
|
272
|
+
if 'dxf' in rotmodel:
|
273
|
+
return mcv + ['ndt(agndst)'] + rotmodel['dxf']['fsl']
|
274
|
+
templ = 'rot_hsm'
|
275
|
+
rotmodel.update(model.rotor[templ])
|
272
276
|
return mcv + culosses + self.render_rotor(rotmodel, templ)
|
273
277
|
|
274
278
|
def create_rotor_winding(self, model):
|
275
|
-
if hasattr(model, 'rotor') and model.rotortype() == '
|
279
|
+
if hasattr(model, 'rotor') and model.rotortype() == 'EESM':
|
276
280
|
return self.render_rotor(model.rotor, 'rotor_winding')
|
277
281
|
return []
|
278
282
|
|
@@ -306,21 +310,22 @@ class Builder:
|
|
306
310
|
|
307
311
|
if templ == 'dxf':
|
308
312
|
# reuse dxfsl model
|
309
|
-
self.
|
313
|
+
self.fsl_rotor = True
|
310
314
|
if templ != 'dxffile':
|
311
315
|
return
|
312
316
|
|
313
317
|
from femagtools.dxfsl.converter import convert
|
314
318
|
params = {}
|
315
|
-
|
316
|
-
params['
|
319
|
+
rotor = model.magnet
|
320
|
+
params['split'] = rotor[templ].get('split', False)
|
321
|
+
params['show_plots'] = rotor[templ].get('plot', False)
|
317
322
|
params['write_fsl'] = True
|
318
323
|
params['airgap'] = -1.0
|
319
324
|
pos = 'out' if model.external_rotor else 'in'
|
320
325
|
params['part'] = ('rotor', pos)
|
321
326
|
logger.info("Conv rotor from %s",
|
322
|
-
|
323
|
-
conv = convert(
|
327
|
+
rotor[templ]['name'])
|
328
|
+
conv = convert(rotor[templ]['name'], **params)
|
324
329
|
model.set_value('poles', int(conv.get('num_poles')))
|
325
330
|
self.set_diameter_parameter(model, conv)
|
326
331
|
if model.get('da2'):
|
@@ -328,9 +333,9 @@ class Builder:
|
|
328
333
|
ag = (model.get('bore_diam') - model.get('da2')/1e3)/2
|
329
334
|
model.set_value('airgap', ag)
|
330
335
|
|
331
|
-
|
332
|
-
self.
|
333
|
-
del
|
336
|
+
rotor['dxf'] = dict(fsl=conv['fsl'])
|
337
|
+
self.fsl_rotor = True
|
338
|
+
del rotor[templ]
|
334
339
|
|
335
340
|
def render_rotor(self, magmodel, templ):
|
336
341
|
fslcode = self.__render(magmodel, templ, magnet=True)
|
@@ -351,23 +356,25 @@ class Builder:
|
|
351
356
|
if 'thcond' in model.stator:
|
352
357
|
fslcmds += [
|
353
358
|
'-- thermal properties in airgap',
|
354
|
-
'
|
355
|
-
'
|
356
|
-
'
|
357
|
-
'
|
358
|
-
'
|
359
|
-
'xai,
|
360
|
-
'
|
361
|
-
'xai,
|
362
|
-
'
|
359
|
+
'if m.zeroangl ~= nil then',
|
360
|
+
' ag_cond = 0.063',
|
361
|
+
' thcap = 1007',
|
362
|
+
' beta = math.pi*m.npols_gen/m.num_poles + m.zeroangl/180*math.pi',
|
363
|
+
' xai, yai = pr2c((da1+da2)/4, beta)',
|
364
|
+
' def_mat_therm(xai,yai,"cyan",1.19,ag_cond,thcap,1)',
|
365
|
+
' xai, yai = pr2c((da1+da2)/4-ag/4, beta)',
|
366
|
+
' def_mat_therm(xai,yai,"cyan",1.19,ag_cond,thcap,1)',
|
367
|
+
' xai, yai = pr2c((da1+da2)/4+ag/4, beta)',
|
368
|
+
' def_mat_therm(xai,yai,"cyan",1.19,ag_cond,thcap,1)',
|
363
369
|
'',
|
364
|
-
'state_of_problem("therm_static") -- thermic boundary conditions',
|
365
|
-
'x1,y1 = pd2c(dy2/2,m.zeroangl)',
|
366
|
-
'x2,y2 = pd2c(dy1/2,m.zeroangl)',
|
367
|
-
'beta = 360*m.npols_gen/m.num_poles',
|
368
|
-
'x3,y3 = pd2c(dy1/2,beta+m.zeroangl)',
|
369
|
-
'x4,y4 = pd2c(dy2/2,beta+m.zeroangl)',
|
370
|
-
'def_bcond_tp(x1,y1,x2,y2,x3,y3,x4,y4, 4)',
|
370
|
+
' state_of_problem("therm_static") -- thermic boundary conditions',
|
371
|
+
' x1,y1 = pd2c(dy2/2,m.zeroangl)',
|
372
|
+
' x2,y2 = pd2c(dy1/2,m.zeroangl)',
|
373
|
+
' beta = 360*m.npols_gen/m.num_poles',
|
374
|
+
' x3,y3 = pd2c(dy1/2,beta+m.zeroangl)',
|
375
|
+
' x4,y4 = pd2c(dy2/2,beta+m.zeroangl)',
|
376
|
+
' def_bcond_tp(x1,y1,x2,y2,x3,y3,x4,y4, 4)',
|
377
|
+
'end',
|
371
378
|
'state_of_problem("mag_static")']
|
372
379
|
return fslcmds
|
373
380
|
return []
|
@@ -409,10 +416,10 @@ class Builder:
|
|
409
416
|
cond = condMat.find(windings['material'])
|
410
417
|
if not cond:
|
411
418
|
raise FslBuilderError(
|
412
|
-
'conductor material {} not found'.format(
|
413
|
-
windings['material']))
|
419
|
+
'conductor material {} not found in {}'.format(
|
420
|
+
windings['material'], condMat))
|
414
421
|
windings['cuconduct'] = cond['elconduct']
|
415
|
-
for k in ('thcond', 'thcap'):
|
422
|
+
for k in ('thcond', 'thcap', 'spmaweight'):
|
416
423
|
if k in cond:
|
417
424
|
windings[k] = cond[k]
|
418
425
|
|
@@ -433,7 +440,14 @@ class Builder:
|
|
433
440
|
return []
|
434
441
|
|
435
442
|
def create_gen_winding(self, model):
|
436
|
-
|
443
|
+
try:
|
444
|
+
if model.winding['wire']['name'] == 'hairpin_winding':
|
445
|
+
model.winding['wire'].update(
|
446
|
+
{"num_layers": model.winding["num_layers"]})
|
447
|
+
genwdg = self.__render(model.winding,
|
448
|
+
'gen_' + model.winding['wire'].get('name'))
|
449
|
+
except KeyError: # not hairpin_winding
|
450
|
+
genwdg = self.__render(model, 'gen_winding')
|
437
451
|
k = list({'leak_dist_wind',
|
438
452
|
'leak_evol_wind',
|
439
453
|
'leak_tooth_wind'}.intersection(model.winding))
|
@@ -480,6 +494,9 @@ class Builder:
|
|
480
494
|
params['airgap'] = model.dxffile.get('airgap', 0.0)
|
481
495
|
params['nodedist'] = model.dxffile.get('nodedist', 1)
|
482
496
|
params['full_model'] = model.dxffile.get('full_model', False)
|
497
|
+
params['EESM'] = model.dxffile.get('type', 'PMSM') == 'EESM'
|
498
|
+
if params['EESM']:
|
499
|
+
model.rotor['EESM'] = {}
|
483
500
|
conv = convert(dxfname, **params)
|
484
501
|
|
485
502
|
model.set_value('poles', conv.get('num_poles'))
|
@@ -492,6 +509,7 @@ class Builder:
|
|
492
509
|
if not hasattr(model, 'stator'):
|
493
510
|
setattr(model, 'stator', {})
|
494
511
|
model.stator['num_slots'] = conv.get('tot_num_slot')
|
512
|
+
model.stator['slot_area'] = conv.get('slot_area')
|
495
513
|
if model.get('num_agnodes', 0) == 0:
|
496
514
|
model.set_value('agndst', conv['agndst']*1e-3)
|
497
515
|
logger.info("num poles %d num slots %d outer diameter %.4f m agndst %.4f mm",
|
@@ -509,11 +527,17 @@ class Builder:
|
|
509
527
|
if 'fsl_stator' in conv:
|
510
528
|
self.fsl_stator = True
|
511
529
|
model.stator['dxf'] = dict(fsl=conv['fsl_stator'])
|
512
|
-
if not hasattr(model, 'magnet'):
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
530
|
+
if not (hasattr(model, 'magnet') or hasattr(model, 'rotor')):
|
531
|
+
if params['EESM']:
|
532
|
+
setattr(model, 'rotor', {})
|
533
|
+
else:
|
534
|
+
setattr(model, 'magnet', {})
|
535
|
+
if 'fsl_rotor' in conv:
|
536
|
+
self.fsl_rotor = True
|
537
|
+
if hasattr(model, 'magnet'):
|
538
|
+
model.magnet['dxf'] = dict(fsl=conv['fsl_rotor'])
|
539
|
+
if hasattr(model, 'rotor'):
|
540
|
+
model.rotor['dxf'] = dict(fsl=conv['fsl_rotor'])
|
517
541
|
|
518
542
|
def create_model(self, model, magnets=[], condMat=[], ignore_material=False):
|
519
543
|
magnetMat = {}
|
@@ -563,10 +587,9 @@ class Builder:
|
|
563
587
|
'remanenc', 1.2)
|
564
588
|
model['magnet']['relperm'] = magnetMat.get('relperm', 1.05)
|
565
589
|
model['magnet']['rlen'] = magnetMat.get('rlen', 1.0)
|
566
|
-
for k in ('thcond', 'thcap'):
|
590
|
+
for k in ('spmaweight', 'thcond', 'thcap'):
|
567
591
|
if k in magnetMat:
|
568
|
-
model['magnet'][k] = magnetMat[k]
|
569
|
-
|
592
|
+
model['magnet'][k+'_magnet'] = magnetMat[k]
|
570
593
|
rotor = (self.create_magnet(model) +
|
571
594
|
self.create_magnet_model(model))
|
572
595
|
if magnetMat:
|
@@ -714,11 +737,10 @@ class Builder:
|
|
714
737
|
return self.__render(model, 'colorgrad')
|
715
738
|
|
716
739
|
def mesh_airgap(self, model):
|
717
|
-
if ((self.fsl_stator and self.
|
740
|
+
if ((self.fsl_stator and self.fsl_rotor) or
|
718
741
|
model.get('num_agnodes', 0)):
|
719
742
|
return self.__render(model, 'mesh-airgap')
|
720
|
-
|
721
|
-
return []
|
743
|
+
return []
|
722
744
|
|
723
745
|
def create(self, model, sim, magnets=None, condMat=[]):
|
724
746
|
"create model and analysis function"
|
@@ -768,10 +790,10 @@ class Builder:
|
|
768
790
|
|
769
791
|
return (fslmodel + self.create_analysis(sim) +
|
770
792
|
['save_model("close")'])
|
771
|
-
|
772
|
-
def create_detailed_wire(self, params, templ):
|
793
|
+
|
794
|
+
def create_detailed_wire(self, params, templ):
|
773
795
|
return self.__render(params, templ)
|
774
|
-
|
796
|
+
|
775
797
|
def __render(self, model, templ, stator=False, magnet=False):
|
776
798
|
if templ.split('.')[-1] in ('fsl', 'mako'):
|
777
799
|
try:
|
@@ -791,7 +813,7 @@ class Builder:
|
|
791
813
|
if stator:
|
792
814
|
self.fsl_stator = True
|
793
815
|
if magnet:
|
794
|
-
self.
|
816
|
+
self.fsl_rotor = True
|
795
817
|
|
796
818
|
return template.render_unicode(model=model).split('\n')
|
797
819
|
|
femagtools/isa7.py
CHANGED
@@ -528,7 +528,7 @@ class Isa7(object):
|
|
528
528
|
|
529
529
|
color = {1: [1.0, 0.0, 0.0], # RED
|
530
530
|
2: [0.0, 1.0, 0.0], # GREEN
|
531
|
-
3: [1.0,
|
531
|
+
3: [1.0, 0.8, 0.0], # DARKYELLOW
|
532
532
|
4: [0.0, 0.5019607843137255, 1.0], # BLUE
|
533
533
|
5: [0.9803921568627451, 0.0, 1.0], # MAGENTA
|
534
534
|
6: [0.0, 1.0, 0.8235294117647058], # CYAN
|
@@ -749,7 +749,7 @@ class Isa7(object):
|
|
749
749
|
for e in self.elements])
|
750
750
|
|
751
751
|
for a in ('FC_RADIUS', 'pole_pairs', 'poles_sim',
|
752
|
-
'delta_node_angle', 'speed',
|
752
|
+
'layers', 'coil_span', 'delta_node_angle', 'speed',
|
753
753
|
'MAGN_TEMPERATURE', 'BR_TEMP_COEF',
|
754
754
|
'MA_SPEZ_WEIGHT', 'CU_SPEZ_WEIGHT'):
|
755
755
|
v = getattr(reader, a, '')
|
femagtools/machine/effloss.py
CHANGED
@@ -323,6 +323,8 @@ def efficiency_losses_map(eecpars, u1, T, temp, n, npoints=(60, 40),
|
|
323
323
|
plcu1 = m.iqd_plcu1(iqd[0], iqd[1], 2*np.pi*f1)
|
324
324
|
plcu2 = m.iqd_plcu2(*iqd)
|
325
325
|
tfric = m.tfric
|
326
|
+
logger.info("Iex %f %f",
|
327
|
+
np.min(iqd[2]), np.max(iqd[2]))
|
326
328
|
else:
|
327
329
|
plfe1 = np.array(r['plfe1'])
|
328
330
|
plfe2 = np.zeros(ntmesh.shape[1])
|
femagtools/machine/pm.py
CHANGED
@@ -141,6 +141,14 @@ class PmRelMachine(object):
|
|
141
141
|
def rstat(self, w):
|
142
142
|
"""stator resistance
|
143
143
|
"""
|
144
|
+
if isinstance(self.zeta1, list):
|
145
|
+
logger.info("setup ac loss parameters...")
|
146
|
+
# polyfit from ac loss calculation
|
147
|
+
freq = w/2/np.pi
|
148
|
+
kr = self.zeta1[0]*freq**3 + self.zeta1[1]*freq**2 + \
|
149
|
+
self.zeta1[2]*freq + self.zeta1[3]
|
150
|
+
kr[kr<1] = 1.
|
151
|
+
return self.r1*(1 - self.kth1*(self.tcu1 - 20))*kr # ref 20°C
|
144
152
|
if self.skin_resistance is not None:
|
145
153
|
return self.skin_resistance(self.r1, w, self.tcu1, kth=self.kth1)
|
146
154
|
|
@@ -947,7 +955,7 @@ class PmRelMachine(object):
|
|
947
955
|
i1max: max. phase current (RMS)
|
948
956
|
"""
|
949
957
|
r = dict(id=[], iq=[], uq=[], ud=[], u1=[], i1=[], T=[],
|
950
|
-
beta=[], gamma=[], phi=[], cosphi=[], pmech=[], n=[])
|
958
|
+
beta=[], gamma=[], phi=[], cosphi=[], pmech=[], n=[], type_op=[])
|
951
959
|
|
952
960
|
if kwargs.get('i1max', 0):
|
953
961
|
w1type, T = self.w1_imax_umax(kwargs['i1max'], u1max)
|
@@ -1032,6 +1040,7 @@ class PmRelMachine(object):
|
|
1032
1040
|
r['n'].append(nx)
|
1033
1041
|
r['T'].append(Tf)
|
1034
1042
|
|
1043
|
+
r['type_op'] = list(betai1(iq, id))
|
1035
1044
|
Pmax = 2*np.pi*n1*Tf
|
1036
1045
|
for ns, nu, iv in zip(nstab[1:], speedrange[2:], interv):
|
1037
1046
|
# find id, iq, torque in fieldweakening range
|